refactor(driver): centralize I2C locking and migrate polling to RTOS timers#7230
Open
raphaelcoeffic wants to merge 9 commits intomainfrom
Open
refactor(driver): centralize I2C locking and migrate polling to RTOS timers#7230raphaelcoeffic wants to merge 9 commits intomainfrom
raphaelcoeffic wants to merge 9 commits intomainfrom
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
i2c_lock/i2c_trylock/i2c_unlockAPI inhal/i2c_driver.h; mutex removed from STM32 driver, callers lock explicitlyi2c_trylock(non-blocking), task-context usesi2c_lock, pre-scheduler skips lockingi2c_trylocki2c_read/i2c_write), moved fromtargets/common/arm/stm32/todrivers/, polling moved to own RTOS timerIICReadStatusFlagbus-preemption workaround from CSD203 and GT911 touch driver — the I2C mutex handles bus sharingMutexLockRAII wrapper fromos/task.hstm32_i2c_is_dev_readyoverloadTest plan
🤖 Generated with Claude Code