diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.c b/micropython/modules/pimoroni_i2c/pimoroni_i2c.c index e91b53b3..6070e51f 100644 --- a/micropython/modules/pimoroni_i2c/pimoroni_i2c.c +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.c @@ -5,15 +5,20 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// -/***** Methods *****/ +/* MP_DEFINE_CONST_FUN_OBJ_1(PimoroniI2C___del___obj, PimoroniI2C___del__); -/***** Binding of Methods *****/ STATIC const mp_rom_map_elem_t PimoroniI2C_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&PimoroniI2C___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(PimoroniI2C_locals_dict, PimoroniI2C_locals_dict_table); +*/ + +STATIC const mp_machine_i2c_p_t machine_i2c_p = { + .transfer = mp_machine_i2c_transfer_adaptor, + .transfer_single = machine_i2c_transfer_single, +}; /***** Class Definition *****/ const mp_obj_type_t PimoroniI2C_type = { @@ -21,7 +26,8 @@ const mp_obj_type_t PimoroniI2C_type = { .name = MP_QSTR_pimoroni_i2c, .print = PimoroniI2C_print, .make_new = PimoroniI2C_make_new, - .locals_dict = (mp_obj_dict_t*)&PimoroniI2C_locals_dict, + .protocol = &machine_i2c_p, + .locals_dict = (mp_obj_dict_t*)&mp_machine_i2c_locals_dict, }; diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp b/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp index f8924fd2..62ad1858 100644 --- a/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp @@ -12,6 +12,9 @@ using namespace pimoroni; extern "C" { #include "pimoroni_i2c.h" +#include "py/mperrno.h" +#include "extmod/machine_i2c.h" +#include "hardware/i2c.h" /***** Variables Struct *****/ typedef struct _PimoroniI2C_obj_t { @@ -83,4 +86,47 @@ mp_obj_t PimoroniI2C_make_new(const mp_obj_type_t *type, size_t n_args, size_t n return MP_OBJ_FROM_PTR(self); } +// Reimplementation of the RP2 port's machine_i2c_transfer_single in terms of Pimoroni I2C +// https://github.com/micropython/micropython/blob/1fb01bd6c5dc350f3c617ca8edae8dea9e5516ae/ports/rp2/machine_i2c.c#L123 +int machine_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) { + _PimoroniI2C_obj_t *self = (_PimoroniI2C_obj_t *)self_in; + int ret; + bool nostop = !(flags & MP_MACHINE_I2C_FLAG_STOP); + if (flags & MP_MACHINE_I2C_FLAG_READ) { + ret = i2c_read_blocking(self->i2c->get_i2c(), addr, buf, len, nostop); + } else { + if (len == 0) { + // Workaround issue with hardware I2C not accepting zero-length writes. + mp_machine_soft_i2c_obj_t soft_i2c = { + .base = { &mp_machine_soft_i2c_type }, + .us_delay = 500000 / self->i2c->get_baudrate() + 1, + .us_timeout = 50000, + .scl = self->i2c->get_scl(), + .sda = self->i2c->get_sda(), + }; + mp_machine_i2c_buf_t bufs = { + .len = len, + .buf = buf, + }; + mp_hal_pin_open_drain(self->i2c->get_scl()); + mp_hal_pin_open_drain(self->i2c->get_sda()); + ret = mp_machine_soft_i2c_transfer(&soft_i2c.base, addr, 1, &bufs, flags); + gpio_set_function(self->i2c->get_scl(), GPIO_FUNC_I2C); + gpio_set_function(self->i2c->get_sda(), GPIO_FUNC_I2C); + return ret; + } else { + ret = i2c_write_blocking(self->i2c->get_i2c(), addr, buf, len, nostop); + } + } + if (ret < 0) { + if (ret == PICO_ERROR_TIMEOUT) { + return -MP_ETIMEDOUT; + } else { + return -MP_EIO; + } + } else { + return ret; + } +} + } \ No newline at end of file diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.h b/micropython/modules/pimoroni_i2c/pimoroni_i2c.h index 3351a8af..9b044861 100644 --- a/micropython/modules/pimoroni_i2c/pimoroni_i2c.h +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.h @@ -1,5 +1,6 @@ // Include MicroPython API. #include "py/runtime.h" +#include "extmod/machine_i2c.h" /***** Extern of Class Definition *****/ extern const mp_obj_type_t PimoroniI2C_type; @@ -9,4 +10,6 @@ extern void PimoroniI2C_print(const mp_print_t *print, mp_obj_t self_in, mp_prin 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 mp_obj_t PimoroniI2C___del__(mp_obj_t self_in); -extern bool Pimoroni_mp_obj_to_i2c(mp_obj_t in, void *out); \ No newline at end of file +extern bool Pimoroni_mp_obj_to_i2c(mp_obj_t in, void *out); + +extern int machine_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags); \ No newline at end of file