WS2812 LED bit code problem

Hello, I am currently finishing a WS2812 NeoPixel library which simplifies the process of controlling the addressable LEDs with a variety of functions but I am facing an issue.

The problem is that when sending the bits to the array of WS2812 LEDs (which each take 24-bits, one-byte for each color) both the 0 code and 1 code are being interpreted as 1 codes.

WS2812

Image referred - from WS2812 documentation

I have troubleshot the library trying to find any possible issues and have narrowed it down to the timing between codes sent to the W2812. As the transfer time window between the codes is nanoseconds:

I implemented port manipulation instead of digitalWrite() and used bitwise operators instead of bitRead() all to lower the amount of cycles needed to perform the same function.

However still all the bits received by the LEDs were 1 codes and so all LEDs were at maximum brightness (255) and so white.

My library works as follows:
neoByte[] is a byte array storing all values from (0 to 255) of each LED (red, green and blue) in the WS2812. So with 20 LEDs there would be 60 bytes. Which is changed dependant on the functions used.

To update the LEDs the function NeoPixel::NeoUpdate() is called

void NeoPixel::NeoUpdate() {
  for(uint16_t bytes = 0; bytes <= byteLength; bytes++) {
    for(uint8_t bitIndex = 0; bitIndex < 8; bitIndex++) {
      //NeoBit(bitRead(neoByte[bytes], bitIndex));
      NeoBit(neoByte[bytes] & char(pow(2, bitIndex)));
    }
  }
}

To send each bit individually of the array by using the NeoBit() function which uses port manipulation and __asm__ __volatile__ ("nop\n\t") to delay by cycles

Where byteLength in our example = 59 (60 - 1)

I believe the problem is the for loops and bitwise operation of NeoUpdate() already exceeding the 0 code length and so are interpreted as 1 codes.

Any help is greatly appreciated as I have not been able to fix the problem yet and suggestions on how to optimise the for loops

Helpful sources:
A video explaining WS2812 LEDs with C
WS2812 documentation

Why not use the FastLED.h library or Adafruit's Neopixel library, which handles the timing manipulation in assembly code to achieve the fast timing needed?

I was doing it as a project to create a library but then I stumbled across this problem, maybe I should just use an existing library, but I wanted to see if anyone has suggestions.

I know my code may seem primitive compared to assembly code but I was just creating a starting point to base the idea on

You aren’t making your own controller, LED strings, resistors, so why are you making your own library when there are proven versions already. ?

Why not make your own compiler ?

:thinking:

The big problem here is the timer 0 interrupt that keeps going off every 4uS, that disturbs the timing. The existing libraries get round this by disabling the interrupt when outputting the data.
The direct port access helps with the timing but is not much different to using assembler.

1 Like

Thanks for the suggestion I will start on making my own compiler :sweat_smile:

But I just wanted to try make a library for the WS2812 LEDs as project because I wanted some more specific functions

I have researched it a bit and I can see why it is being interpreted as a 1 code now, as you said the interrupt of 4uS is effecting the narrow time frame of each bit because even that is nearly three fold the cycle time of one bit.

Thank you

Use the existing libraries and modify them to your need.

Don’t reinvent the wheel.

1 Like

What kind of functions do you have in mind ?

Totally. If you look into those libraries you will find that the timing is so 'tight' that they use bit-bang methods in assembler, and use different code for different clock speed and boards. If your idea could be made to work, it would probably exist already.