arch/arm/src/lpc17xx_40xx/lpc17_40_i2c.c: Cancel timeout on i2c stop
Not canceling the I2C timeout watch dog immediately after finishing all I2C transactions in interrupt context can lead to a race condition due to nxsem_wait(&priv->wait) in lpc17_40_i2c_start() not resuming execution fast enough (this can be easily triggered if another task / thread is using a lot of cpu time). Falling to cancel the watchdog up to time will cause the priv->wait semaphore to be incremented twice (first by lpc17_40_i2c_stop() then by lpc17_40_i2c_timeout()), so all I2C transactions after that will return immediately and priv->msgs will hold pointers to memory it doesn't own anymore. Canceling the priv->timeout watch dog in lpc17_40_i2c_stop() prevents this as it is executed from the I2C interrupt handler. arch/arm/src/lpc17xx_40xx/lpc17_40_i2c.c: Fix timeout calculation For each byte received / transmitted, an acknowledge bit is also transmitted / received, requiring effectively 9 bits for each byte.
This commit is contained in:
parent
3b53cd1e57
commit
0be87af99d
1 changed files with 2 additions and 3 deletions
|
|
@ -232,7 +232,7 @@ static int lpc17_40_i2c_start(struct lpc17_40_i2cdev_s *priv)
|
|||
|
||||
/* Calculate the approximate timeout */
|
||||
|
||||
timeout = ((total_len * (8000000 / CONFIG_USEC_PER_TICK)) / freq) + 1;
|
||||
timeout = ((total_len * (9000000 / CONFIG_USEC_PER_TICK)) / freq) + 1;
|
||||
|
||||
/* Initializes the I2C state machine to a known value */
|
||||
|
||||
|
|
@ -242,8 +242,6 @@ static int lpc17_40_i2c_start(struct lpc17_40_i2cdev_s *priv)
|
|||
(uint32_t)priv);
|
||||
nxsem_wait(&priv->wait);
|
||||
|
||||
wd_cancel(priv->timeout);
|
||||
|
||||
return priv->nmsg;
|
||||
}
|
||||
|
||||
|
|
@ -263,6 +261,7 @@ static void lpc17_40_i2c_stop(struct lpc17_40_i2cdev_s *priv)
|
|||
priv->base + LPC17_40_I2C_CONSET_OFFSET);
|
||||
}
|
||||
|
||||
wd_cancel(priv->timeout);
|
||||
nxsem_post(&priv->wait);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue