embedded
protocol_error
ai_generated
true
I2C: clock stretch timeout on SCL line, slave holding clock low
ID: embedded/i2c-clock-stretch-timeout
79%Fix Rate
86%Confidence
1Evidence
2024-02-10First Seen
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| STM32Cube_FW_L4_V1.18.0 | active | — | — | — |
| IAR EWARM 9.40.1 | active | — | — | — |
| ARM GCC 10.3.1 | active | — | — | — |
| FreeRTOSv202212.01 | active | — | — | — |
Root Cause
I2C slave device stretches the clock (holds SCL low) beyond the master's timeout period, often due to slow internal processing or bus lock.
generic中文
I2C从设备拉伸时钟(保持SCL低电平)超过主设备超时周期,通常由内部处理缓慢或总线锁定引起。
Official Documentation
https://www.st.com/resource/en/application_note/dm00108059-i2c-timing-configuration-on-stm32-mcus-stmicroelectronics.pdfWorkarounds
-
82% success Increase I2C timeout in HAL_I2C_Master_Transmit(): set hi2c1.Init.Timing = 0x20C0E0FF; (for 100 kHz) and use HAL_I2C_Master_Transmit() with a timeout of 10000 ms instead of default 1000 ms.
Increase I2C timeout in HAL_I2C_Master_Transmit(): set hi2c1.Init.Timing = 0x20C0E0FF; (for 100 kHz) and use HAL_I2C_Master_Transmit() with a timeout of 10000 ms instead of default 1000 ms.
-
78% success Implement software reset of I2C peripheral after timeout: call HAL_I2C_DeInit(&hi2c1); HAL_I2C_Init(&hi2c1); then retry the transaction up to 3 times.
Implement software reset of I2C peripheral after timeout: call HAL_I2C_DeInit(&hi2c1); HAL_I2C_Init(&hi2c1); then retry the transaction up to 3 times.
-
85% success Use I2C recovery sequence: toggle SCL 9 times while SDA is high to release the slave: for(int i=0;i<9;i++) { HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET); delay_us(5); HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET); delay_us(5); }
Use I2C recovery sequence: toggle SCL 9 times while SDA is high to release the slave: for(int i=0;i<9;i++) { HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET); delay_us(5); HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET); delay_us(5); }
中文步骤
Increase I2C timeout in HAL_I2C_Master_Transmit(): set hi2c1.Init.Timing = 0x20C0E0FF; (for 100 kHz) and use HAL_I2C_Master_Transmit() with a timeout of 10000 ms instead of default 1000 ms.
Implement software reset of I2C peripheral after timeout: call HAL_I2C_DeInit(&hi2c1); HAL_I2C_Init(&hi2c1); then retry the transaction up to 3 times.
Use I2C recovery sequence: toggle SCL 9 times while SDA is high to release the slave: for(int i=0;i<9;i++) { HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_RESET); delay_us(5); HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, GPIO_PIN_SET); delay_us(5); }
Dead Ends
Common approaches that don't work:
-
Reducing I2C bus speed from 400 kHz to 100 kHz
80% fail
Slower speed may increase stretch duration, making timeout more likely.
-
Disabling clock stretching in the slave device configuration
90% fail
Many I2C slaves require clock stretching for proper operation; disabling it may cause data corruption.
-
Adding a hardware pull-up resistor on SCL line
85% fail
Pull-up resistors are already present; this does not address the slave holding the line low.