Merge pull request #4169 from hierophect/stm32-i2cstart
STM32: Fix I2C repeated start by converting to IT mode
This commit is contained in:
commit
0ecb24c3e5
@ -21,5 +21,6 @@ LD_FILE = boards/STM32F401xd_fs.ld
|
||||
# meantime
|
||||
CIRCUITPY_ULAB = 0
|
||||
CIRCUITPY_BUSDEVICE = 0
|
||||
CIRCUITPY_FRAMEBUFFERIO = 0
|
||||
|
||||
SUPEROPT_GC = 0
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user