drivers/ws281x: Bit banging STM32 support
Contribution description
This pull request adds support for driving ws281x LEDs on STM32 microcontrollers operating at 84, 100, and 180 MHz clock frequencies. That's the case for almost all STM32F4 microcontrollers, except 405/415 and 407/417. The implementation uses the bit banging approach by exploiting NOPs. (Don't be afraid of all the lines I've changed. Most of them are NOPs.)
The following parts of the RIOT are involved:
- drivers/ws281x
- drivers/include
You can test my changes with the test application provided in tests/ws281x and using a STM32 board like the "nucleo-f411re" or any other Nucleo with a STM32 that operates at 84, 100, and 180 MHz.
Testing procedure
This implementation was tested with the test application provided in tests/ws281x using a "weact-f401cc", "nucleo-f411re" and "nucleo-f446re" board. Each time I did a visual inspection of the LEDs. In addition to that, I also checked the timings with a "Saleae Logic Analyzer" at 500MS/s. Since every board I mentioned above has a different CPU speed, I confirmed that my implementation works for all mentioned clock frequencies.
Thanks for you pull request and sorry for the long delay.
This PR has been opened just shortly after https://github.com/RIOT-OS/RIOT/pull/19891 was merged. I think it might be, that you have been unaware of https://github.com/RIOT-OS/RIOT/pull/19891.
For https://github.com/RIOT-OS/RIOT/pull/19891 to work on STM32 MCUs the periph_timer_poll extension is needed. I do believe that this would be the better approach, as this API extension would be useful not only for ws281x bit-banging, but other bit-banging as well.
In addition I have made some unpleasant experiences with counting CPU cycles for timing, as this can vary a lot between different MCUs. E.g. the Cortex M7 has this dual issue feature that may allow the CPU to perform two instructions in a single CPU cycle. However, it is difficult to find out documentation that clearly specifies which instructions get executed simultaneously and which not. Specifically, would to nops qualify for this to be executed in one CPU cycles, or not? Also whether the instruction cache is hot or not has a huge impact. Hence, I believe that using a timer for timing is less fragile.
In conclusion, I would prefer if ws281x bit-banging would be implemented using the timer.
Also note: https://github.com/RIOT-OS/RIOT/pull/20218 would be even another approach that would work for STM32. (Ab)using SPI with DMA for the bit-banging would allow the CPU to either attend other tasks, or to conserve power. That would only work for STM32 MCUs with DMA, though.
Would https://github.com/RIOT-OS/RIOT/pull/20646 be a viable alternative for you?
Hi,
yes at this time i was unaware of https://github.com/RIOT-OS/RIOT/pull/19891 and it seems like the better option.
Hi,
I haven't looked in my PR for a while. I sadly was unable to reliably control one family of ws281x LEDs with that PR.
It might be a hardware issue with that 5x5 LED matrix I was testing against.
It might be that the alternative I suggested doesn't meet the timing requirements good enough for consistently controlling the ws281x LEDs. Or I just didn't get the implementation right yet. Or I messed up the PCB desing of LED matrix tested against.
I sadly do not have time to dig deeper into it as of now ☹️