diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index 77676b5355..347a2e3490 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -41,7 +41,7 @@ #define ATTEMPTS 2 void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, - const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency) { + const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency, uint32_t timeout) { Sercom* sercom = NULL; uint8_t sercom_index; uint32_t sda_pinmux = 0; diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 616e9875c1..907a4cbdfd 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -28,7 +28,7 @@ #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_MODULE_WEAK_LINKS (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) -#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_USE_INTERNAL_ERRNO (0) #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_COMPLEX (0) diff --git a/ports/nrf/common-hal/busio/I2C.c b/ports/nrf/common-hal/busio/I2C.c index 07b067a2cb..7e92a84ffe 100644 --- a/ports/nrf/common-hal/busio/I2C.c +++ b/ports/nrf/common-hal/busio/I2C.c @@ -32,7 +32,7 @@ #include "pins.h" #include "nrf.h" -void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency) { +void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency, uint32_t timeout ) { if (scl->pin == sda->pin) { mp_raise_ValueError("Invalid pins"); } diff --git a/py/objexcept.c b/py/objexcept.c index 4844c7f92d..9ef2f2e34d 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -275,9 +275,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException) MP_DEFINE_EXCEPTION(UnboundLocalError, NameError) */ MP_DEFINE_EXCEPTION(OSError, Exception) -#if MICROPY_PY_BUILTINS_TIMEOUTERROR - MP_DEFINE_EXCEPTION(TimeoutError, OSError) -#endif + MP_DEFINE_EXCEPTION(TimeoutError, OSError) /* MP_DEFINE_EXCEPTION(BlockingIOError, OSError) MP_DEFINE_EXCEPTION(ChildProcessError, OSError) diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c index f8f60210e6..a5c000ae5a 100644 --- a/shared-bindings/bitbangio/I2C.c +++ b/shared-bindings/bitbangio/I2C.c @@ -35,6 +35,7 @@ #include "lib/utils/context_manager_helpers.h" #include "py/mperrno.h" #include "py/runtime.h" + //| .. currentmodule:: bitbangio //| //| :class:`I2C` --- Two wire serial protocol @@ -49,6 +50,7 @@ //| :param ~microcontroller.Pin scl: The clock pin //| :param ~microcontroller.Pin sda: The data pin //| :param int frequency: The clock frequency of the bus +//| :param int timeout: The maximum clock stretching timeout in microseconds //| STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); @@ -57,11 +59,12 @@ STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, self->base.type = &bitbangio_i2c_type; mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); - enum { ARG_scl, ARG_sda, ARG_frequency }; + enum { ARG_scl, ARG_sda, ARG_frequency, ARG_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -69,7 +72,7 @@ STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, assert_pin(args[ARG_sda].u_obj, false); const mcu_pin_obj_t* scl = MP_OBJ_TO_PTR(args[ARG_scl].u_obj); const mcu_pin_obj_t* sda = MP_OBJ_TO_PTR(args[ARG_sda].u_obj); - shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int); + shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int); return (mp_obj_t)self; } diff --git a/shared-bindings/bitbangio/I2C.h b/shared-bindings/bitbangio/I2C.h index 9d393ee124..1ce4d21e91 100644 --- a/shared-bindings/bitbangio/I2C.h +++ b/shared-bindings/bitbangio/I2C.h @@ -39,7 +39,8 @@ extern const mp_obj_type_t bitbangio_i2c_type; extern void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, const mcu_pin_obj_t * scl, const mcu_pin_obj_t * sda, - uint32_t frequency); + uint32_t frequency, + uint32_t us_timeout); extern void shared_module_bitbangio_i2c_deinit(bitbangio_i2c_obj_t *self); extern bool shared_module_bitbangio_i2c_deinited(bitbangio_i2c_obj_t *self); diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index b0954d6c8a..0d21d30f00 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -56,6 +56,7 @@ //| :param ~microcontroller.Pin scl: The clock pin //| :param ~microcontroller.Pin sda: The data pin //| :param int frequency: The clock frequency in Hertz +//| :param int timeout: The maximum clock stretching timeut - only for bitbang //| STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); @@ -63,11 +64,12 @@ STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz self->base.type = &busio_i2c_type; mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); - enum { ARG_scl, ARG_sda, ARG_frequency }; + enum { ARG_scl, ARG_sda, ARG_frequency, ARG_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -77,7 +79,7 @@ STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz assert_pin_free(scl); const mcu_pin_obj_t* sda = MP_OBJ_TO_PTR(args[ARG_sda].u_obj); assert_pin_free(sda); - common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int); + common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int); return (mp_obj_t)self; } diff --git a/shared-bindings/busio/I2C.h b/shared-bindings/busio/I2C.h index 7185d6075c..739732e97b 100644 --- a/shared-bindings/busio/I2C.h +++ b/shared-bindings/busio/I2C.h @@ -46,7 +46,8 @@ extern const mp_obj_type_t busio_i2c_type; extern void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t * scl, const mcu_pin_obj_t * sda, - uint32_t frequency); + uint32_t frequency, + uint32_t timeout); extern void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self); extern bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self); diff --git a/shared-module/bitbangio/I2C.c b/shared-module/bitbangio/I2C.c index 7eeda0e00e..47529748a5 100644 --- a/shared-module/bitbangio/I2C.c +++ b/shared-module/bitbangio/I2C.c @@ -25,16 +25,15 @@ */ #include "shared-bindings/bitbangio/I2C.h" - #include "py/mperrno.h" #include "py/obj.h" +#include "py/runtime.h" #include "common-hal/microcontroller/Pin.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-module/bitbangio/types.h" -#define I2C_STRETCH_LIMIT 255 STATIC void delay(bitbangio_i2c_obj_t *self) { // We need to use an accurate delay to get acceptable I2C @@ -48,11 +47,16 @@ STATIC void scl_low(bitbangio_i2c_obj_t *self) { STATIC void scl_release(bitbangio_i2c_obj_t *self) { common_hal_digitalio_digitalinout_set_value(&self->scl, true); + uint32_t count = self->us_timeout; delay(self); // For clock stretching, wait for the SCL pin to be released, with timeout. - for (int count = I2C_STRETCH_LIMIT; !common_hal_digitalio_digitalinout_get_value(&self->scl) && count; --count) { + for (; !common_hal_digitalio_digitalinout_get_value(&self->scl) && count; --count) { common_hal_mcu_delay_us(1); } + // raise exception on timeout + if (count == 0) { + mp_raise_msg(&mp_type_TimeoutError, "Clock stretch too long"); + } } STATIC void sda_low(bitbangio_i2c_obj_t *self) { @@ -142,7 +146,10 @@ STATIC bool read_byte(bitbangio_i2c_obj_t *self, uint8_t *val, bool ack) { void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, const mcu_pin_obj_t * scl, const mcu_pin_obj_t * sda, - uint32_t frequency) { + uint32_t frequency, + uint32_t us_timeout) { + + self->us_timeout = us_timeout; self->us_delay = 500000 / frequency; if (self->us_delay == 0) { self->us_delay = 1; diff --git a/shared-module/bitbangio/types.h b/shared-module/bitbangio/types.h index dfe50f0499..6d17234741 100644 --- a/shared-module/bitbangio/types.h +++ b/shared-module/bitbangio/types.h @@ -36,6 +36,7 @@ typedef struct { digitalio_digitalinout_obj_t scl; digitalio_digitalinout_obj_t sda; uint32_t us_delay; + uint32_t us_timeout; volatile bool locked; } bitbangio_i2c_obj_t; diff --git a/shared-module/busio/I2C.c b/shared-module/busio/I2C.c index 68d6ea22ab..06e1af10a1 100644 --- a/shared-module/busio/I2C.c +++ b/shared-module/busio/I2C.c @@ -30,8 +30,8 @@ #include "py/nlr.h" void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, - const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t freq) { - shared_module_bitbangio_i2c_construct(&self->bitbang, scl, sda, freq); + const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t freq, uint32_t timeout) { + shared_module_bitbangio_i2c_construct(&self->bitbang, scl, sda, freq, timeout); } bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {