diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index 7d77c0d43a27b..14a21f78778c4 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; @@ -97,6 +97,12 @@ 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 board supports internal pullups, set SDA and SCL channels up + if (internal_pullup){ + gpio_set_pin_pull_mode(sda->number, GPIO_PULL_UP); + gpio_set_pin_pull_mode(scl->number, GPIO_PULL_UP); + } + if (!gpio_get_pin_level(sda->number) || !gpio_get_pin_level(scl->number)) { reset_pin_number(sda->number); reset_pin_number(scl->number); diff --git a/ports/broadcom/common-hal/busio/I2C.c b/ports/broadcom/common-hal/busio/I2C.c index 8e135ab4d7fe7..8fa05f36c879c 100644 --- a/ports/broadcom/common-hal/busio/I2C.c +++ b/ports/broadcom/common-hal/busio/I2C.c @@ -66,10 +66,13 @@ 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) { + + //NB: this board doesn't appear to support internal pullups - throw internal_pullup away? + size_t instance_index = NUM_I2C; - uint8_t scl_alt = 0; - uint8_t sda_alt = 0; + uint8_t scl_alt = 0; // Are these necessary, or can they be declared in the for? + uint8_t sda_alt = 0; // e.g. for (uint8_t scl_alt = 0; scl_alt < 6; scl_alt++) for (scl_alt = 0; scl_alt < 6; scl_alt++) { if (scl->functions[scl_alt].type != PIN_FUNCTION_I2C || i2c_in_use[scl->functions[scl_alt].index] || diff --git a/ports/cxd56/common-hal/busio/I2C.c b/ports/cxd56/common-hal/busio/I2C.c index 7b9420fa1b7d8..571c3a08d2514 100644 --- a/ports/cxd56/common-hal/busio/I2C.c +++ b/ports/cxd56/common-hal/busio/I2C.c @@ -35,6 +35,9 @@ 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) { + + //NB: This board doesn't appear to support internal pullups - throw internal_pullup away? + 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..b9f65f47c1254 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. @@ -58,6 +58,9 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, gpio_pulldown_dis(sda->number); gpio_pulldown_dis(scl->number); + // This appears to be a board-specific way of supporting internal pullups without + // going through all of the changes I've made - @dhalbert can you comment? + // Not going to change anything here before discussion - will just throw internal_pullup away #if CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP gpio_pullup_en(sda->number); gpio_pullup_en(scl->number); diff --git a/ports/mimxrt10xx/common-hal/busio/I2C.c b/ports/mimxrt10xx/common-hal/busio/I2C.c index 74639d0ef169e..9620bba8afd52 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.) @@ -105,6 +105,12 @@ 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 the board supports internal pullups, set the SDA and SCL channel pulls up + if (internal_pullup){ + i2c_check_pin_config(sda, 1); + i2c_check_pin_config(scl, 1); + } if (!GPIO_PinRead(sda->gpio, sda->number) || !GPIO_PinRead(scl->gpio, scl->number)) { common_hal_reset_pin(sda); diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 04a648a4e2c47..4b1ebf76b789b 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -275,18 +275,20 @@ FLASHER ?= ifeq ($(FLASHER),) +# NOTE: added the .exe extension for WSL users - not sure if this needs to be removed prevent breakage + # Also update to bootloader settting to validate application and skip checksum ( app valid = 0x0001, crc = 0x0000 ) flash: $(BUILD)/firmware.hex - nrfjprog --program $< --sectorerase -f $(MCU_VARIANT) - nrfjprog --erasepage $(BOOT_SETTING_ADDR) -f $(MCU_VARIANT) - nrfjprog --memwr $(BOOT_SETTING_ADDR) --val 0x00000001 -f $(MCU_VARIANT) - nrfjprog --reset -f $(MCU_VARIANT) + nrfjprog.exe --program $< --sectorerase -f $(MCU_VARIANT) + nrfjprog.exe --erasepage $(BOOT_SETTING_ADDR) -f $(MCU_VARIANT) + nrfjprog.exe --memwr $(BOOT_SETTING_ADDR) --val 0x00000001 -f $(MCU_VARIANT) + nrfjprog.exe --reset -f $(MCU_VARIANT) sd: $(BUILD)/firmware.hex - nrfjprog --eraseall -f $(MCU_VARIANT) - nrfjprog --program $(SOFTDEV_HEX) -f $(MCU_VARIANT) - nrfjprog --program $< --sectorerase -f $(MCU_VARIANT) - nrfjprog --reset -f $(MCU_VARIANT) + nrfjprog.exe --eraseall -f $(MCU_VARIANT) + nrfjprog.exe --program $(SOFTDEV_HEX) -f $(MCU_VARIANT) + nrfjprog.exe --program $< --sectorerase -f $(MCU_VARIANT) + nrfjprog.exe --reset -f $(MCU_VARIANT) else ifeq ($(FLASHER), pyocd) diff --git a/ports/nrf/boards/pca10100/mpconfigboard.mk b/ports/nrf/boards/pca10100/mpconfigboard.mk index 8ae25393f80d1..7a3dead34c4d3 100644 --- a/ports/nrf/boards/pca10100/mpconfigboard.mk +++ b/ports/nrf/boards/pca10100/mpconfigboard.mk @@ -19,6 +19,10 @@ CIRCUITPY_DISPLAYIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_I2CPERIPHERAL = 0 + +# Support for Internal Pullups for this MCU +CIRCUITPY_I2C_INTERNAL_PULLUPS = 1 + CIRCUITPY_IS31FL3741 = 0 CIRCUITPY_JSON = 0 CIRCUITPY_KEYPAD = 0 diff --git a/ports/nrf/common-hal/busio/I2C.c b/ports/nrf/common-hal/busio/I2C.c index de9417a6cc3e7..0722ae983eecc 100644 --- a/ports/nrf/common-hal/busio/I2C.c +++ b/ports/nrf/common-hal/busio/I2C.c @@ -94,11 +94,19 @@ 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")); } + // Set pulls on I2C pins up if setpullup is 1 - this supports boards with internal pullups + 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); + } + // Find a free instance. self->twim_peripheral = NULL; for (size_t i = 0; i < MP_ARRAY_SIZE(twim_peripherals); i++) { @@ -126,6 +134,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); + // 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); + } + if (!nrf_gpio_pin_read(sda->number) || !nrf_gpio_pin_read(scl->number)) { reset_pin_number(sda->number); reset_pin_number(scl->number); diff --git a/ports/raspberrypi/common-hal/busio/I2C.c b/ports/raspberrypi/common-hal/busio/I2C.c index 87c78814c2364..40bb7a3109ef4 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,6 +92,12 @@ 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); + // Set pull for SDA and SCL pins UP if internal_pullup = true + if (internal_pullup){ + gpio_set_pulls(sda->number, true, false) + gpio_set_pulls(scl->number, true, false) + } + if (!gpio_get(sda->number) || !gpio_get(scl->number)) { reset_pin_number(sda->number); reset_pin_number(scl->number); @@ -112,7 +118,9 @@ 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, + // + // NB: passing internal_pullup to satisfy new signature + 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..10c08e02087e9 100644 --- a/ports/stm/common-hal/busio/I2C.c +++ b/ports/stm/common-hal/busio/I2C.c @@ -83,7 +83,10 @@ 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) { + + // code is particularly involved, no idea if this board supports internal pullups + // will throw internal_pullup away // Match pins to I2C objects I2C_TypeDef *I2Cx; diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 6efc341fce2af..6b27ebf3d1077 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_I2C_INTERNAL_PULLUPS +#define I2C_USE_INTERNAL_PULLUPS = true +#else +#define I2C_USE_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..f69d855aaae0e 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -241,6 +241,10 @@ CFLAGS += -DCIRCUITPY_GNSS=$(CIRCUITPY_GNSS) CIRCUITPY_I2CPERIPHERAL ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_I2CPERIPHERAL=$(CIRCUITPY_I2CPERIPHERAL) +# Support for use of internal pullups with I2C +CIRCUITPY_I2C_INTERNAL_PULLUPS ?= 0 +CFLAGS += -DCIRCUITPY_I2C_INTERNAL_PULLUPS=$(CIRCUITPY_I2C_INTERNAL_PULLUPS) + CIRCUITPY_IMAGECAPTURE ?= 0 CFLAGS += -DCIRCUITPY_IMAGECAPTURE=$(CIRCUITPY_IMAGECAPTURE) diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c index b47ace149f076..1a0d8e5d12b8d 100644 --- a/shared-bindings/bitbangio/I2C.c +++ b/shared-bindings/bitbangio/I2C.c @@ -55,15 +55,17 @@ //| //| :param ~microcontroller.Pin scl: The clock pin //| :param ~microcontroller.Pin sda: The data pin +//| :param bool internal_pullup: Indicates if internal pullups should be used - only available on boards that support them. //| :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 *all_args) { - 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 = 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..173c2a486ce3a 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_pullup: Indicates if internal pullups should be used - only available on boards that support them. //| :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..d3dbc487025a6 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, I2C_USE_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..4bfd2b24a1a08 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, uint32_t timeout) { - shared_module_bitbangio_i2c_construct(&self->bitbang, scl, sda, freq, 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, internal_pullup, freq, timeout); } bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {