diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c index dd46c1855..14b3f84da 100644 --- a/os/hal/platforms/STM32/i2c_lld.c +++ b/os/hal/platforms/STM32/i2c_lld.c @@ -290,31 +290,6 @@ static void i2c_lld_set_opmode(I2CDriver *i2cp) { dp->CR1 = regCR1; } -/** - * @brief Return the last event value from I2C status registers. - * @details Important but implicit destination of this function is - * clearing interrupts flags. - * @note Internal use only. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -static uint32_t i2c_get_event(I2CDriver *i2cp) { - I2C_TypeDef *dp = i2cp->i2c; - uint16_t regSR1 = dp->SR1; - uint16_t regSR2 = dp->SR2; - -#if CH_DBG_ENABLE_ASSERTS - dbgSR1 = regSR1; - dbgSR2 = regSR2; - dbgCR1 = dp->CR1; - dbgCR2 = dp->CR2; -#endif /* CH_DBG_ENABLE_ASSERTS */ - - return (I2C_EV_MASK & (regSR1 | (regSR2 << 16))); -} - /** * @brief I2C shared ISR code. * @@ -324,11 +299,13 @@ static uint32_t i2c_get_event(I2CDriver *i2cp) { */ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { I2C_TypeDef *dp = i2cp->i2c; + uint32_t regSR = dp->SR2; + uint32_t event = dp->SR1; /* Interrupts are disabled just before dmaStreamEnable() because there is no need of interrupts until next transaction begin. All the work is done by the DMA.*/ - switch (i2c_get_event(i2cp)) { + switch (I2C_EV_MASK & (event | (regSR << 16))) { case I2C_EV5_MASTER_MODE_SELECT: dp->DR = i2cp->addr; break; @@ -336,6 +313,8 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { dp->CR2 &= ~I2C_CR2_ITEVTEN; dmaStreamEnable(i2cp->dmarx); dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */ + if (dmaStreamGetTransactionSize(i2cp->dmarx) < 2) + dp->CR1 &= ~I2C_CR1_ACK; break; case I2C_EV6_MASTER_TRA_MODE_SELECTED: dp->CR2 &= ~I2C_CR2_ITEVTEN; @@ -356,6 +335,9 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { default: break; } + /* Clear ADDR flag. */ + if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10)) + (void)dp->SR2; } /** @@ -786,7 +768,9 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, I2C_TypeDef *dp = i2cp->i2c; VirtualTimer vt; +#if defined(STM32F1XX) chDbgCheck((rxbytes > 1), "i2c_lld_master_receive_timeout"); +#endif /* Global timeout for the whole operation.*/ if (timeout != TIME_INFINITE) @@ -865,8 +849,10 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, I2C_TypeDef *dp = i2cp->i2c; VirtualTimer vt; +#if defined(STM32F1XX) chDbgCheck(((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))), "i2c_lld_master_transmit_timeout"); +#endif /* Global timeout for the whole operation.*/ if (timeout != TIME_INFINITE) diff --git a/readme.txt b/readme.txt index 46d4cc751..fed22d09f 100644 --- a/readme.txt +++ b/readme.txt @@ -101,6 +101,8 @@ - NEW: Validated CAN driver on STM32F2/F4. - Small fixes to the STM32F4 board files. - Various documentation fixes and improvements. +- NEW: I2C workaround allowing to read single byte on STM32 platforms + except F1x. *** 2.4.1 *** - FIX: Fixed inconsistent LPCxxx Internal RC oscillator names (bug 3524138).