OctoWS2811 and Threading

MartinB

Member
Hi,
I am just starting a project that is using LED sheets... they are essentially an LED strip zig-zagged. The difference is that each RGB "LED" is actually 3 White LEDs. The strip has TM1812 controls but using the OctoWS2811 works just fine. The final project will have 16 sheets each with 96 "LEDs" - or should I say 288 white LEDs for me to address individually. I am experimentation with one sheet to start with and controlling the individual LEDs exactly as I want is not a problem. Well it wasn't until I tried using Threading. Even if I just add #include "TeensyThreads.h" a function that fades a bunch of LED up and down causes random flashing of other LEDs not in the set being faded.

Is it possible that there is just an incompatibility between the OctoWS2811 board and library and Threading, or is there any tweaks I cam make to stop the problem?

A very simple example of a sketch that demos the problem is below. In an effort to minimize the complexity just to show the problem at its bare bones I even stripped out the fading. With the sketch all is fine with the threading disabled, but once it is enabled the random flashing occurs. The for loop is just to simulate the changing of the brightness values for the LEDs so fading them.

Any suggestions very much appreciated.

//#include "TeensyThreads.h"
#include <OctoWS2811.h>

const int ledsPerStrip = 88;

DMAMEM int displayMemory[ledsPerStrip * 6];
int drawingMemory[ledsPerStrip * 6];
const int config = WS2811_RGB | WS2811_800kHz;
OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, config);

void setup() {
leds.begin();
}

void loop() {
// put your main code here, to run repeatedly:
LightTheLEDs();
delay(5000);
}

void LightTheLEDs()
{
for (int i = 0; i < 100; i++)
{
leds.setPixel(14, 0, 40, 40);
leds.setPixel(15, 40, 40, 0);
leds.setPixel(16, 0, 40, 0);
leds.setPixel(17, 0, 0, 40);
leds.setPixel(30, 40, 0, 0);
leds.setPixel(31, 0, 40, 0);
leds.setPixel(32, 0, 40, 0);
leds.setPixel(33, 0, 0, 40);
leds.show();
delay(40);
}
}
 
Hi,

I'm new here as well, but as I'm using the OctoWS2811 lib myself as well, I'll try to help you until someone with more experience chimes in.

I'm not sure that I actually understand what you want to use the TeensyThreads library for. The OctoWS2811 library already drives all pins simultaneously and is just blocking for around 2ms at most if I remember correctly.
Does running your test sketch work at all with all leds connected? You're only using setPixel on all 88 leds of the first strip and 12 leds on the second strip.

I guess the use of "delay" is just for your test sketch, right? Because using a non-blocking library for driving the leds and then using "delay" wouldn't make much sense.
 
Last edited:
Hi,
Thanks for your response. The reason for investigating the use of Threading is that I will have a number of functions that update groups of LEDs. Each function will loop and provide animation for that group of LEDs. Each function will essentially be blocking which I don't want to be the case and I had hoped that Threading would be the answer. But it introduces random flashing even when it has just been included and not even invoked.

Re you observations about the Display and Drawing memory settings. I took the example sketch and left those two values as they were. My test rig has a single strand of 88 connected to the first output of the OctoWS2811 Adaptor (via Cat6 cable). Based on that what do you believe the Display and Drawing memory settings should be?

The delay is set to 40 millis as that is equivalent to 1 25th of a second which is the rate at which I plan to have the LEDs refresh at. However for the proper project I will no doubt use the Blink without delay method.

The posted script works just fine (as to the proper animation functions I have written) when the threading is not activated. But as soon as it is the random flashing becomes an issue.

Regards - Martin
 
Hi,

about those displayMemory and drawingMemory settings, I had a logical error in my reply, so I edited that out, those settings are fine.

Did you try to use the TeensyThreads library without using any "delay" within your sketch? I could imagine that threading and delay wouldn't play nice together.

I just noticed (overlooked that before), that you're looping 100 times but still only set the colors for leds 14, 15, 16, 17, 30, 31, 32 and 33.
There's no code to change the "color" after that, just repeatedly the same leds and colors, so they wouldn't change at all after the first run, is that intended?
 
Hi,
Yes I did try without delay. I implemented the "Blink without delay" timer and had the same results.
The example sketch I included was a simplified, very cut down sketch that does no more that show the issue while removing any distractions in the code. I am certain that the random flashing occurs when the leds.show(); command is executed. as when a longer delay is placed in the function the flashing is also delayed. So I suspect that there is an incompatibility between the OctoWS2811 and TeensyThreads libraries.

Regards - Martin
 
I don't get, why you would want to use the Thread library at all, as the WS2811 library is using DMA, so the code, that is updating the the LEDs does not have to wait at all, because after you set the data, everything else is done in background.

And while we are at that: I have no real clue, how all that DMA magic works, but I would assume, that it might be an issue, that you might have race-conditions on that memory, when you randomly stop one "thread" to execute the next one, doing literally the same.

the library does everything on 2 areas in the memory (displayMemory, drawingMemory). I don't know exactly, what is going on in those areas, but I would assume, that it is something like doublebuffering. so setPixel writes into drawingMemory, .show() copies that into displayMemory and in the background DMA magic is sending the displayMemory to the LEDs. If you manipulate drawingMemory in one "thread" while another part is doing that "copy drawing to display and trigger background sending), that will probably mess up the results you are expecting.

As I don't know what you are doing, I can just assume, but there is not much, that really needs to block the execution of the main loop. where every there is a while(conditionToContinueIsFalse){yield();} can be replaced by if( conitionToContinueIsFalse) return; and just get called periodically. I totally can miss something but all the IO possibilities (SPI, Serial, I2C whatever) are all buffering and non-blocking, so if something is blocking, its highly possible that its something that can be changed.

So instead of trying to work around a problem that maybe does not even exists and try to find problems in 2 (hopefully) optimized libraries, I would spend the time in investigating a way, to just not need fake-multithreading.
 
Hi,
The reason for trying to use the Threading was due to seeing it as an easy way to achieve what I was aiming to do. I have a few functions that create animations of groups of LEDs on the Sheet of LEDs that I am working with. Each function is blocking as it uses a "for" to produce its animation. Not having used the TeensyThread library before I did not realize that it would produce the unexpected (random flashing) that it does. So, having googled to see if anyone else had had the same issue and resolved it with no luck I thought I would ask here.

Thank you for your insights into the potential cause being the way that DMA is used.

I have come to the conclusion that I will need to alter my approach to the functions and create one that controls the others. Issuing updates to each to advance their individual animation frame at an appropriate x number of millis in a loop.

Thank you for your time replying.
 
TeensyThreads has a thread.delay() that should be used and not the delay() function - check the github readme and examples.

Using the delay() would cause some difficulty for TeensyThreads to work effectively.

@Uija makes good points where threading may or may not be the best. Some tasks need to complete.
> Mundane code in loop() can keep them from happening.
> But interrupting a critical task before completion isn't helpful.

Using the thread.delay() or better .yield() allows the multitasking to be cooperative if time slices are as long as needed then that .delay() or .yield() returns the CPU to the next task on completion or if no work at hand.

The loop() code is another task.

github.com/ftrias/TeensyThreads
Code:
void yield()	Yield current thread's remaining time slice to the next thread, causing immedidate context switch

void delay(int millisecond)	Wait for milliseconds using yield(), giving other slices your wait time
 
Hi,
The problem is evident even when delay() is not used. With the delay() used it just highlights the problem. To eliminate delay() as being part of the issue I have tried using the "blink without delay method of adding delay to the function. The random flashing still occurred. The problem occurs without actually implementing threading, just including the #include "TeensyThreads.h" library is enough to cause the issue.

As mentioned I am now taking a different approach by using a "mast" function to issue out updates to the other functions at relevant timings.

Regards - Martin
 
If "all" you are doing there in a for-loop is iterating through Animation-Frames and the Blocking Part is the loop waiting for the time to perform the next frame, than it should be easily possible to get that non-blocking, by iterating a variable with the frame index and just calling the function periodically based on the time between frames.

You can do that in several approaches. You could use elapsedMillis for that:
Code:
elapsedMillis frame_timer = 0;
void lood() {
  if( frame_timer >= MILLISECONDS_PER_FRAME) {
    frame_timer -= MILLISECONDS_PER_FRAME;
    nextStepForAnimationA();
    nextStepForAnimationB();
    nextStepForAnimationC();
  }
}
That way you should have a more or less constant frame rate independent of how long the Animation-Calculation takes.

Or you can use IntervalTimer, that are quite exact:

Code:
IntervalTimer animation_timer;
void nextStepForAnimations() {
  nextStepForAnimationA();
  nextStepForAnimationB();
  nextStepForAnimationC();
}
void setup() {
  animation_timer.begin( nextStepForAnimations, 40000); // should be around 25fps
}
void loop() {
  // Do whatever you need to do outside of animating LEDS.
}
 
Back
Top