Skip to content

Commit 0ecb24c

Browse files
authored
Merge pull request #4169 from hierophect/stm32-i2cstart
STM32: Fix I2C repeated start by converting to IT mode
2 parents e29178c + edb7f2d commit 0ecb24c

File tree

4 files changed

+98
-3
lines changed

4 files changed

+98
-3
lines changed

ports/stm/boards/espruino_pico/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ LD_FILE = boards/STM32F401xd_fs.ld
2121
# meantime
2222
CIRCUITPY_ULAB = 0
2323
CIRCUITPY_BUSDEVICE = 0
24+
CIRCUITPY_FRAMEBUFFERIO = 0
2425

2526
SUPEROPT_GC = 0

ports/stm/common-hal/busio/I2C.c

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ STATIC bool never_reset_i2c[MAX_I2C];
6161
#define ALL_CLOCKS 0xFF
6262
STATIC void i2c_clock_enable(uint8_t mask);
6363
STATIC void i2c_clock_disable(uint8_t mask);
64+
STATIC void i2c_assign_irq(busio_i2c_obj_t *self, I2C_TypeDef * I2Cx);
6465

6566
void i2c_reset(void) {
6667
uint16_t never_reset_mask = 0x00;
@@ -136,6 +137,10 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
136137
i2c_clock_enable(1 << (self->sda->periph_index - 1));
137138
reserved_i2c[self->sda->periph_index - 1] = true;
138139

140+
// Create root pointer and assign IRQ
141+
MP_STATE_PORT(cpy_i2c_obj_all)[self->sda->periph_index - 1] = self;
142+
i2c_assign_irq(self, I2Cx);
143+
139144
// Handle the HAL handle differences
140145
#if (CPY_STM32H7 || CPY_STM32F7)
141146
if (frequency == 400000) {
@@ -163,6 +168,13 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
163168
}
164169
common_hal_mcu_pin_claim(sda);
165170
common_hal_mcu_pin_claim(scl);
171+
172+
self->frame_in_prog = false;
173+
174+
//start the receive interrupt chain
175+
HAL_NVIC_DisableIRQ(self->irq); //prevent handle lock contention
176+
HAL_NVIC_SetPriority(self->irq, 1, 0);
177+
HAL_NVIC_EnableIRQ(self->irq);
166178
}
167179

168180
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) {
229241

230242
uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr,
231243
const uint8_t *data, size_t len, bool transmit_stop_bit) {
232-
HAL_StatusTypeDef result = HAL_I2C_Master_Transmit(&(self->handle), (uint16_t)(addr << 1),
244+
HAL_StatusTypeDef result;
245+
if (!transmit_stop_bit) {
246+
uint32_t xfer_opt;
247+
if (!self->frame_in_prog) {
248+
xfer_opt = I2C_FIRST_FRAME;
249+
} else {
250+
// handle rare possibility of multiple restart writes in a row
251+
xfer_opt = I2C_NEXT_FRAME;
252+
}
253+
result = HAL_I2C_Master_Seq_Transmit_IT(&(self->handle),
254+
(uint16_t)(addr << 1), (uint8_t *)data,
255+
(uint16_t)len, xfer_opt);
256+
while (HAL_I2C_GetState(&(self->handle)) != HAL_I2C_STATE_READY)
257+
{
258+
RUN_BACKGROUND_TASKS;
259+
}
260+
self->frame_in_prog = true;
261+
} else {
262+
result = HAL_I2C_Master_Transmit(&(self->handle), (uint16_t)(addr << 1),
233263
(uint8_t *)data, (uint16_t)len, 500);
264+
}
234265
return result == HAL_OK ? 0 : MP_EIO;
235266
}
236267

237268
uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr,
238269
uint8_t *data, size_t len) {
239-
return HAL_I2C_Master_Receive(&(self->handle), (uint16_t)(addr<<1), data, (uint16_t)len, 500)
270+
if (!self->frame_in_prog) {
271+
return HAL_I2C_Master_Receive(&(self->handle), (uint16_t)(addr<<1), data, (uint16_t)len, 500)
240272
== HAL_OK ? 0 : MP_EIO;
273+
} else {
274+
HAL_StatusTypeDef result = HAL_I2C_Master_Seq_Receive_IT(&(self->handle),
275+
(uint16_t)(addr << 1), (uint8_t *)data,
276+
(uint16_t)len, I2C_LAST_FRAME);
277+
while (HAL_I2C_GetState(&(self->handle)) != HAL_I2C_STATE_READY)
278+
{
279+
RUN_BACKGROUND_TASKS;
280+
}
281+
self->frame_in_prog = false;
282+
return result;
283+
}
241284
}
242285

243286
STATIC void i2c_clock_enable(uint8_t mask) {
@@ -294,3 +337,48 @@ STATIC void i2c_clock_disable(uint8_t mask) {
294337
}
295338
#endif
296339
}
340+
341+
STATIC void i2c_assign_irq(busio_i2c_obj_t *self, I2C_TypeDef * I2Cx) {
342+
#ifdef I2C1
343+
if (I2Cx == I2C1) {
344+
self->irq = I2C1_EV_IRQn;
345+
}
346+
#endif
347+
#ifdef I2C2
348+
if (I2Cx == I2C2) {
349+
self->irq = I2C2_EV_IRQn;
350+
}
351+
#endif
352+
#ifdef I2C3
353+
if (I2Cx == I2C3) {
354+
self->irq = I2C3_EV_IRQn;
355+
}
356+
#endif
357+
#ifdef I2C4
358+
if (I2Cx == I2C4) {
359+
self->irq = I2C4_EV_IRQn;
360+
}
361+
#endif
362+
}
363+
364+
STATIC void call_hal_irq(int i2c_num) {
365+
//Create casted context pointer
366+
busio_i2c_obj_t * context = (busio_i2c_obj_t*)MP_STATE_PORT(cpy_i2c_obj_all)[i2c_num - 1];
367+
if (context != NULL) {
368+
HAL_NVIC_ClearPendingIRQ(context->irq);
369+
HAL_I2C_EV_IRQHandler(&context->handle);
370+
}
371+
}
372+
373+
void I2C1_EV_IRQHandler(void) {
374+
call_hal_irq(1);
375+
}
376+
void I2C2_EV_IRQHandler(void) {
377+
call_hal_irq(2);
378+
}
379+
void I2C3_EV_IRQHandler(void) {
380+
call_hal_irq(3);
381+
}
382+
void I2C4_EV_IRQHandler(void) {
383+
call_hal_irq(4);
384+
}

ports/stm/common-hal/busio/I2C.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
typedef struct {
3838
mp_obj_base_t base;
3939
I2C_HandleTypeDef handle;
40+
IRQn_Type irq;
41+
bool frame_in_prog;
4042
bool has_lock;
4143
const mcu_periph_obj_t *scl;
4244
const mcu_periph_obj_t *sda;

ports/stm/mpconfigport.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,14 @@ extern uint8_t _ld_default_stack_size;
5252
#define BOARD_NO_VBUS_SENSE (0)
5353
#endif
5454

55-
#define MAX_UART 10 //how many UART are implemented
55+
// Peripheral implementation counts
56+
#define MAX_UART 10
57+
#define MAX_I2C 4
58+
#define MAX_SPI 6
5659

5760
#define MICROPY_PORT_ROOT_POINTERS \
5861
void *cpy_uart_obj_all[MAX_UART]; \
62+
void *cpy_i2c_obj_all[MAX_I2C]; \
5963
CIRCUITPY_COMMON_ROOT_POINTERS
6064

6165
#endif // __INCLUDED_MPCONFIGPORT_H

0 commit comments

Comments
 (0)