dakejahl opened a new pull request, #19703:
URL: https://github.com/apache/nuttx/pull/19703
## Summary
`stm32_i2c_init()` and `stm32_i2c_deinit()` hardcode `STM32_RCC_APB1LENR` /
`STM32_RCC_APB1LRSTR` while taking the enable and reset bits from the
per-instance `struct stm32_i2c_config_s`. That is correct for I2C1-3, but I2C4
is on APB4: its bits are `RCC_APB4ENR_I2C4EN` and `RCC_APB4RSTR_I2C4RST`, both
bit 7 — and bit 7 of `APB1LENR` / `APB1LRSTR` is TIM13.
So on I2C4 the driver has been enabling TIM13's clock, pulsing TIM13's
reset, and never resetting the I2C4 peripheral at all; on deinit it gates TIM13
and leaves the I2C4 clock running. This dates back to the original H7 I2C
driver in af8a002a10.
Register map, cross-checked against the ST CMSIS device headers (identical
in stm32h743xx.h, stm32h755xx.h, stm32h723xx.h, stm32h7a3xx.h and
stm32h7b3xx.h):
| register | offset | I2C bit | conflicting bit |
| --- | --- | --- | --- |
| `RCC_APB1LENR` / `RCC_APB1LRSTR` | 0x0e8 / 0x090 | I2C1-3 = 21/22/23 | bit
7 = TIM13 |
| `RCC_APB4ENR` / `RCC_APB4RSTR` | 0x0f4 / 0x09c | I2C4 = 7 | — |
This patch stores the clock-enable and reset register addresses in the
per-instance config next to the bits, and uses them.
## Impact
STM32H7 boards with I2C4 enabled.
I2C4 still enumerates and transfers today, because `rcc_enableapb4()` sets
`I2C4EN` unconditionally at boot — which is likely why this went unnoticed.
What is actually broken:
- `stm32_i2c_reset()` (`CONFIG_I2C_RESET`) never resets the I2C4 peripheral.
Its recovery sequence is deinit → bit-bang SCL to release a stuck slave →
re-init, where the re-init's peripheral reset is what clears a latched I2C
state machine. On I2C4 only the slave side is recovered, so a wedged I2C4
peripheral stays wedged.
- `stm32_i2c_deinit()` leaves the I2C4 clock enabled and gates TIM13 instead.
- TIM13's clock is enabled and its registers are reset whenever an I2C4 bus
is initialized. Harmless where TIM13 is unused, but it will clobber a TIM13
already in use (e.g. driving PWM) if I2C4 is brought up later in boot.
No functional change for I2C1-3. No API, configuration, or board-level
change — the two added fields are internal to the driver.
## Testing
Host: Ubuntu 24.04, arm-none-eabi-gcc 13.2.1 (15:13.2.rel1-2)
**`stm32h745i-disco:nsh`** (STM32H745, in-tree), with `CONFIG_STM32_I2C4=y`
and `CONFIG_I2C_RESET=y` added — builds clean, and the compiled I2C4 config now
carries the APB4 registers:
```
$ arm-none-eabi-objdump -s -j .rodata.stm32_i2c4_config
arch/arm/src/stm32_i2c.o
0000 001c0058 f4440258 80000000 9c440258 ...X.D.X.....D.X
0010 80000000 3c4a0800 3d4a0800 6f000000 ....<J..=J..o...
0020 70000000 p...
```
which decodes as base `0x58001c00` (I2C4), clk_reg `0x580244f4`
(`RCC_APB4ENR`), clk_bit `0x80`, rst_reg `0x5802449c` (`RCC_APB4RSTR`),
reset_bit `0x80`. Before this patch the driver wrote `0x580244e8` (`APB1LENR`)
and `0x58024490` (`APB1LRSTR`) with those same bit-7 values, i.e. TIM13.
**ARKV6X** (STM32H743IIK6) via the PX4 NuttX tree with the equivalent patch
applied — this board runs I2C4 as its internal sensor bus (BMM150 magnetometer
@ 0x10, BMP390 barometer @ 0x76) with `CONFIG_I2C_RESET=y`. Builds clean.
Not tested on hardware. The change is build-verified and verified against
the ST register map as described above; I do not have a bench setup to run it
on. Happy to have someone with an H7 board using I2C4 confirm.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]