Skip to content

refactor(driver): centralize I2C locking and migrate polling to RTOS timers#7230

Open
raphaelcoeffic wants to merge 9 commits intomainfrom
i2c-conflicts
Open

refactor(driver): centralize I2C locking and migrate polling to RTOS timers#7230
raphaelcoeffic wants to merge 9 commits intomainfrom
i2c-conflicts

Conversation

@raphaelcoeffic
Copy link
Copy Markdown
Member

@raphaelcoeffic raphaelcoeffic commented Mar 29, 2026

Summary

  • I2C locking moved to HAL layer — new i2c_lock/i2c_trylock/i2c_unlock API in hal/i2c_driver.h; mutex removed from STM32 driver, callers lock explicitly
  • I2C bus recovery — SCL bit-bang per ST AN2824 with auto-retry on transfer failure
  • All I2C callers updated — timer-context uses i2c_trylock (non-blocking), task-context uses i2c_lock, pre-scheduler skips locking
  • IMU polling migrated from mixer task to dedicated RTOS timer with i2c_trylock
  • GX12 switch polling migrated from synchronous mixer-task to async/timer pattern
  • CSD203 power sensor ported to ETX HAL (i2c_read/i2c_write), moved from targets/common/arm/stm32/ to drivers/, polling moved to own RTOS timer
  • Removed obsolete IICReadStatusFlag bus-preemption workaround from CSD203 and GT911 touch driver — the I2C mutex handles bus sharing
  • Removed unused MutexLock RAII wrapper from os/task.h
  • Fixed latent deadlock in 2-arg stm32_i2c_is_dev_ready overload
  • I2C scan via CLI command

Test plan

  • Build and flash V12, V14, V16 (CSD203 targets) — verify battery voltage reads correctly
  • Build and flash TX16S, Boxer (non-CSD203 targets) — verify no regressions
  • Verify GX12 switches still work properly
  • On shared-bus targets (ST16, TX15, X12S): verify touch + IMU work without I2C contention
  • Verify IMU/gyro readings are stable after timer migration

🤖 Generated with Claude Code

raphaelcoeffic and others added 8 commits March 29, 2026 10:22
Add centralized I2C bus recovery via SCL bit-banging (per ST AN2824) to
handle the well-known STM32F4 SDA-stuck-low condition. All I2C transfer
functions now automatically attempt recovery + retry on failure.

Migrate GX12 PCA9555 switch polling from synchronous mixer-task calls to
the async/timer pattern (matching rm-h750), eliminating I2C bus access
from the mixer task entirely. Add 3-level error recovery to the GX12
IO expander reads (PCA reset -> I2C bus recover -> give up).

Fix GX12 EXTI config: PE14 (PCA9555 INT) needs EXTI15_10, not EXTI1.
Fix latent deadlock in 2-arg stm32_i2c_is_dev_ready overload.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move per-bus mutex ownership from the STM32 I2C driver to the HAL layer
(i2c_bus.cpp). Transfer functions no longer lock internally — callers
are responsible for explicit locking matching their execution context:

  - i2c_lock/unlock: blocking, for regular task context
  - i2c_trylock/unlock: non-blocking, for timer task context
  - no locking needed before RTOS scheduler starts

This avoids blocking the FreeRTOS timer service task (which must never
block per FreeRTOS documentation) when I2C buses are shared between
timer-polled devices (IMU, IO expanders) and task-polled devices (touch).

Update GX12 bsp_io to use i2c_trylock from timer callback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update all I2C device drivers to use the new explicit locking API:

Timer/ISR context (i2c_trylock, skip if busy):
  - GX12 bsp_io (PCA9555 switch polling)
  - rm-h750 bsp_io (PCA9555 switch polling)
  - PA01 key_driver (AW9523B matrix scanning)
  - CSD203 power sensor

Regular task context (i2c_lock/unlock):
  - Touch drivers (GT911, CST8xx, CST340, CST836U, FT6236, CHSC5448)
  - IMU drivers (LSM6DS, ICM42607C, SC7U22)
  - TAS2505 audio codec volume control
  - EEPROM driver
  - Volume I2C driver
  - Seesaw GPIO expander

Init-only drivers (no locking, pre-scheduler):
  - WM8904 audio codec
  - PCA95xx (locking at call site)
  - AW9523B (locking at call site)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move gyro/accelerometer I2C reads from the mixer task to a dedicated
10ms RTOS timer callback. Uses i2c_trylock so the timer service task
never blocks — if the bus is held (e.g. by touch controller in menu
task), the IMU sample is skipped and retried next cycle.

This eliminates I2C bus contention between IMU and touch on targets
where they share a bus (ST16, TX15, Horus X12S).

Changes:
- gyro.cpp: replace gyroWakeup() with timer callback using trylock
- gyroStart() now takes bus parameter, starts the timer
- IMU read functions (lsm6ds, icm42607C, sc7u22): remove internal
  i2c_lock since gyro timer callback handles locking
- imuDetect() returns detected bus via output parameter
- Remove gyroWakeup() from mixer task execMixerFrequentActions()
- Update all board.cpp gyroInit() to pass bus to gyroStart()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The minimal_board_lib native target compiles i2c_bus.cpp without
BOOT or FREE_RTOS defined. Change the preprocessor guard from
!defined(BOOT) to defined(FREE_RTOS) so mutex code is only compiled
when FreeRTOS is actually available.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move CSD203 power sensor from targets/common/arm/stm32/ to
drivers/, replacing STM32-specific stm32_i2c_master_tx/rx with
HAL i2c_read/write. Polling migrated from per10ms() to a
dedicated RTOS timer (matching the IMU pattern), and the obsolete
IICReadStatusFlag bus-preemption workaround removed from
tp_gt911.cpp since the I2C mutex now handles bus sharing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gyro.cpp now calls i2c_trylock/i2c_unlock directly, which are
only provided by the STM32 i2c_bus.cpp. Add no-op stubs for
all i2c_driver.h functions in the simu target so native builds
(simulator and unit tests) link correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@raphaelcoeffic raphaelcoeffic added this to the 3.0 milestone Mar 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant