Port Encoder and Potentiometer to Pimoroni I2C

Wraps just enough of Pimoroni I2C to make it work in MicroPython.

Ports Encoder and Potentiometer to use a PimorniI2C() instance in lieu of sda/scl.
pull/129/head
Phil Howard 2021-05-17 18:09:39 +01:00
rodzic 7fa9e5bdca
commit b2056040e8
6 zmienionych plików z 166 dodań i 45 usunięć

Wyświetl plik

@ -12,6 +12,13 @@ using namespace pimoroni;
extern "C" {
#include "breakout_encoder.h"
#include "pimoroni_i2c.h"
/***** I2C Struct *****/
typedef struct _PimoroniI2C_obj_t {
mp_obj_base_t base;
I2C *i2c;
} _PimoroniI2C_obj_t;
/***** Variables Struct *****/
typedef struct _breakout_encoder_BreakoutEncoder_obj_t {
@ -50,12 +57,10 @@ void BreakoutEncoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
mp_obj_t BreakoutEncoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
breakout_encoder_BreakoutEncoder_obj_t *self = nullptr;
enum { ARG_i2c, ARG_address, ARG_sda, ARG_scl, ARG_interrupt };
enum { ARG_i2c, ARG_address, ARG_interrupt };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_i2c, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_i2c, MP_ARG_OBJ, {.u_obj = nullptr} },
{ MP_QSTR_address, MP_ARG_INT, {.u_int = BreakoutEncoder::DEFAULT_I2C_ADDRESS} },
{ MP_QSTR_sda, MP_ARG_INT, {.u_int = I2C_DEFAULT_SDA} },
{ MP_QSTR_scl, MP_ARG_INT, {.u_int = I2C_DEFAULT_SCL} },
{ MP_QSTR_interrupt, MP_ARG_INT, {.u_int = PIN_UNUSED} },
};
@ -63,30 +68,17 @@ mp_obj_t BreakoutEncoder_make_new(const mp_obj_type_t *type, size_t n_args, size
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// Get I2C bus.
int i2c_id = args[ARG_i2c].u_int;
int sda = args[ARG_sda].u_int;
int scl = args[ARG_scl].u_int;
if(i2c_id == -1) {
i2c_id = (sda >> 1) & 0b1; // If no i2c specified, choose the one for the given SDA pin
}
if(i2c_id < 0 || i2c_id > 1) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id);
if(!MP_OBJ_IS_TYPE(args[ARG_i2c].u_obj, &PimoroniI2C_type)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad i2C object"));
return mp_const_none;
}
if(!IS_VALID_SDA(i2c_id, sda)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SDA pin"));
}
if(!IS_VALID_SCL(i2c_id, scl)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SCL pin"));
}
_PimoroniI2C_obj_t *i2c = (_PimoroniI2C_obj_t *)MP_OBJ_TO_PTR(args[ARG_i2c].u_obj);
self = m_new_obj(breakout_encoder_BreakoutEncoder_obj_t);
self->base.type = &breakout_encoder_BreakoutEncoder_type;
self->breakout = new BreakoutEncoder(args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int);
self->breakout = new BreakoutEncoder(i2c->i2c, args[ARG_address].u_int, args[ARG_interrupt].u_int);
if(!self->breakout->init()) {
mp_raise_msg(&mp_type_RuntimeError, "Encoder breakout not found when initialising");

Wyświetl plik

@ -12,6 +12,13 @@ using namespace pimoroni;
extern "C" {
#include "breakout_potentiometer.h"
#include "pimoroni_i2c.h"
/***** I2C Struct *****/
typedef struct _PimoroniI2C_obj_t {
mp_obj_base_t base;
I2C *i2c;
} _PimoroniI2C_obj_t;
/***** Variables Struct *****/
typedef struct _breakout_potentiometer_BreakoutPotentiometer_obj_t {
@ -50,12 +57,10 @@ void BreakoutPotentiometer_print(const mp_print_t *print, mp_obj_t self_in, mp_p
mp_obj_t BreakoutPotentiometer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
breakout_potentiometer_BreakoutPotentiometer_obj_t *self = nullptr;
enum { ARG_i2c, ARG_address, ARG_sda, ARG_scl, ARG_interrupt };
enum { ARG_i2c, ARG_interrupt };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_i2c, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_i2c, MP_ARG_OBJ, {.u_obj = nullptr} },
{ MP_QSTR_address, MP_ARG_INT, {.u_int = BreakoutPotentiometer::DEFAULT_I2C_ADDRESS} },
{ MP_QSTR_sda, MP_ARG_INT, {.u_int = I2C_DEFAULT_SDA} },
{ MP_QSTR_scl, MP_ARG_INT, {.u_int = I2C_DEFAULT_SCL} },
{ MP_QSTR_interrupt, MP_ARG_INT, {.u_int = PIN_UNUSED} },
};
@ -63,30 +68,17 @@ mp_obj_t BreakoutPotentiometer_make_new(const mp_obj_type_t *type, size_t n_args
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// Get I2C bus.
int i2c_id = args[ARG_i2c].u_int;
int sda = args[ARG_sda].u_int;
int scl = args[ARG_scl].u_int;
if(i2c_id == -1) {
i2c_id = (sda >> 1) & 0b1; // If no i2c specified, choose the one for the given SDA pin
}
if(i2c_id < 0 || i2c_id > 1) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id);
if(!MP_OBJ_IS_TYPE(args[ARG_i2c].u_obj, &PimoroniI2C_type)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad i2C object"));
return mp_const_none;
}
if(!IS_VALID_SDA(i2c_id, sda)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SDA pin"));
}
if(!IS_VALID_SCL(i2c_id, scl)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SCL pin"));
}
_PimoroniI2C_obj_t *i2c = (_PimoroniI2C_obj_t *)MP_OBJ_TO_PTR(args[ARG_i2c].u_obj);
self = m_new_obj(breakout_potentiometer_BreakoutPotentiometer_obj_t);
self->base.type = &breakout_potentiometer_BreakoutPotentiometer_type;
self->breakout = new BreakoutPotentiometer(args[ARG_address].u_int, sda, scl, args[ARG_interrupt].u_int);
self->breakout = new BreakoutPotentiometer(i2c->i2c, args[ARG_interrupt].u_int);
if(!self->breakout->init()) {
mp_raise_msg(&mp_type_RuntimeError, "Potentiometer breakout not found when initialising");

Wyświetl plik

@ -3,6 +3,8 @@ string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
add_library(usermod_${MOD_NAME} INTERFACE)
target_sources(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../common/pimoroni_i2c.cpp
)
@ -11,7 +13,7 @@ target_include_directories(usermod_${MOD_NAME} INTERFACE
)
target_compile_definitions(usermod_${MOD_NAME} INTERFACE
-DMODULE_${MOD_NAME_UPPER}_ENABLED=1
MODULE_${MOD_NAME_UPPER}_ENABLED=1
)
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})

Wyświetl plik

@ -0,0 +1,47 @@
#include "pimoroni_i2c.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// PimoroniI2C Class
////////////////////////////////////////////////////////////////////////////////////////////////////
/***** Methods *****/
//MP_DEFINE_CONST_FUN_OBJ_KW(PimoroniI2C_read_obj, 2, PimoroniI2C_set_address);
/***** Binding of Methods *****/
STATIC const mp_rom_map_elem_t PimoroniI2C_locals_dict_table[] = {
};
STATIC MP_DEFINE_CONST_DICT(PimoroniI2C_locals_dict, PimoroniI2C_locals_dict_table);
/***** Class Definition *****/
const mp_obj_type_t PimoroniI2C_type = {
{ &mp_type_type },
.name = MP_QSTR_pimoroni_i2c,
.print = PimoroniI2C_print,
.make_new = PimoroniI2C_make_new,
.locals_dict = (mp_obj_dict_t*)&PimoroniI2C_locals_dict,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// breakout_potentiometer Module
////////////////////////////////////////////////////////////////////////////////////////////////////
/***** Globals Table *****/
STATIC const mp_map_elem_t pimoroni_i2c_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pimoroni_i2c) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PimoroniI2C), (mp_obj_t)&PimoroniI2C_type },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_pimoroni_i2c_globals, pimoroni_i2c_globals_table);
/***** Module Definition *****/
const mp_obj_module_t pimoroni_i2c_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_pimoroni_i2c_globals,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
MP_REGISTER_MODULE(MP_QSTR_pimoroni_i2c, pimoroni_i2c_user_cmodule, MODULE_PIMORONI_I2C_ENABLED);
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

Wyświetl plik

@ -0,0 +1,77 @@
#include "common/pimoroni_i2c.hpp"
#include <cstdio>
#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o))
// SDA/SCL on even/odd pins, I2C0/I2C1 on even/odd pairs of pins.
#define IS_VALID_SCL(i2c, pin) (((pin) & 1) == 1 && (((pin) & 2) >> 1) == (i2c))
#define IS_VALID_SDA(i2c, pin) (((pin) & 1) == 0 && (((pin) & 2) >> 1) == (i2c))
using namespace pimoroni;
extern "C" {
#include "pimoroni_i2c.h"
/***** Variables Struct *****/
typedef struct _PimoroniI2C_obj_t {
mp_obj_base_t base;
I2C *i2c;
} _PimoroniI2C_obj_t;
/***** Print *****/
void PimoroniI2C_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind; //Unused input parameter
_PimoroniI2C_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PimoroniI2C_obj_t);
I2C* i2c = self->i2c;
mp_print_str(print, "PimoroniI2C(");
mp_print_str(print, "i2c = ");
mp_obj_print_helper(print, mp_obj_new_int((i2c->get_i2c() == i2c0) ? 0 : 1), PRINT_REPR);
mp_print_str(print, ", sda = ");
mp_obj_print_helper(print, mp_obj_new_int(i2c->get_sda()), PRINT_REPR);
mp_print_str(print, ", scl = ");
mp_obj_print_helper(print, mp_obj_new_int(i2c->get_scl()), PRINT_REPR);
mp_print_str(print, ")");
}
/***** Constructor *****/
mp_obj_t PimoroniI2C_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
_PimoroniI2C_obj_t *self = nullptr;
enum { ARG_sda, ARG_scl };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_sda, MP_ARG_INT, {.u_int = I2C_DEFAULT_SDA} },
{ MP_QSTR_scl, MP_ARG_INT, {.u_int = I2C_DEFAULT_SCL} },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// Get I2C bus.
int sda = args[ARG_sda].u_int;
int scl = args[ARG_scl].u_int;
int i2c_id = (sda >> 1) & 0b1; // i2c bus for given SDA pin
if(!IS_VALID_SDA(i2c_id, sda)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SDA pin"));
}
if(!IS_VALID_SCL(i2c_id, scl)) {
mp_raise_ValueError(MP_ERROR_TEXT("bad SCL pin"));
}
self = m_new_obj(_PimoroniI2C_obj_t);
self->base.type = &PimoroniI2C_type;
self->i2c = new I2C(sda, scl);
return MP_OBJ_FROM_PTR(self);
}
}

Wyświetl plik

@ -0,0 +1,11 @@
// Include MicroPython API.
#include "py/runtime.h"
/***** Extern of Class Definition *****/
extern const mp_obj_type_t PimoroniI2C_type;
/***** Extern of Class Methods *****/
extern void PimoroniI2C_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
extern mp_obj_t PimoroniI2C_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern bool Pimoroni_mp_obj_to_i2c(mp_obj_t in, void *out);