From edf77ddb760eae3957699e7229dcc3509eb0fb9c Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 18 May 2021 09:48:41 +0100 Subject: [PATCH] Add finaliser for Pimoroni I2C This is the final piece of the puzzle. Prior to this rather considerable change, Pimoroni breakouts were not de-init'ing I2C when they failed to init() This change adds a __del__ method which cleans up the I2C instance attached to a MicroPython object. Under the hood this calls i2c_deinit() and resets the associated pins to their default state. This means that I2C is now cleaned up during a *soft* reset, so running a script with the wrong pins, seeing an error, changing the pins and running it again will not result in subsequent I2C errors. Previously a hard reset was required. To recreate on Breakout Garden run the following code: ``` from breakout_potentiometer import BreakoutPotentiometer from pimoroni_i2c import PimoroniI2C i2c = PimoroniI2C() pot = BreakoutPotentiometer(i2c) ``` This will fail correctly with "Potentiometer breakout not found when initialising." (The default pins are configured for Pico Explorer) Now change that to the following and run again without hard-resetting: ``` from breakout_potentiometer import BreakoutPotentiometer from pimoroni_i2c import PimoroniI2C i2c = PimoroniI2C(4, 5) pot = BreakoutPotentiometer(i2c) ``` This should now work, since the failed I2C instance was cleaned up. Without this change, the second attempt would result in an inexplicable failure. Since most? (many?) Pico users do not have a reset button, this trap requiring a hard-reset is pretty nasty and would likely have resulted in a support nightmare. Whew. --- micropython/modules/pimoroni_i2c/pimoroni_i2c.c | 3 ++- micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp | 9 ++++++++- micropython/modules/pimoroni_i2c/pimoroni_i2c.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.c b/micropython/modules/pimoroni_i2c/pimoroni_i2c.c index 9c5e021d..e91b53b3 100644 --- a/micropython/modules/pimoroni_i2c/pimoroni_i2c.c +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.c @@ -6,10 +6,11 @@ /***** Methods *****/ -//MP_DEFINE_CONST_FUN_OBJ_KW(PimoroniI2C_read_obj, 2, PimoroniI2C_set_address); +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); diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp b/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp index 9e071782..1d0c2dee 100644 --- a/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.cpp @@ -39,6 +39,13 @@ void PimoroniI2C_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ mp_print_str(print, ")"); } +/***** Destructor ******/ +mp_obj_t PimoroniI2C___del__(mp_obj_t self_in) { + _PimoroniI2C_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PimoroniI2C_obj_t); + delete self->i2c; + return mp_const_none; +} + /***** 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; @@ -66,7 +73,7 @@ mp_obj_t PimoroniI2C_make_new(const mp_obj_type_t *type, size_t n_args, size_t n mp_raise_ValueError(MP_ERROR_TEXT("bad SCL pin")); } - self = m_new_obj(_PimoroniI2C_obj_t); + self = m_new_obj_with_finaliser(_PimoroniI2C_obj_t); self->base.type = &PimoroniI2C_type; self->i2c = new I2C(sda, scl); diff --git a/micropython/modules/pimoroni_i2c/pimoroni_i2c.h b/micropython/modules/pimoroni_i2c/pimoroni_i2c.h index 684c9c22..3351a8af 100644 --- a/micropython/modules/pimoroni_i2c/pimoroni_i2c.h +++ b/micropython/modules/pimoroni_i2c/pimoroni_i2c.h @@ -7,5 +7,6 @@ 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 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