FastLED, WS2812b and UART Interrupts

Status
Not open for further replies.

Cosford

Well-known member
I've got a project receiving UART data on UART0 (Serial1) whilst driving a string of WS2812b's, using FastLED, on a Teensy 3.2.

The UART runs at 460800 bps, I'm driving 15 LEDs.

My understanding of the default timing of FastLED and WS2812b's is as follows:
1) Disable interrupts
2) Output data for first LED (~30uS)
3) Enable Interrupts for 5 uS, then disable again.
4) Output data for next LED
5) ...

In my case, I have serial data coming in at 460800 bps, therefore a new byte is available approximately every 21uS. Uart 0 has an 8-byte receive FIFO, so in theory, we need to service it (at least) every ~168uS, to shift the data out of the FIFO and into the soft circular buffer.

It appears, initially, that my LED data is being occasionally corrupted - this would suggest that FastLED is correctly enabling interrupts, but there is an interrupt running in that period which is longer than 5uS. Sure enough, defining FASTLED_ALLOW_INTERRUPTS to 0 (and thus disabling the interrupts between LED data writes), prevents the LED corruption (but of course, prevents the FIFO being serviced and thus serial data is lost).

Anyone got any ideas on this one? How long does it take to run that UART 0 status ISR? Are there other interrupt routines that could be running in there I should be aware of ? (I'm also using the audio library, but this issue occurs even when it isn't playing anything).

Unfortunately the design is committed to hardware, so leveraging Octows2812, or changing to clockable LEDs is not an option.

Thanks in advance,
Iestyn
 
Further investigation has revealed that (as I somewhat expected), it wasn't anything to do with the UART (this was merely a symptom of course).

Stripping back my sketch, it appears the simple creation of an AudioOutputAnalog object is enough to cause the issue - I don't understand why though. I've tried to use AudioNoInterrupts() and AudioInterrupts() to wrap around the FastLED.show() calls, but this hasn't helped...

Funnily enough - it appears I encountered this problem before https://forum.pjrc.com/threads/39913-Audio-Library-Interrupt-Frequency
Back then, I got away with it by disabling the interrupts between LED writes, but in this case, I need these to work to get the serial data in.

Is there a way we can prevent these audio interrupts running? Can we disable all interrupts below a certain priority level? Or disable the DAC?
 
Last edited:
So this crossed my mind - the issue being that the calls to FastLED.show() weren't running in an interrupt, so could be interrupted by anything. Based on that, I devised a work-around.

I used an IntervalTimer to generate a software interrupt, and stuck FastLED.show() in that (inheriting an interrupt priority of 128 - higher than the audio libraries slow interrupts). This effectively disabled the audio library interrupts.
(Of course, I needed to disable the IntervalTimer too to make sure we didn't stack up interrupts!).

This seems to have worked - I don't yet know what the effect of disabling the 'slow' audio library interrupts for 0.5ms will be yet though!
 
Anyone got any ideas on this one?

Use WS2812Serial, which does not disable interrupts. You'll need to connect the LED data to pin 10.

For an example how to do this with FastLED, in Arduino click File > Examples > WS2812Serial > FastLED_Cylon. Using this alternate driver and extra library will completely remove the interrupt disable behavior, which causes trouble with Serial1 while the LEDs are updating.

You might also need to increase the Serial1 receive buffer, by editing serial1.c.
 
Status
Not open for further replies.
Back
Top