This adds hardware timing support for driving WS2812 LEDs on Cortex-M microcontrollers running at 160MHz (such as the STM32U585).
- Updated `go:generate` directive to include 160MHz.
- Generated the corresponding `ws2812_writeByte160` assembly routine.
- Added a switch case in `WriteByte` to handle generic 160MHz processors.
Signed-off-by: deadprogram <ron@hybridgroup.com>
For details, see: https://github.com/tinygo-org/tinygo/pull/3927
This change just means we need to be more careful to use the right type,
now that types like C.uint32_t don't match to the Go equivalent (like
uint32).
This is better for various reasons:
* I don't like the inline assembly implementation in TinyGo. It kinda
works, but it's hard to use correctly.
* The Go version had a subtle bug: the i and value variables weren't
marked as modified. The compiler produced correct code by chance. In
GCC-style inline assembly, it's possible to correctly mark it as an
input+output operand.
* LLVM 14 has some changes to inline assembly that change how memory
operands can be created. Instead of supporting that, I'd like to get
rid of memory operands entirely (and possibly inline assembly in
general).
I did some light testing: the ARM assembly changed a bit but not in any
way that should have a practical effect, and the RISC-V assembly didn't
change at all.
The possible branch distance is a lot shorter on ARMv6M (Cortex-M and
Cortex-M0+) for conditional branches. Therefore, convert this long
conditional branch into an unconditional branch.
This probably makes the code a little bit slower but because it is in
the low period of the WS2812 signal it shouldn't matter for the
protocol. And it avoids difficult workarounds specifically for the
RP2040.
The WS2811 has a slightly slower data rate, but it is close enough that
a single library can support both LEDs at the same time. In my testing,
this package was already compatible with WS2811 LEDs before this change
when running at 4-5V, but when the voltage dropped to 3V or so the LEDs
started misbehaving. With these improved timings, the LEDs remained of
the correct color even at very low voltages (although blue was starting
to fade due to lack of voltage - that's not a software/protocol issue).
Previously, a new implementation had to be written for each processor
speed. This is tedious and error-prone, therefore I've rewritten all of
the assembly code using a tool that will calculate exactly how many NOP
instructions are required.
I've also switched from build tags to a switch statement over all
processor speeds.
All in all, this means that:
- Chips with a supported CPU performance will automatically be
supported (no build tags necessary).
- Adding a new chip is as easy as adding the MHz count to the
generator script and to the switch statement.
Right now this is only for the Cortex-M, but it's certainly feasible to
extend this to other architectures such as the AVR.