Skip to content

fix(radio): RGB leds signal left floating between frames - #7620

Open
3djc wants to merge 1 commit into
mainfrom
3djc/fix-rgbleds
Open

fix(radio): RGB leds signal left floating between frames#7620
3djc wants to merge 1 commit into
mainfrom
3djc/fix-rgbleds

Conversation

@3djc

@3djc 3djc commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Summary of changes:

The WS2812 data line was left floating between frames, and the frame itself
was refilled from an ISR while the DMA was already running. Both are fixed
here.

1. The line floats between frames

At end of frame _update_dma_buffer() disabled the timer compare channel
(LL_TIM_CC_DisableChannel). With OSSR = 0 that releases the pad instead of
holding it, so the data line floats until the next rgbleds_update(). A
floating input on a WS2812 can be read as bit activity, the reset gap is
missed, and the chip keeps counting bits across frames — the visible symptom
is the whole strip shifted by one LED, colours landing on the wrong chip.

The channel is now left enabled with a compare value of 0, so the output is
actively driven low between frames; only the DMA request source is stopped.
The pin also gets a pull-down at init (insurance for boot / de-init, where the
timer does not drive the pad), and the line is driven low from rgbleds_init() so an idle strip is never left floating before the first frame.

That was the heart of the issue. (#6926). In essence, all radio where vulnerable, but only few exhibited the issue because it needs a specific non favorable board layout to be. actually seen.

2. The frame was refilled under an ISR deadline

The DMA buffer held two LEDs and was refilled half-by-half from the HT/TC
interrupts, so every 24 bit-slots the ISR had a hard deadline. Any higher
priority IRQ (SDMMC, USB) that overran it corrupted the frame in flight.

The whole frame is now built up front and sent as a single one-shot DMA
transfer (LL_DMA_MODE_NORMAL, sized from LED_STRIP_LENGTH), with only a
TC interrupt at the end. There is no refill deadline left, and a late TC IRQ
is harmless because the frame ends with RGBLEDS_TRAIL_SLOTS zero slots that
keep the line low. RGBLEDS_TRAILING_RESET is gone as a result.

Since NDTR and the memory address are not reloaded by simply re-enabling the
stream, rgbleds_update() reprograms both per frame, and a new
stm32_dma_clear_flags() helper (both the H7RS and the classic DMA variants
in stm32_dma.h) clears the pending event flags — a stream cannot be
re-enabled while any of them is still set.

This part was found while trying to harden the signal

This fixes #6926

@3djc 3djc added bug 🪲 Something isn't working backport/2.12 To be backported to a 2.12 release also. backport/2.11 To be backported to a 2.11 release also. labels Aug 5, 2026
@pfeerick pfeerick added this to the 2.11.8 milestone Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport/2.11 To be backported to a 2.11 release also. backport/2.12 To be backported to a 2.12 release also. bug 🪲 Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

USB connection messes up customisable switch LEDs on Jumper T15Pro

2 participants