bigjosh / SimpleNeoPixelDemo

A demonstration showing how easy it can be to drive WS2812 NeoPixels
MIT License
223 stars 59 forks source link

LEDs just go white... #3

Closed ajfisher closed 9 years ago

ajfisher commented 9 years ago

I've got the code compiling fine and flashing onto the board but for some reason the LEDs just go white and never change.

I've tried debugging this and bringing it back to as simple a task as possible.

Even doing a loop where you do this:

sendPixel(255,0,0);
show();

Will correctly turn on the first pixel but it will set it white as well.

doing something like this:

sendPixel(0,0,0);
show();
delay(5000);
sendPixel(255,0,0);
show();
delay(5000);

Which should effectively give you a blink on the first pixel doesn't seem to do that. Writing some debug statements into sendByte I can see it's got the correct values but for some reason the pixel itself is going full white (even when being sent zeroes).

So the question is - have you seen this before? If so is it something to do with timings?

FYI - I am using WS2812Bs from china however they work totally fine with the adafruit library so I know the LEDs are fine... so it has to be something software related.

bigjosh commented 9 years ago

Yes, the latest versions of the compiler look like they are optimizing the code differently. This changes the timing and stretches all the bits into 1's - which is why you see all white.

One way around this is to rewrite the bit routines in hard coded assembly, but this kind misses the point of keeping everything simple and in C. :)

Right now I am writing an article showing how to drive NeopIxels using the Timer output. This is not simple at all, but should work on any compiler because the timing is done in hardware. I hope to get this article up today.

If the new article does not work for what you are trying to do, LMK and I will make a path to this code that will work with the new compiler.

Thanks!

-josh

ajfisher commented 9 years ago

Ah that's annoying - got to love compilers changing things on you.

If you need anyone to do some testing let me know and I'll be more than up for it.

On Sat Feb 14 2015 at 01:44:07 Josh Levine notifications@github.com wrote:

Yes, the latest versions of the compile look like they are optimizing the code differently. This changes the timing and stretches all the bits into 1's - which is why you see all white.

One way around this is to rewrite the bit routines in hard coded assembly, but this kind misses the point of keeping everything simple and in C. :)

Right now I am writing an article showing how to drive NeopIxels using the Timer output. This is not simple at all, but should work on any compiler because the timing is done in hardware. I hope to get this article up today.

If the new article does not work for what you are trying to do, LMK and I will make a path to this code that will work with the new compiler.

Thanks!

-josh

— Reply to this email directly or view it on GitHub https://github.com/bigjosh/SimpleNeoPixelDemo/issues/3#issuecomment-74263464 .

bigjosh commented 9 years ago

After some research, I now think it is impossible to write any practical code that is dependent on exact timing and sequence in GCC because there is no way to prevent the compiler from rearranging the order of operations when it optimizes. You might be able to craft a piece of code that happens to result in the correct order of operations for a specific compiler version with specific settings, but it is just luck and there are no guarantee that the same code will continue to work.

My new strategy is to generate the critical timing sequences using the chip's Timer2 hardware. The output of this unit is precise to a single clock cycle (62.5ns with a 16Mhz clock) and completely deterministic. Also, once started it will run completely independently of and ode that is executing, so you can do simultaneous foreground processing and even turn off interrupts. As long as the system clock is running, the correct pulse will go out.

BTW, I know that many people want this code so they can respond to latency sensitive interrupts while also driving NeoPixels (mainly for RF reception). While the current code is succeeds in letting you receive data while also driving NeopIxels, it is possible that the NeoPixels can be corrupted because the RF receive routine turns of interrupts long enough to cause the NeoPixels to reset. There is not much you can do about this without re-writing the receive code, at least with the new Timer2-based approach you can detect when this happens and limit the damage to a single pixel, and then immediately try to update the NeoPixel string again with the correct data.

I hope to have an article up by next week!

bigjosh commented 9 years ago

I just updated the code so that the timing now should work correctly with any compiler.

ajfisher commented 9 years ago

Excellent - will give that a crack this week and report back on how it goes.

On Sun, Mar 15, 2015 at 8:33 AM Josh Levine notifications@github.com wrote:

I just updated the code so that the timing now should work correctly with any compiler.

— Reply to this email directly or view it on GitHub https://github.com/bigjosh/SimpleNeoPixelDemo/issues/3#issuecomment-80726482 .