drivers: i2c_ll_stm32_v2: Add timeout on transfer
When, due to EMC, a spike happens on the SCL line the driver stay in BUSY state. It could be reproduced by forcing the SCL temporarily to ground. It's probably a behavior relating to the operation of multi-master. By adding a timeout to the msg_read and msg_write function we can detect that something went wrong, and when that happens we force the end of communication. Signed-off-by: Julien D'Ascenzio <julien.dascenzio@paratronic.fr>
This commit is contained in:
parent
847ba43df9
commit
e1d22a0b61
|
@ -25,6 +25,8 @@ LOG_MODULE_REGISTER(i2c_ll_stm32_v2);
|
|||
|
||||
#include "i2c-priv.h"
|
||||
|
||||
#define STM32_I2C_TRANSFER_TIMEOUT_MSEC 500
|
||||
|
||||
static inline void msg_init(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *next_msg_flags, uint16_t slave,
|
||||
uint32_t transfer)
|
||||
|
@ -384,6 +386,7 @@ int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
|||
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
|
||||
struct i2c_stm32_data *data = DEV_DATA(dev);
|
||||
I2C_TypeDef *i2c = cfg->i2c;
|
||||
bool is_timeout = false;
|
||||
|
||||
data->current.len = msg->len;
|
||||
data->current.buf = msg->buf;
|
||||
|
@ -397,10 +400,15 @@ int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
|||
stm32_i2c_enable_transfer_interrupts(dev);
|
||||
LL_I2C_EnableIT_TX(i2c);
|
||||
|
||||
k_sem_take(&data->device_sync_sem, K_FOREVER);
|
||||
if (k_sem_take(&data->device_sync_sem,
|
||||
K_MSEC(STM32_I2C_TRANSFER_TIMEOUT_MSEC)) != 0) {
|
||||
stm32_i2c_master_mode_end(dev);
|
||||
k_sem_take(&data->device_sync_sem, K_FOREVER);
|
||||
is_timeout = true;
|
||||
}
|
||||
|
||||
if (data->current.is_nack || data->current.is_err ||
|
||||
data->current.is_arlo) {
|
||||
data->current.is_arlo || is_timeout) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -423,6 +431,10 @@ error:
|
|||
data->current.is_err = 0U;
|
||||
}
|
||||
|
||||
if (is_timeout) {
|
||||
LOG_DBG("%s: TIMEOUT", __func__);
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -432,6 +444,7 @@ int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
|||
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
|
||||
struct i2c_stm32_data *data = DEV_DATA(dev);
|
||||
I2C_TypeDef *i2c = cfg->i2c;
|
||||
bool is_timeout = false;
|
||||
|
||||
data->current.len = msg->len;
|
||||
data->current.buf = msg->buf;
|
||||
|
@ -446,10 +459,15 @@ int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
|||
stm32_i2c_enable_transfer_interrupts(dev);
|
||||
LL_I2C_EnableIT_RX(i2c);
|
||||
|
||||
k_sem_take(&data->device_sync_sem, K_FOREVER);
|
||||
if (k_sem_take(&data->device_sync_sem,
|
||||
K_MSEC(STM32_I2C_TRANSFER_TIMEOUT_MSEC)) != 0) {
|
||||
stm32_i2c_master_mode_end(dev);
|
||||
k_sem_take(&data->device_sync_sem, K_FOREVER);
|
||||
is_timeout = true;
|
||||
}
|
||||
|
||||
if (data->current.is_nack || data->current.is_err ||
|
||||
data->current.is_arlo) {
|
||||
data->current.is_arlo || is_timeout) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -472,6 +490,10 @@ error:
|
|||
data->current.is_err = 0U;
|
||||
}
|
||||
|
||||
if (is_timeout) {
|
||||
LOG_DBG("%s: TIMEOUT", __func__);
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue