-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Open
Labels
bugThe issue is a bug, or the PR is fixing a bugThe issue is a bug, or the PR is fixing a bugplatform: STM32ST Micro STM32ST Micro STM32
Description
Bug description
On STM32 I²C v2 in multi-master setups (device configured for both master + target), the Zephyr driver sets data->master_active = true in msg_init() before issuing a START and before the bus is confirmed idle. If the bus is still BUSY (e.g., peer master performs immediate repeated-STARTs), target IRQ handling is suppressed by the slave_attached && !master_active check; the local device fails to ACK as a target, the peer stalls with BUSY held, and our master side spins waiting for idle → deadlock / bus hang.
File: drivers/i2c/i2c_ll_stm32_v2.c
Function: msg_init()
Bug Fix:
#define STM32_I2C_ARLO_TIMEOUT_USEC 2000
static inline int wait_bus_idle(const struct device *dev, uint32_t timeout_us)
{
const struct i2c_stm32_config *cfg = dev->config;
I2C_TypeDef *i2c = cfg->i2c;
uint32_t start = k_cycle_get_32();
/* Wait for BUSY=0 (bus idle) */
while (LL_I2C_IsActiveFlag_BUSY(i2c)) {
if (k_cyc_to_us_near32(k_cycle_get_32() - start) > timeout_us) {
return -EBUSY;
}
}
return 0;
}
static inline void msg_init(const struct device *dev, struct i2c_msg *msg,
uint8_t *next_msg_flags, uint16_t slave,
uint32_t transfer)
{
const struct i2c_stm32_config *cfg = dev->config;
struct i2c_stm32_data *data = dev->data;
I2C_TypeDef *i2c = cfg->i2c;
if (LL_I2C_IsEnabledReloadMode(i2c)) {
LL_I2C_SetTransferSize(i2c, msg->len);
} else {
if (I2C_ADDR_10_BITS & data->dev_config) {
LL_I2C_SetMasterAddressingMode(i2c,
LL_I2C_ADDRESSING_MODE_10BIT);
LL_I2C_SetSlaveAddr(i2c, (uint32_t) slave);
} else {
LL_I2C_SetMasterAddressingMode(i2c,
LL_I2C_ADDRESSING_MODE_7BIT);
LL_I2C_SetSlaveAddr(i2c, (uint32_t) slave << 1);
}
if (!(msg->flags & I2C_MSG_STOP) && next_msg_flags &&
!(*next_msg_flags & I2C_MSG_RESTART)) {
LL_I2C_EnableReloadMode(i2c);
} else {
LL_I2C_DisableReloadMode(i2c);
}
LL_I2C_DisableAutoEndMode(i2c);
LL_I2C_SetTransferRequest(i2c, transfer);
LL_I2C_SetTransferSize(i2c, msg->len);
LL_I2C_Enable(i2c);
/*wait for real bus idle BEFORE declaring master_active */
if (wait_bus_idle(dev, STM32_I2C_ARLO_TIMEOUT_USEC) != 0) {
/* Make sure we do NOT look like a master while we back out */
#if defined(CONFIG_I2C_TARGET)
data->master_active = false;
#endif
return;
}
#if defined(CONFIG_I2C_TARGET)
data->master_active = true; /* <<< set only now */
#endif
LL_I2C_GenerateStartCondition(i2c);
}
}
Regression
- This is a regression.
Steps to reproduce
No response
Relevant log output
Impact
Showstopper – Prevents release or major functionality; system unusable.
Environment
Zephyr SDK, STM32
Additional Context
No response
Metadata
Metadata
Assignees
Labels
bugThe issue is a bug, or the PR is fixing a bugThe issue is a bug, or the PR is fixing a bugplatform: STM32ST Micro STM32ST Micro STM32