-
-
Notifications
You must be signed in to change notification settings - Fork 196
neopixel: Support using SPI hardware to send data #771
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
One thing I'm unable to test, and is probably quite important for how this would be used out in the wild, is whether it works properly on Pi 4 and older hardware. On the Pi 5 the SPI clock rate is controlled by the RP1's clock, which is fixed at 200MHz. On older Pi hardware the SPI clock is determined by the core clock, so the actual SPI clock rate might be much slower than requested, depending on how the core clock is scaled at the time of sending data. Any suggestions on how to get some willing testers? I'm also unsure of whether sending this direct to Kalico is appropriate, instead of to Klipper? I'm leaving this as draft for a few days as I want to do some final rounds of testing as soon as I get back to the same room as my hardware. I /think/ it's pretty much ready for review, though. |
de86afd to
f4b6e68
Compare
|
For maximum compatibility with WS2812 clones and revisions it is best if 1 bits are high for at least 800ns. You shouldn't need to make the patterns longer. Just switch some 0 to 1. See Klipper3d/klipper#7113 for my reasoning. (Even Klipper's current T1H = 650 is not long enough for my LEDs.) |
Good timing (😉). Actually even easier, I believe running at 4MHz may solve the problem (1us T1H, 1us T1L, 500ns T0H, 1.5us T0L), and that's user-configurable here -- but switching 1 of the 1-bit bits would probably give wider ranges of compatibility. I need to work through the timings again, anyways. I veered away from what the Adafruit libraries were doing because I couldn't find documentation about the reasoning, but I'll look again with an eye towards this, thanks. I'll also use your test macros, looks more thorough than what I'd been doing.
Would you be willing to help test out this patch? |
|
500ns may be too long for T0H. My research seems to indicate 200 to 300 is best, and 400+ will generate bug reports. The general idea of using SPI and DMA to avoid pre-emption trouble on the Raspberry Pi goes back pretty much all the way to the original launch, although I am not sure how well it ever worked. At the moment I can only test on RP2040 as I don't have a stand-alone voltage shifter to use with other boards, other than the one on my SB0000 toolhead breakout. I have the parts to build one on order though. |
|
I put together a spreadsheet to show the different timings from various bit patterns and how they would work out for different SPI data rates: https://docs.google.com/spreadsheets/d/15FCtdJybMRscKh2xRNOzyStjmfH_7MbzbncTJFRtUMw It seems like a default SPI data rate around 5-6MHz and a bit pattern of 2 high bits for a 0 and 5 for a 1 would be a good range, and hopefully the fact that the SPI data rate is configurable by the user would allow even more flexibility for compatibility. WDYT? The main thing I still wanted to check is what exactly happens on the boards I have when you request a SPI rate that the board doesn't support -- I can't remember if both the Pi and STM32 gave the closest possible rate, or some other behaviour. |
I don't know much about the RP2040, but if it supports SPI on the pin you're using for your neopixels that'd be a useful datapoint on a piece of hardware that I don't have (and so haven't tested on). |
|
I have a SB2209/RP2040. The LED port is GPIO16. That's a SPI Rx, so it won't work for me. When I get the parts I can test a generic Pico. I have never touched SPI on RP2040 as PIO is the go to for signal synthesis. Afaik Klipper does not use it because it is arch specific, but it is really powerful. |
6a1ef9d to
3b9fb5d
Compare
This change allows the use of a SPI bus to send correctly timed data to a string of neopixels. The idea is to take advantage of hardware to do the timing; this does not magically make these SPI devices. As such, it is only allowed on platforms that support hardware SPI. The main motivation is that the bitbang approach cannot be used directly from a Raspberry Pi secondary MCU as the bitbang timing is not precise enough. Using a SPI bus to send data to neopixels is a commonly used technique among other open source projects, and seems to work well in Kalico, too. On the devices I have tested (Raspberry Pi 5) the available SPI speeds work with the data patterns that I have hardcoded, but it is conceivable that it may be necessary to make the data configurable or automatically generated based on requested bus speed in order to support some neopixel-like devices. In order to support Neopixel strings longer than 8-10 pixels (depending on the number of colours), this also adds a `spidev_transfer_large` to the linux platform which uses a `size_t` data length instead of `uint8_t`. Signed-off-by: Russell Cloran <rcloran@gmail.com>
3b9fb5d to
6688a7b
Compare
|
My initial formulation of this supported using SPI on any MCU. However, the SPI support on most platforms sends one byte at a time -- this translates to one bit of neopixel data in this code, and the timing between the SPI bytes/neopixel bits is unconstrained. Most of the time this seemed to work out, but it wasn't reliable, and caused occasional flickering. The Linux platform, which was the main motivation behind doing this, does a single data write (or ioctl) to send all SPI data, and so the flickering was never a concern on small strings of pixels. For larger strings of pixels I tried to chunk the data in the So, I've introduced a new interface, which is only implemented in the Linux platform. I'm a little uneasy with the naming I've chosen ( |
This change allows the use of a SPI bus to send correctly timed data to
a string of neopixels. The idea is to take advantage of hardware to do
the timing; this does not magically make these SPI devices. As such, it
is only allowed on platforms that support hardware SPI.
The main motivation is that the bitbang approach cannot be used directly
from a Raspberry Pi secondary MCU as the bitbang timing is not precise
enough. Using the SPI bus to send data to neopixels is a commonly used
technique among other open source projects, and seems to work well in
Kalico, too.
On the devices I have tested (Raspberry Pi 5) the available SPI speeds
work with the data patterns that I have hardcoded, but it is conceivable
that it may be necessary to make the data configurable or automatically
generated based on requested bus speed in order to support some
neopixel-like devices.
In order to support Neopixel strings longer than 8-10 pixels (depending
on the number of colours), this also adds a
spidev_transfer_largetothe linux platform which uses a
size_tdata length instead ofuint8_t.Signed-off-by: Russell Cloran rcloran@gmail.com
Checklist