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
|
# meantime
|
||||||
CIRCUITPY_ULAB = 0
|
CIRCUITPY_ULAB = 0
|
||||||
CIRCUITPY_BUSDEVICE = 0
|
CIRCUITPY_BUSDEVICE = 0
|
||||||
|
CIRCUITPY_FRAMEBUFFERIO = 0
|
||||||
|
|
||||||
SUPEROPT_GC = 0
|
SUPEROPT_GC = 0
|
||||||
|
@ -61,6 +61,7 @@ STATIC bool never_reset_i2c[MAX_I2C];
|
|||||||
#define ALL_CLOCKS 0xFF
|
#define ALL_CLOCKS 0xFF
|
||||||
STATIC void i2c_clock_enable(uint8_t mask);
|
STATIC void i2c_clock_enable(uint8_t mask);
|
||||||
STATIC void i2c_clock_disable(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) {
|
void i2c_reset(void) {
|
||||||
uint16_t never_reset_mask = 0x00;
|
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));
|
i2c_clock_enable(1 << (self->sda->periph_index - 1));
|
||||||
reserved_i2c[self->sda->periph_index - 1] = true;
|
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
|
// Handle the HAL handle differences
|
||||||
#if (CPY_STM32H7 || CPY_STM32F7)
|
#if (CPY_STM32H7 || CPY_STM32F7)
|
||||||
if (frequency == 400000) {
|
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(sda);
|
||||||
common_hal_mcu_pin_claim(scl);
|
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) {
|
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,
|
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) {
|
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);
|
(uint8_t *)data, (uint16_t)len, 500);
|
||||||
|
}
|
||||||
return result == HAL_OK ? 0 : MP_EIO;
|
return result == HAL_OK ? 0 : MP_EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr,
|
uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr,
|
||||||
uint8_t *data, size_t len) {
|
uint8_t *data, size_t len) {
|
||||||
|
if (!self->frame_in_prog) {
|
||||||
return HAL_I2C_Master_Receive(&(self->handle), (uint16_t)(addr<<1), data, (uint16_t)len, 500)
|
return HAL_I2C_Master_Receive(&(self->handle), (uint16_t)(addr<<1), data, (uint16_t)len, 500)
|
||||||
== HAL_OK ? 0 : MP_EIO;
|
== 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) {
|
STATIC void i2c_clock_enable(uint8_t mask) {
|
||||||
@ -294,3 +337,48 @@ STATIC void i2c_clock_disable(uint8_t mask) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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 {
|
typedef struct {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
I2C_HandleTypeDef handle;
|
I2C_HandleTypeDef handle;
|
||||||
|
IRQn_Type irq;
|
||||||
|
bool frame_in_prog;
|
||||||
bool has_lock;
|
bool has_lock;
|
||||||
const mcu_periph_obj_t *scl;
|
const mcu_periph_obj_t *scl;
|
||||||
const mcu_periph_obj_t *sda;
|
const mcu_periph_obj_t *sda;
|
||||||
|
@ -52,10 +52,14 @@ extern uint8_t _ld_default_stack_size;
|
|||||||
#define BOARD_NO_VBUS_SENSE (0)
|
#define BOARD_NO_VBUS_SENSE (0)
|
||||||
#endif
|
#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 \
|
#define MICROPY_PORT_ROOT_POINTERS \
|
||||||
void *cpy_uart_obj_all[MAX_UART]; \
|
void *cpy_uart_obj_all[MAX_UART]; \
|
||||||
|
void *cpy_i2c_obj_all[MAX_I2C]; \
|
||||||
CIRCUITPY_COMMON_ROOT_POINTERS
|
CIRCUITPY_COMMON_ROOT_POINTERS
|
||||||
|
|
||||||
#endif // __INCLUDED_MPCONFIGPORT_H
|
#endif // __INCLUDED_MPCONFIGPORT_H
|
||||||
|
Loading…
Reference in New Issue
Block a user