Fix I2C Repeated start error by converting to IT mode

This commit is contained in:
Lucian Copeland 2021-02-10 13:53:06 -05:00
parent 0c0b517112
commit d00bee2149
3 changed files with 97 additions and 3 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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