Skip to content

Commit 2066b8c

Browse files
Jean Nanchenfabiobaltieri
authored andcommitted
drivers: i2c: stm32: add timeout to avoid infinite loop
Fix issue where STM32 I2C LL driver could block forever when SDA and SCL are shorted and interrupts are disabled (CONFIG_I2C_STM32_INTERRUPT=n). Added timeouts to all blocking wait loops in the STM32 LL I2C driver to avoid indefinite blocking. Fixes #88506 Signed-off-by: Jean Nanchen <jean.nanchen@hevs.ch>
1 parent b513e08 commit 2066b8c

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

drivers/i2c/i2c_ll_stm32_v2.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,17 +866,26 @@ static inline int msg_done(const struct device *dev,
866866
{
867867
const struct i2c_stm32_config *cfg = dev->config;
868868
I2C_TypeDef *i2c = cfg->i2c;
869+
int64_t start_time = k_uptime_get();
869870

870871
/* Wait for transfer to complete */
871872
while (!LL_I2C_IsActiveFlag_TC(i2c) && !LL_I2C_IsActiveFlag_TCR(i2c)) {
872873
if (check_errors(dev, __func__)) {
873874
return -EIO;
874875
}
876+
if ((k_uptime_get() - start_time) >
877+
STM32_I2C_TRANSFER_TIMEOUT_MSEC) {
878+
return -ETIMEDOUT;
879+
}
875880
}
876881
/* Issue stop condition if necessary */
877882
if (current_msg_flags & I2C_MSG_STOP) {
878883
LL_I2C_GenerateStopCondition(i2c);
879884
while (!LL_I2C_IsActiveFlag_STOP(i2c)) {
885+
if ((k_uptime_get() - start_time) >
886+
STM32_I2C_TRANSFER_TIMEOUT_MSEC) {
887+
return -ETIMEDOUT;
888+
}
880889
}
881890

882891
LL_I2C_ClearFlag_STOP(i2c);
@@ -893,6 +902,7 @@ static int i2c_stm32_msg_write(const struct device *dev, struct i2c_msg *msg,
893902
I2C_TypeDef *i2c = cfg->i2c;
894903
unsigned int len = 0U;
895904
uint8_t *buf = msg->buf;
905+
int64_t start_time = k_uptime_get();
896906

897907
msg_init(dev, msg, next_msg_flags, slave, LL_I2C_REQUEST_WRITE);
898908

@@ -906,6 +916,11 @@ static int i2c_stm32_msg_write(const struct device *dev, struct i2c_msg *msg,
906916
if (check_errors(dev, __func__)) {
907917
return -EIO;
908918
}
919+
920+
if ((k_uptime_get() - start_time) >
921+
STM32_I2C_TRANSFER_TIMEOUT_MSEC) {
922+
return -ETIMEDOUT;
923+
}
909924
}
910925

911926
LL_I2C_TransmitData8(i2c, *buf);
@@ -923,6 +938,7 @@ static int i2c_stm32_msg_read(const struct device *dev, struct i2c_msg *msg,
923938
I2C_TypeDef *i2c = cfg->i2c;
924939
unsigned int len = 0U;
925940
uint8_t *buf = msg->buf;
941+
int64_t start_time = k_uptime_get();
926942

927943
msg_init(dev, msg, next_msg_flags, slave, LL_I2C_REQUEST_READ);
928944

@@ -932,6 +948,10 @@ static int i2c_stm32_msg_read(const struct device *dev, struct i2c_msg *msg,
932948
if (check_errors(dev, __func__)) {
933949
return -EIO;
934950
}
951+
if ((k_uptime_get() - start_time) >
952+
STM32_I2C_TRANSFER_TIMEOUT_MSEC) {
953+
return -ETIMEDOUT;
954+
}
935955
}
936956

937957
*buf = LL_I2C_ReceiveData8(i2c);
@@ -1302,5 +1322,26 @@ int i2c_stm32_transaction(const struct device *dev,
13021322
msg.len = rest;
13031323
} while (rest > 0U);
13041324

1325+
#ifndef CONFIG_I2C_STM32_INTERRUPT
1326+
struct i2c_stm32_data *data = dev->data;
1327+
1328+
if (ret == -ETIMEDOUT) {
1329+
if (LL_I2C_IsEnabledReloadMode(i2c)) {
1330+
LL_I2C_DisableReloadMode(i2c);
1331+
}
1332+
#if defined(CONFIG_I2C_TARGET)
1333+
data->master_active = false;
1334+
if (!data->slave_attached && !data->smbalert_active) {
1335+
LL_I2C_Disable(i2c);
1336+
}
1337+
#else
1338+
if (!data->smbalert_active) {
1339+
LL_I2C_Disable(i2c);
1340+
}
1341+
#endif
1342+
return -EIO;
1343+
}
1344+
#endif /* !CONFIG_I2C_STM32_INTERRUPT */
1345+
13051346
return ret;
13061347
}

0 commit comments

Comments
 (0)