diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index 7d77c0d43a27b..51d989c2d00f1 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -68,7 +68,7 @@ Sercom *samd_i2c_get_sercom(const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, } 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) { + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, bool internal_pullup, uint32_t frequency, uint32_t timeout) { uint8_t sercom_index; uint32_t sda_pinmux, scl_pinmux; diff --git a/ports/broadcom/common-hal/busio/I2C.c b/ports/broadcom/common-hal/busio/I2C.c index 8e135ab4d7fe7..d251150711631 100644 --- a/ports/broadcom/common-hal/busio/I2C.c +++ b/ports/broadcom/common-hal/busio/I2C.c @@ -66,7 +66,7 @@ void reset_i2c(void) { } 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) { + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, bool internal_pullup, uint32_t frequency, uint32_t timeout) { size_t instance_index = NUM_I2C; uint8_t scl_alt = 0; uint8_t sda_alt = 0; diff --git a/ports/cxd56/common-hal/busio/I2C.c b/ports/cxd56/common-hal/busio/I2C.c index 7b9420fa1b7d8..17503b9d7857f 100644 --- a/ports/cxd56/common-hal/busio/I2C.c +++ b/ports/cxd56/common-hal/busio/I2C.c @@ -34,7 +34,7 @@ #include "shared-bindings/busio/I2C.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, uint32_t timeout) { + const mcu_pin_obj_t *sda, bool internal_pullup, uint32_t frequency, uint32_t timeout) { if (frequency != I2C_SPEED_STANDARD && frequency != I2C_SPEED_FAST) { mp_raise_ValueError(translate("Unsupported baudrate")); } diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index 81b23cb3a3570..50a23db5121f5 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -35,7 +35,7 @@ #include "supervisor/shared/translate.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, uint32_t timeout) { + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, bool internal_pullup, uint32_t frequency, uint32_t timeout) { // Pins 45 and 46 are "strapping" pins that impact start up behavior. They usually need to // be pulled-down so pulling them up for I2C is a bad idea. To make this hard, we don't // support I2C on these pins. diff --git a/ports/mimxrt10xx/common-hal/busio/I2C.c b/ports/mimxrt10xx/common-hal/busio/I2C.c index 74639d0ef169e..dfc454308f28d 100644 --- a/ports/mimxrt10xx/common-hal/busio/I2C.c +++ b/ports/mimxrt10xx/common-hal/busio/I2C.c @@ -86,7 +86,7 @@ static void i2c_check_pin_config(const mcu_pin_obj_t *pin, uint32_t pull) { } 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) { + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, bool internal_pullup, uint32_t frequency, uint32_t timeout) { #if CIRCUITPY_REQUIRE_I2C_PULLUPS // Test that the pins are in a high state. (Hopefully indicating they are pulled up.) diff --git a/ports/nrf/common-hal/busio/I2C.c b/ports/nrf/common-hal/busio/I2C.c index de9417a6cc3e7..cae313495fadb 100644 --- a/ports/nrf/common-hal/busio/I2C.c +++ b/ports/nrf/common-hal/busio/I2C.c @@ -94,11 +94,13 @@ static uint8_t twi_error_to_mp(const nrfx_err_t err) { return 0; } -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) { +void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, bool internal_pullup, uint32_t frequency, uint32_t timeout) { if (scl->number == sda->number) { mp_raise_ValueError(translate("Invalid pins")); } + + // Find a free instance. self->twim_peripheral = NULL; for (size_t i = 0; i < MP_ARRAY_SIZE(twim_peripherals); i++) { @@ -126,7 +128,14 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t * // We must pull up within 3us to achieve 400khz. common_hal_mcu_delay_us(3); - if (!nrf_gpio_pin_read(sda->number) || !nrf_gpio_pin_read(scl->number)) { + // Set pulls up if internal_pullup is true + if (internal_pullup){ + nrf_gpio_pin_pull_t hal_pull = NRF_GPIO_PIN_PULLUP; + + nrf_gpio_cfg_input(scl->number, hal_pull); + nrf_gpio_cfg_input(sda->number, hal_pull); + } + else if (!nrf_gpio_pin_read(sda->number) || !nrf_gpio_pin_read(scl->number)) { reset_pin_number(sda->number); reset_pin_number(scl->number); mp_raise_RuntimeError(translate("No pull up found on SDA or SCL; check your wiring")); diff --git a/ports/nrf/mpconfigport.mk b/ports/nrf/mpconfigport.mk index 55ade5562f03b..baa205a5af74d 100644 --- a/ports/nrf/mpconfigport.mk +++ b/ports/nrf/mpconfigport.mk @@ -83,6 +83,7 @@ ifeq ($(MCU_CHIP),nrf52833) MCU_SERIES = m4 MCU_VARIANT = nrf52 MCU_SUB_VARIANT = nrf52833 +CIRCUITPY_INTERNAL_PULLUPS = 1 SD ?= s140 SOFTDEV_VERSION ?= 7.0.1 diff --git a/ports/raspberrypi/common-hal/busio/I2C.c b/ports/raspberrypi/common-hal/busio/I2C.c index 87c78814c2364..d3e057aa71a79 100644 --- a/ports/raspberrypi/common-hal/busio/I2C.c +++ b/ports/raspberrypi/common-hal/busio/I2C.c @@ -55,7 +55,7 @@ void reset_i2c(void) { } 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) { + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, bool internal_pullup, uint32_t frequency, uint32_t timeout) { self->peripheral = NULL; // I2C pins have a regular pattern. SCL is always odd and SDA is even. They match up in pairs // so we can divide by two to get the instance. This pattern repeats. @@ -92,7 +92,14 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // We must pull up within 3us to achieve 400khz. common_hal_mcu_delay_us(3); - if (!gpio_get(sda->number) || !gpio_get(scl->number)) { + // Set pulls up if internal_pullup is true + if (internal_pullup){ + nrf_gpio_pin_pull_t hal_pull = NRF_GPIO_PIN_PULLUP; + + nrf_gpio_cfg_input(scl->number, hal_pull); + nrf_gpio_cfg_input(sda->number, hal_pull); + } + else if (!nrf_gpio_pin_read(sda->number) || !nrf_gpio_pin_read(scl->number)) { reset_pin_number(sda->number); reset_pin_number(scl->number); mp_raise_RuntimeError(translate("No pull up found on SDA or SCL; check your wiring")); @@ -112,7 +119,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // // Do not use the default supplied clock stretching timeout here. // It is too short for some devices. Use the busio timeout instead. - shared_module_bitbangio_i2c_construct(&self->bitbangio_i2c, scl, sda, + shared_module_bitbangio_i2c_construct(&self->bitbangio_i2c, scl, sda, internal_pullup, frequency, BUS_TIMEOUT_US); self->baudrate = i2c_init(self->peripheral, frequency); diff --git a/ports/stm/common-hal/busio/I2C.c b/ports/stm/common-hal/busio/I2C.c index ffad368a2f145..c7477cb4f2074 100644 --- a/ports/stm/common-hal/busio/I2C.c +++ b/ports/stm/common-hal/busio/I2C.c @@ -83,7 +83,7 @@ void i2c_reset(void) { } 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) { + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, bool internal_pullup, uint32_t frequency, uint32_t timeout) { // Match pins to I2C objects I2C_TypeDef *I2Cx; diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 6efc341fce2af..e469b5dd4792e 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -276,6 +276,13 @@ typedef long mp_off_t; #define BOARD_UART_ROOT_POINTER #endif +// Support for internal pullups for boards that have them: e.g. nrf52833 +#if CIRCUITPY_INTERNAL_PULLUPS +#define HAS_INTERNAL_PULLUPS = true +#else +#define HAS_INTERNAL_PULLUPS = false +#endif + #if CIRCUITPY_DISPLAYIO #ifndef CIRCUITPY_DISPLAY_LIMIT #define CIRCUITPY_DISPLAY_LIMIT (1) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 7f0721264b896..ff666058c5d03 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -462,3 +462,7 @@ CFLAGS += -DCIRCUITPY_WATCHDOG=$(CIRCUITPY_WATCHDOG) CIRCUITPY_WIFI ?= 0 CFLAGS += -DCIRCUITPY_WIFI=$(CIRCUITPY_WIFI) + +# support for internal pullups +CIRCUITPY_INTERNAL_PULLUPS ?= 0 +CFLAGS += -DCIRCUITPY_INTERNAL_PULLUPS=$(CIRCUITPY_INTERNAL_PULLUPS) \ No newline at end of file diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c index b47ace149f076..9727026623f1b 100644 --- a/shared-bindings/bitbangio/I2C.c +++ b/shared-bindings/bitbangio/I2C.c @@ -55,6 +55,7 @@ //| //| :param ~microcontroller.Pin scl: The clock pin //| :param ~microcontroller.Pin sda: The data pin +//| :param bool internal_pullups: Set pulls on each pin to up if board supports internal pullups - defaults to false //| :param int frequency: The clock frequency of the bus //| :param int timeout: The maximum clock stretching timeout in microseconds""" //| ... @@ -64,6 +65,7 @@ STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, 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_internal_pullup, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { 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} }, }; @@ -75,7 +77,7 @@ STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, bitbangio_i2c_obj_t *self = m_new_obj(bitbangio_i2c_obj_t); self->base.type = &bitbangio_i2c_type; - shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int); + shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_internal_pullup].u_int, 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 d950180a23274..40feb5ad4beab 100644 --- a/shared-bindings/bitbangio/I2C.h +++ b/shared-bindings/bitbangio/I2C.h @@ -39,6 +39,7 @@ 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, + bool internal_pullup, uint32_t frequency, uint32_t us_timeout); diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index 4aea62a8a5242..96b6ebb804b7f 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -55,6 +55,7 @@ //| //| :param ~microcontroller.Pin scl: The clock pin //| :param ~microcontroller.Pin sda: The data pin +//| :param bool internal_pullups: Set pulls on each pin to up if board supports internal pullups - defaults to false //| :param int frequency: The clock frequency in Hertz //| :param int timeout: The maximum clock stretching timeut - (used only for //| :class:`bitbangio.I2C`; ignored for :class:`busio.I2C`) @@ -67,10 +68,11 @@ 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 *all_args) { busio_i2c_obj_t *self = m_new_obj(busio_i2c_obj_t); self->base.type = &busio_i2c_type; - enum { ARG_scl, ARG_sda, ARG_frequency, ARG_timeout }; + enum { ARG_scl, ARG_sda, ARG_internal_pullup, 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_internal_pullup, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} }, }; @@ -80,7 +82,7 @@ STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz const mcu_pin_obj_t *scl = validate_obj_is_free_pin(args[ARG_scl].u_obj); const mcu_pin_obj_t *sda = validate_obj_is_free_pin(args[ARG_sda].u_obj); - common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int); + common_hal_busio_i2c_construct(self, scl, sda, args[ARG_internal_pullup].u_int, 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 08701938c9153..f3c672f2ed699 100644 --- a/shared-bindings/busio/I2C.h +++ b/shared-bindings/busio/I2C.h @@ -46,6 +46,7 @@ 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, + bool internal_pullup, uint32_t frequency, uint32_t timeout); diff --git a/shared-module/bitbangio/I2C.c b/shared-module/bitbangio/I2C.c index 7d7380e214fdc..1153e86eda12c 100644 --- a/shared-module/bitbangio/I2C.c +++ b/shared-module/bitbangio/I2C.c @@ -145,6 +145,7 @@ 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, + bool internal_pullup, uint32_t frequency, uint32_t us_timeout) { diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 19d9e7ece0d85..352d599cec80f 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -62,7 +62,7 @@ mp_obj_t common_hal_board_create_i2c(void) { busio_i2c_obj_t *self = &i2c_obj; self->base.type = &busio_i2c_type; - common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, 100000, 255); + common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, HAS_INTERNAL_PULLUPS, 100000, 255); i2c_singleton = (mp_obj_t)self; return i2c_singleton; } diff --git a/shared-module/busio/I2C.c b/shared-module/busio/I2C.c index d3db18e3ad2ab..9be8c70b62ae7 100644 --- a/shared-module/busio/I2C.c +++ b/shared-module/busio/I2C.c @@ -30,7 +30,7 @@ #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, uint32_t timeout) { + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, bool internal_pullup, uint32_t freq, uint32_t timeout) { shared_module_bitbangio_i2c_construct(&self->bitbang, scl, sda, freq, timeout); }