Close

More RPI SPI/WS2812 problems, and USB

A project log for Tron Identity Disc upgrade.1

Upgrade a Tron Identity Disc with: RPI Zero, WS2812b LEDs, Sound, Gyro/Accel, USB storage/networking/charging, Wi-Fi, haptic feedback...

dan-rogahnDan Rogahn 04/29/2017 at 06:590 Comments

I investigated realtime and deadline schedulers to see if they could improve reliability of WS2812 LEDs connected to SPI1 on a RPI.

In short: no.

Additionally, the bcm2385 main & aux SPI drivers definitely need some work to support bit lengths other than 8.

Surprisingly, I found that USB (or the USB network gadget) has a huge impact (I read USB on RPI makes use of a special high priority, fast interrupt).
Activating the network, or a data transfer of several kB causes major glitches in the SPI/LED timing - until the traffic dies down.

More details below...
The docs I've read suggest that the scheduler/interrupt latency varies around 75-100us. Generally, every task or interrupt handler should get a chance to run in that time period, even in the worst case of a 100% cpu load (give or take priorities). But for the 9us LED reset, that is too quick for an interrupt (so can't do something tricky like connecting SPI1.CS0 to a GPIO pin and monitor it with an interrupt)

The linux command "chrt" changes the task scheduler and priority for a process. This allows you to test the "realtime" scheduler to give a process the highest available priority, and longest runtime slice. Unfortunately this doesn't help my SPI/WS2812 problem.

There is a recent kernel option for SCHED_DEADLINE that can guarantee scheduling for recurring tasks, which could help avoid timing out that 9us reset. The chrt app should allow testing sched_deadline -- but the util-linux package that contains it is old. Building chrt from source was not hard (./configure; make chrt).

Deadline has a few parameters: process expects to run for T (it can finish early), must finish before D each period, and period is P.
T<=D<=P and T >= 1024 (all microseconds)

But I only get an error "chrt: failed to set pid 0's policy: Invalid argument"
So I guess that deadline wasn't built into the RPI kernel.

So, can we make the SPI transmission more efficient?
To review: I'm sending zero as 0b100 and one as 0b110 (2x3 bits padded to 8).
Theoretically, stretching out the transmitted LED bit 1x0, into 111xxx0 and transmitting at 3x the rate saves some time. But the buffer also empties out 50% faster (3x rate and 1/2 the LEDs per byte) .

Can we make the transmission slower, to get more time to refill the SPI buffer?
The LEDs lose all data at 1.9 MHz (estimates say they should work down to 1.7Mhz).
The internet suggests there is a 1us padding before & after a SPI transmit. If the data line idles at 0, we could transmit __1x__ at 1.88 MHz. (Or a little bit more gain with variable length __1__ and __11__)
Unfortunately the main and aux SPI drivers only support 8 bit transfers. Furthermore, the aux driver sets variable width SPI mode, wasting one of the bytes in the 4 byte buffer. (It is a 4 byte buffer? The Broadcom doc is not so good)
Additionally, if the SPI transfer will take longer than 30us, the driver will setup to wait for the IRQ instead of busy-wait. At 1 MHz that is less than 30 bits. That may be a big problem for this application.

Discussions