summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucian Copeland <hierophect@gmail.com>2021-02-18 15:19:00 -0500
committerGitHub <noreply@github.com>2021-02-18 15:19:00 -0500
commit0ecb24c3e56c64c11265611ec174950b18fce8bf (patch)
tree49e23794ef16c43c763a38d85aa59157543093ea
parente29178cf94f981f068a88f3b11de163351c7f020 (diff)
parentedb7f2d807d8fef82d307964907a9763598a5344 (diff)
Merge pull request #4169 from hierophect/stm32-i2cstart
STM32: Fix I2C repeated start by converting to IT mode
-rw-r--r--ports/stm/boards/espruino_pico/mpconfigboard.mk1
-rw-r--r--ports/stm/common-hal/busio/I2C.c92
-rw-r--r--ports/stm/common-hal/busio/I2C.h2
-rw-r--r--ports/stm/mpconfigport.h6
4 files changed, 98 insertions, 3 deletions
diff --git a/ports/stm/boards/espruino_pico/mpconfigboard.mk b/ports/stm/boards/espruino_pico/mpconfigboard.mk
index 81c3772e7..6d45769f2 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
diff --git a/ports/stm/common-hal/busio/I2C.c b/ports/stm/common-hal/busio/I2C.c
index de69da211..7726b5e87 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 5ca2854eb..687e6a8c4 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 7cdab04f6..3f64e6565 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