Skip to content

refactor(driver): move 6POS tracker into board-level ADC callback#7309

Open
raphaelcoeffic wants to merge 3 commits intomainfrom
sixpos-adc-completion
Open

refactor(driver): move 6POS tracker into board-level ADC callback#7309
raphaelcoeffic wants to merge 3 commits intomainfrom
sixpos-adc-completion

Conversation

@raphaelcoeffic
Copy link
Copy Markdown
Member

@raphaelcoeffic raphaelcoeffic commented Apr 20, 2026

Summary

Follow-up to #7304. The 6POS sticky-position tracker lived in hal/adc_driver.cpp:getAnalogValue() behind a SIXPOS_SWITCH_INDEX special case. Every reader (cli, diaganas, switches, inactivity_timer, …) re-triggered the state machine, which is wasteful and ran state updates from contexts that were never meant to drive them.

This moves the tracker into sixPosUpdateFromAdc(), invoked once per conversion from the board adc_wait_completion callback in boards/generic_stm32/analog_inputs.cpp. The pattern matches the existing ADS79xx SPI ADC integration, keeping all ADC post-processing in one well-defined layer.

  • getAnalogValue() becomes a plain array read — no SIXPOS_SWITCH_INDEX branch.
  • getSixPosAnalogValue is no longer a board-level API; it's internal to rgb_6pos.cpp.
  • rgbLedOnUpdate() still reads _six_pos_state from the LED timer task, unchanged.

Stacked on #7304 — merge that first. Targets base ws2812-double-buffering here; retarget to main once #7304 lands.

Test plan

  • make firmware builds on V16 (RADIO_V16, Horus-family 6POS)
  • make firmware builds on V14 (RADIO_V14, Taranis-family 6POS)
  • make firmware builds on tx16s (non-6POS sanity check)
  • On-radio smoke test: 6POS switch positions still register correctly and LEDs follow the pressed position

raphaelcoeffic and others added 3 commits April 19, 2026 09:41
The WS2812 LED strip was driven from two contexts without any
serialisation: the FreeRTOS refresh timer (50ms) and Lua's
applyRGBLedColors. Both called ws2812_update directly, racing on the
DMA arming sequence, and the DMA ISR read the same _led_colors buffer
that callers were mid-writing — producing torn pixels and partial-frame
flicker.

Switch to a lock-free single-driver design:

- Board (rgb_leds.cpp) now owns a back buffer (writes) and a front
  buffer (DMA). Setters touch only the back buffer; the timer task is
  the sole arm point for ws2812_update at runtime.
- A seqlock-style counter (_commit_seq) publishes batches: setters
  mark the LSB to flag mid-batch; rgbLedColorApply rounds up to the
  next even value to publish; the timer copies back→front only when
  the seq is even, differs from the last consumed value, and DMA is
  idle. Compiler barriers prevent reordering of plain back-buffer
  writes around the volatile seq updates.
- Pre-OS callers (charging UI) bypass the timer: rgbLedColorApply
  detects scheduler_is_running() == false and flushes synchronously.

To make the board the sole entry point, the no-buf ws2812_set_color /
get_color / get_state are replaced by buffer-parameterised variants;
all direct callers in horus/taranis/pl18/pa01/rm-h750/jumper-h750
boards and the generic_stm32 fsLedRGB now go through rgbSetLedColor.
fsLedRGB and pa01's status-LED helpers gain explicit rgbLedColorApply
calls to preserve their fire-and-forget semantics.

pa01's separate _led_charge_colors buffer and ad-hoc ws2812_init are
removed; rgbLedHwInit is exposed so the charging UI can bring up the
WS2812 hardware before the scheduler is running while still sharing
the rgb_leds.cpp front buffer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
getSixPosAnalogValue() ran in the mixer task and wrote directly to the
WS2812 back buffer. On V12/V14/V16 that made the mixer a second writer
racing with Lua's setRGBLedColor / applyRGBLedColors batches — the
double-buffer seqlock only serialises publication, not concurrent
back-buffer writes.

Split the function: keep the sticky position tracker in the ADC hot
path (a single volatile uint8_t write, read by other tasks as an
atomic byte), and move the LED paint into a new weak rgbLedOnUpdate()
hook called by the rgb_leds.cpp refresh timer. The 6POS LEDs (indices
0..5) now have the LED timer task as their sole writer, while Lua
addresses map through BLING_LED_STRIP_START=6 onto the remaining
range — so the two writable ranges are disjoint and cannot race.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 6POS sticky-position state machine lived in
hal/adc_driver.cpp:getAnalogValue() behind a SIXPOS_SWITCH_INDEX
special case. Every reader (cli, diaganas, switches, inactivity_timer,
…) re-triggered the tracker, which is wasteful and ran state updates
from contexts that were never meant to drive them.

Move the tracker into sixPosUpdateFromAdc(), called once per conversion
from the board adc_wait_completion callback in analog_inputs.cpp. This
matches the pattern used by the ADS79xx SPI ADC integration and keeps
all ADC post-processing in one well-defined layer. getAnalogValue is
now a plain array read with no special cases, and the 6POS entry
point is no longer a board-level API.

rgbLedOnUpdate() still reads _six_pos_state in the LED timer task,
unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@raphaelcoeffic raphaelcoeffic added the backport/2.12 To be backported to a 2.12 release also. label Apr 20, 2026
@pfeerick pfeerick added this to the 2.12.1 milestone Apr 28, 2026
@pfeerick pfeerick added the house keeping 🧹 Cleanup of code and house keeping label Apr 28, 2026
@helloradiosky
Copy link
Copy Markdown
Contributor

image After I fixed it this way, I no longer encountered the issue of random key presses during my testing. Let's see if this method works.

Base automatically changed from ws2812-double-buffering to main April 29, 2026 10:09
@pfeerick pfeerick added the needs: rebase A git rebase on top of the latest destination branch version is required label Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport/2.12 To be backported to a 2.12 release also. house keeping 🧹 Cleanup of code and house keeping needs: rebase A git rebase on top of the latest destination branch version is required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants