drivers: i2c_nrfx_twi: Add recover when I2C transfer timeout

Previously to this commit, nothing was done to restore the bus to an
healthy level.
However, I2C devices sometimes needs help to recover from an aborted
transaction.
Therefore, we now add a call to nrfx_{twi, twim}_bus_recover().

Signed-off-by: Xavier Chapron <xavier.chapron@stimio.fr>
This commit is contained in:
Xavier Chapron 2020-12-08 14:11:10 +01:00 committed by Kumar Gala
commit e845878870
2 changed files with 26 additions and 8 deletions

View file

@ -114,16 +114,25 @@ static int i2c_nrfx_twi_transfer(const struct device *dev,
I2C_TRANSFER_TIMEOUT_MSEC); I2C_TRANSFER_TIMEOUT_MSEC);
if (ret != 0) { if (ret != 0) {
/* Whatever the frequency, completion_sync should have /* Whatever the frequency, completion_sync should have
* been give by the event handler. * been given by the event handler.
* *
* If it hasn't it's probably due to an hardware issue * If it hasn't, it's probably due to an hardware issue
* on the I2C line, for example a short between SDA and * on the I2C line, for example a short between SDA and
* GND. * GND.
* This is issue has also been when trying to use the
* I2C bus during MCU internal flash erase.
* *
* Note to fully recover from this issue one should * In many situation, a retry is sufficient.
* reinit nrfx twi. * However, some time the I2C device get stuck and need
* help to recover.
* Therefore we always call nrfx_twi_bus_recover() to
* make sure everything has been done to restore the
* bus from this error.
*/ */
LOG_ERR("Error on I2C line occurred for message %d", i); LOG_ERR("Error on I2C line occurred for message %d", i);
nrfx_twi_disable(&get_dev_config(dev)->twi);
nrfx_twi_bus_recover(get_dev_config(dev)->config.scl,
get_dev_config(dev)->config.sda);
ret = -EIO; ret = -EIO;
break; break;
} }

View file

@ -131,16 +131,25 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
I2C_TRANSFER_TIMEOUT_MSEC); I2C_TRANSFER_TIMEOUT_MSEC);
if (ret != 0) { if (ret != 0) {
/* Whatever the frequency, completion_sync should have /* Whatever the frequency, completion_sync should have
* been give by the event handler. * been given by the event handler.
* *
* If it hasn't it's probably due to an hardware issue * If it hasn't, it's probably due to an hardware issue
* on the I2C line, for example a short between SDA and * on the I2C line, for example a short between SDA and
* GND. * GND.
* This is issue has also been when trying to use the
* I2C bus during MCU internal flash erase.
* *
* Note to fully recover from this issue one should * In many situation, a retry is sufficient.
* reinit nrfx twim. * However, some time the I2C device get stuck and need
* help to recover.
* Therefore we always call nrfx_twim_bus_recover() to
* make sure everything has been done to restore the
* bus from this error.
*/ */
LOG_ERR("Error on I2C line occurred for message %d", i); LOG_ERR("Error on I2C line occurred for message %d", i);
nrfx_twim_disable(&get_dev_config(dev)->twim);
nrfx_twim_bus_recover(get_dev_config(dev)->config.scl,
get_dev_config(dev)->config.sda);
ret = -EIO; ret = -EIO;
break; break;
} }