diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c index 9927016a7..40732c122 100644 --- a/os/hal/platforms/STM32/i2c_lld.c +++ b/os/hal/platforms/STM32/i2c_lld.c @@ -305,16 +305,21 @@ static uint32_t i2c_get_event(I2CDriver *i2cp) { */ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { + /* Interrupts disabled just before dmaStreamEnable() because there is no + * need of interrupts until next transaction begin. All work + * will be done by DMA. */ + switch (i2c_get_event(i2cp)) { case I2C_EV5_MASTER_MODE_SELECT: i2cp->i2c->DR = i2cp->addr; break; case I2C_EV6_MASTER_REC_MODE_SELECTED: + i2cp->i2c->CR2 &= ~I2C_CR2_ITEVTEN; dmaStreamEnable(i2cp->dmarx); - /* LAST bit needs only during receive phase. */ - i2cp->i2c->CR2 |= I2C_CR2_LAST; + i2cp->i2c->CR2 |= I2C_CR2_LAST; /* need in receiver mode */ break; case I2C_EV6_MASTER_TRA_MODE_SELECTED: + i2cp->i2c->CR2 &= ~I2C_CR2_ITEVTEN; dmaStreamEnable(i2cp->dmatx); break; case I2C_EV8_2_MASTER_BYTE_TRANSMITTED: @@ -356,7 +361,7 @@ static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp, uint32_t flags) { dmaStreamDisable(i2cp->dmarx); dmaStreamClearInterrupt(i2cp->dmarx); - i2cp->i2c->CR2 &= ~(I2C_CR2_LAST | I2C_CR2_ITEVTEN); + i2cp->i2c->CR2 &= ~I2C_CR2_LAST; i2cp->i2c->CR1 &= ~I2C_CR1_ACK; i2cp->i2c->CR1 |= I2C_CR1_STOP; wakeup_isr(i2cp, RDY_OK); @@ -382,6 +387,10 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) { dmaStreamDisable(i2cp->dmatx); dmaStreamClearInterrupt(i2cp->dmatx); + /* Enable interrupts to catch BTF event meaning transmission part complete. + * Interrupt handler will decide to generate STOP or to begin receiving part + * of rw transaction itself. */ + i2cp->i2c->CR2 |= I2C_CR2_ITEVTEN; } /**