From d00bee2149825ee1e187a8a5bfc8c6e75874cc0b Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Wed, 10 Feb 2021 13:53:06 -0500 Subject: [PATCH 1/2] Fix I2C Repeated start error by converting to IT mode --- ports/stm/common-hal/busio/I2C.c | 92 +++++++++++++++++++++++++++++++- ports/stm/common-hal/busio/I2C.h | 2 + ports/stm/mpconfigport.h | 6 ++- 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/ports/stm/common-hal/busio/I2C.c b/ports/stm/common-hal/busio/I2C.c index de69da211a..7726b5e87f 100644 --- a/ports/stm/common-hal/busio/I2C.c +++ b/ports/stm/common-hal/busio/I2C.c @@ -61,6 +61,7 @@ STATIC bool never_reset_i2c[MAX_I2C]; #define ALL_CLOCKS 0xFF STATIC void i2c_clock_enable(uint8_t mask); STATIC void i2c_clock_disable(uint8_t mask); +STATIC void i2c_assign_irq(busio_i2c_obj_t *self, I2C_TypeDef * I2Cx); void i2c_reset(void) { uint16_t never_reset_mask = 0x00; @@ -136,6 +137,10 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, i2c_clock_enable(1 << (self->sda->periph_index - 1)); reserved_i2c[self->sda->periph_index - 1] = true; + // Create root pointer and assign IRQ + MP_STATE_PORT(cpy_i2c_obj_all)[self->sda->periph_index - 1] = self; + i2c_assign_irq(self, I2Cx); + // Handle the HAL handle differences #if (CPY_STM32H7 || CPY_STM32F7) if (frequency == 400000) { @@ -163,6 +168,13 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, } common_hal_mcu_pin_claim(sda); common_hal_mcu_pin_claim(scl); + + self->frame_in_prog = false; + + //start the receive interrupt chain + HAL_NVIC_DisableIRQ(self->irq); //prevent handle lock contention + HAL_NVIC_SetPriority(self->irq, 1, 0); + HAL_NVIC_EnableIRQ(self->irq); } void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { @@ -229,15 +241,46 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { - HAL_StatusTypeDef result = HAL_I2C_Master_Transmit(&(self->handle), (uint16_t)(addr << 1), + HAL_StatusTypeDef result; + if (!transmit_stop_bit) { + uint32_t xfer_opt; + if (!self->frame_in_prog) { + xfer_opt = I2C_FIRST_FRAME; + } else { + // handle rare possibility of multiple restart writes in a row + xfer_opt = I2C_NEXT_FRAME; + } + result = HAL_I2C_Master_Seq_Transmit_IT(&(self->handle), + (uint16_t)(addr << 1), (uint8_t *)data, + (uint16_t)len, xfer_opt); + while (HAL_I2C_GetState(&(self->handle)) != HAL_I2C_STATE_READY) + { + RUN_BACKGROUND_TASKS; + } + self->frame_in_prog = true; + } else { + result = HAL_I2C_Master_Transmit(&(self->handle), (uint16_t)(addr << 1), (uint8_t *)data, (uint16_t)len, 500); + } return result == HAL_OK ? 0 : MP_EIO; } uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { - return HAL_I2C_Master_Receive(&(self->handle), (uint16_t)(addr<<1), data, (uint16_t)len, 500) + if (!self->frame_in_prog) { + return HAL_I2C_Master_Receive(&(self->handle), (uint16_t)(addr<<1), data, (uint16_t)len, 500) == HAL_OK ? 0 : MP_EIO; + } else { + HAL_StatusTypeDef result = HAL_I2C_Master_Seq_Receive_IT(&(self->handle), + (uint16_t)(addr << 1), (uint8_t *)data, + (uint16_t)len, I2C_LAST_FRAME); + while (HAL_I2C_GetState(&(self->handle)) != HAL_I2C_STATE_READY) + { + RUN_BACKGROUND_TASKS; + } + self->frame_in_prog = false; + return result; + } } STATIC void i2c_clock_enable(uint8_t mask) { @@ -294,3 +337,48 @@ STATIC void i2c_clock_disable(uint8_t mask) { } #endif } + +STATIC void i2c_assign_irq(busio_i2c_obj_t *self, I2C_TypeDef * I2Cx) { + #ifdef I2C1 + if (I2Cx == I2C1) { + self->irq = I2C1_EV_IRQn; + } + #endif + #ifdef I2C2 + if (I2Cx == I2C2) { + self->irq = I2C2_EV_IRQn; + } + #endif + #ifdef I2C3 + if (I2Cx == I2C3) { + self->irq = I2C3_EV_IRQn; + } + #endif + #ifdef I2C4 + if (I2Cx == I2C4) { + self->irq = I2C4_EV_IRQn; + } + #endif +} + +STATIC void call_hal_irq(int i2c_num) { + //Create casted context pointer + busio_i2c_obj_t * context = (busio_i2c_obj_t*)MP_STATE_PORT(cpy_i2c_obj_all)[i2c_num - 1]; + if (context != NULL) { + HAL_NVIC_ClearPendingIRQ(context->irq); + HAL_I2C_EV_IRQHandler(&context->handle); + } +} + +void I2C1_EV_IRQHandler(void) { + call_hal_irq(1); +} +void I2C2_EV_IRQHandler(void) { + call_hal_irq(2); +} +void I2C3_EV_IRQHandler(void) { + call_hal_irq(3); +} +void I2C4_EV_IRQHandler(void) { + call_hal_irq(4); +} diff --git a/ports/stm/common-hal/busio/I2C.h b/ports/stm/common-hal/busio/I2C.h index 5ca2854eb8..687e6a8c4d 100644 --- a/ports/stm/common-hal/busio/I2C.h +++ b/ports/stm/common-hal/busio/I2C.h @@ -37,6 +37,8 @@ typedef struct { mp_obj_base_t base; I2C_HandleTypeDef handle; + IRQn_Type irq; + bool frame_in_prog; bool has_lock; const mcu_periph_obj_t *scl; const mcu_periph_obj_t *sda; diff --git a/ports/stm/mpconfigport.h b/ports/stm/mpconfigport.h index 7cdab04f62..3f64e6565b 100644 --- a/ports/stm/mpconfigport.h +++ b/ports/stm/mpconfigport.h @@ -52,10 +52,14 @@ extern uint8_t _ld_default_stack_size; #define BOARD_NO_VBUS_SENSE (0) #endif -#define MAX_UART 10 //how many UART are implemented +// Peripheral implementation counts +#define MAX_UART 10 +#define MAX_I2C 4 +#define MAX_SPI 6 #define MICROPY_PORT_ROOT_POINTERS \ void *cpy_uart_obj_all[MAX_UART]; \ + void *cpy_i2c_obj_all[MAX_I2C]; \ CIRCUITPY_COMMON_ROOT_POINTERS #endif // __INCLUDED_MPCONFIGPORT_H From edb7f2d807d8fef82d307964907a9763598a5344 Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Thu, 11 Feb 2021 16:30:27 -0500 Subject: [PATCH 2/2] Free up space for JA build --- ports/stm/boards/espruino_pico/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm/boards/espruino_pico/mpconfigboard.mk b/ports/stm/boards/espruino_pico/mpconfigboard.mk index 81c3772e72..6d45769f2b 100644 --- a/ports/stm/boards/espruino_pico/mpconfigboard.mk +++ b/ports/stm/boards/espruino_pico/mpconfigboard.mk @@ -21,5 +21,6 @@ LD_FILE = boards/STM32F401xd_fs.ld # meantime CIRCUITPY_ULAB = 0 CIRCUITPY_BUSDEVICE = 0 +CIRCUITPY_FRAMEBUFFERIO = 0 SUPEROPT_GC = 0