Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STM32: Fix I2C repeated start by converting to IT mode #4169

Merged
merged 3 commits into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 90 additions & 2 deletions ports/stm/common-hal/busio/I2C.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
2 changes: 2 additions & 0 deletions ports/stm/common-hal/busio/I2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion ports/stm/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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