diff --git a/micropython/modules/breakout_encoder/breakout_encoder.cpp b/micropython/modules/breakout_encoder/breakout_encoder.cpp index 3c01d831..2bd3b86d 100644 --- a/micropython/modules/breakout_encoder/breakout_encoder.cpp +++ b/micropython/modules/breakout_encoder/breakout_encoder.cpp @@ -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"); diff --git a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp index f2620361..05c2820e 100644 --- a/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp +++ b/micropython/modules/breakout_potentiometer/breakout_potentiometer.cpp @@ -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"); diff --git a/micropython/modules/pimoroni_i2c/micropython.cmake b/micropython/modules/pimoroni_i2c/micropython.cmake index 761e9254..0d4d9801 100644 --- a/micropython/modules/pimoroni_i2c/micropython.cmake +++ b/micropython/modules/pimoroni_i2c/micropython.cmake @@ -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}) \ No newline at end of file diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.c b/micropython/modules/pimoroni_i2c/pimoroni_i2c.c new file mode 100644 index 00000000..9c5e021d --- /dev/null +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.c @@ -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); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp b/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp new file mode 100644 index 00000000..9e071782 --- /dev/null +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp @@ -0,0 +1,77 @@ +#include "common/pimoroni_i2c.hpp" +#include + +#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); +} + +} \ No newline at end of file diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.h b/micropython/modules/pimoroni_i2c/pimoroni_i2c.h new file mode 100644 index 00000000..684c9c22 --- /dev/null +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.h @@ -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); \ No newline at end of file