diff --git a/os/hal/include/i2c.h b/os/hal/include/i2c.h index 15d40808c..00b412ec1 100644 --- a/os/hal/include/i2c.h +++ b/os/hal/include/i2c.h @@ -109,7 +109,7 @@ typedef enum { */ #define i2cMasterTransmit(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes) \ (i2cMasterTransmitTimeout(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes, \ - TIME_INFINITE)) + TIME_INFINITE)) /** * @brief Wrap i2cMasterReceiveTimeout function with TIME_INFINITE timeout. diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c index 012db52b9..fee18ab71 100644 --- a/os/hal/platforms/STM32/i2c_lld.c +++ b/os/hal/platforms/STM32/i2c_lld.c @@ -173,9 +173,11 @@ static void i2c_lld_safety_timeout(void *p) { I2CDriver *i2cp = (I2CDriver *)p; if (i2cp->thread) { + Thread *tp = i2cp->thread; i2c_lld_abort_operation(i2cp); - i2cp->thread->p_u.rdymsg = RDY_TIMEOUT; - chSchReadyI(i2cp->thread); + i2cp->thread = NULL; + tp->p_u.rdymsg = RDY_TIMEOUT; + chSchReadyI(tp); } } @@ -773,12 +775,12 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, systime_t timeout) { I2C_TypeDef *dp = i2cp->i2c; VirtualTimer vt; - msg_t rdymsg; chDbgCheck((rxbytes > 1), "i2c_lld_master_receive_timeout"); /* Global timeout for the whole operation.*/ - chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); + if (timeout != TIME_INFINITE) + chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); /* Releases the lock from high level driver.*/ chSysUnlock(); @@ -794,10 +796,10 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Waits until BUSY flag is reset and the STOP from the previous operation is completed, alternatively for a timeout condition.*/ while ((dp->SR2 & I2C_SR2_BUSY) || (dp->CR1 & I2C_CR1_STOP)) { - if (!chVTIsArmedI(&vt)) { - chSysLock(); + chSysLock(); + if (!chVTIsArmedI(&vt)) return RDY_TIMEOUT; - } + chSysUnlock(); } /* This lock will be released in high level driver.*/ @@ -815,11 +817,10 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Waits for the operation completion or a timeout.*/ i2cp->thread = chThdSelf(); chSchGoSleepS(THD_STATE_SUSPENDED); - rdymsg = chThdSelf()->p_u.rdymsg; - if (rdymsg != RDY_TIMEOUT) + if (chVTIsArmedI(&vt)) chVTResetI(&vt); - return rdymsg; + return chThdSelf()->p_u.rdymsg; } /** @@ -853,13 +854,13 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, systime_t timeout) { I2C_TypeDef *dp = i2cp->i2c; VirtualTimer vt; - msg_t rdymsg; chDbgCheck(((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))), "i2c_lld_master_transmit_timeout"); /* Global timeout for the whole operation.*/ - chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); + if (timeout != TIME_INFINITE) + chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); /* Releases the lock from high level driver.*/ chSysUnlock(); @@ -879,10 +880,10 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Waits until BUSY flag is reset and the STOP from the previous operation is completed, alternatively for a timeout condition.*/ while ((dp->SR2 & I2C_SR2_BUSY) || (dp->CR1 & I2C_CR1_STOP)) { - if (!chVTIsArmedI(&vt)) { - chSysLock(); + chSysLock(); + if (!chVTIsArmedI(&vt)) return RDY_TIMEOUT; - } + chSysUnlock(); } /* This lock will be released in high level driver.*/ @@ -900,11 +901,10 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Waits for the operation completion or a timeout.*/ i2cp->thread = chThdSelf(); chSchGoSleepS(THD_STATE_SUSPENDED); - rdymsg = chThdSelf()->p_u.rdymsg; - if (rdymsg != RDY_TIMEOUT) + if (chVTIsArmedI(&vt)) chVTResetI(&vt); - return rdymsg; + return chThdSelf()->p_u.rdymsg; } #endif /* HAL_USE_I2C */ diff --git a/readme.txt b/readme.txt index e872da4fb..272757e79 100644 --- a/readme.txt +++ b/readme.txt @@ -79,6 +79,7 @@ ***************************************************************************** *** 2.4.2 *** +- FIX: Fixed timeout related race condition in STM32 I2C driver (bug 3530043). - FIX: Fixed wrong macro check in STM32 MAC driver (bug 3527179). - FIX: Fixed error in STM32L-Discovery board.h file (bug 3526918).