How to control a single WS2812B RGB SMD LED (Neopixel)

Thread Starter

q12x

Joined Sep 25, 2015
1,658
-A year or so ago... my original intention was to buy a simple SMD RGB led, with a common gnd and 3 positive pins for each led inside, very simple to command. I thought WS2812B on aliexpres was the correct thing, having 4 pins by the look of it and by the name "5050 SMD WS2812 Individually Addressable Digital RGB LED". After I receive them, I store the leds and didnt touch them until yesterday. But nothing worked in the beginning. I started to understand it's pin configuration from it's datasheet : https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf . It still didn't work even if I power it correctly, adding a 1k and then 10k on the + side, since it was very bright after I slide or quick touch the positive pin (with the resistor on it) with pin 4 (DIN) of this chip. So pretty much I made it work !!! Hurray. But the color changes Randomly, as I contact the DIN wire. If I put the DIN wire to the gnd, nothing happens. It only accepts bursts of positive signals from what I can figure out with my analog tests.
-I only buy this type as 100pcs pack : https://www.aliexpress.com/item/32881704200.html?spm=a2g0s.9042311.0.0.27424c4d9H8lrz .
-But, they can come also already mounted on a role strip (that I dont have) with connectors already printed on it and they can be commanded from only 1 pin (the DIN pin), all 500 leds in series from the strip they come assembled.
-All the tutorials out there are using arduino to command it. I have an arduino uno and I try it. I downloaded 2 libraries and try them out. It didnt work for me. It even changed the COM port from my initial setting COM8 into COM1, and I had some FUN time figure that out. Now is back in bizniz on COM8 as it is working fine for me, but I can not use those libraries.
-My original intention is to command these leds from an analog input. I only want (for the moment) to power them up and command their color and intensity, with analogue means. Simple and to the basics. Just to lit 1 led to an interesting color and leave it as that. I am able to command their intensity with my 10k resistor on the positive rail, so far, which is good. But the color is more hard... by looking on the datasheet, it seems they require signals between 400ns to 800ns. Which the arduino can not deliver such small signals, Ive looked for it, and the lowest delay it has, is the delayMicroseconds(x) function. Ive also google for "arduino delay nanoseconds" and I got the answers, that it is not possible. I wonder now, how those libraries are possible commanding these leds from arduino...very strange.
I've also made a couple of small testing programs in arduino without any "helpful" libraries, but none worked because it needs these nano seconds commands signals.
-I only used a single (one 1) rgb led so far in all my tests.
-The only practical solution I can see and do, is :
1- program my dinky PIC 12F508 a burst of signal between 400ns to 800ns, like they say in the datasheet and also provide this wave form , I guess :
1630059934991.png
At this part, I have trouble understand it, for me it appears very sketchy instructions. But is all that I got, so... I will walk on it as far as I can.
2- use a 555 timer or even a flipflop, to generate that very fast waveform.
-Again, right now, I can change the color, by touching the DIN wire to the + rail (through the 10k) , but the colors are random and sometime they change ,sometime they not. I guess, my touching the wires, I generate some interferences that are recorded as signal by its internal chip of the led. Like a bouncing button interference is what I am generating.
It is good so far because I managed to power the thing, lit it, and even controlling it. So... half of the road is done.
-What I am asking from you, if you have experience with this particular type of RGB led WS2812B, to directly guide my ass to the final working result. Ideally!! If you didnt worked with these specific components, then I am more than happy to read any suggestion you may have, since, I am quite out of good ideas, and my ideas are a bit too sophisticated to quickly try and im not sure if they are even on the correct path. If nothing else, they remain to be tried as a last resort. Until then, I am welcoming your help !
-Thank you !
 
Last edited:

BobTPH

Joined Jun 5, 2013
8,813
The WS2812 requires that you send 24 bits of digital data to operate it. The data is encoded in the length of pulses, which must come with strict timing characteristics. The 24 bits consist of a byte integer specifying the relative brightness of red, green, and blue.

When you operate a strip of them daisy chained via the DIN and DOUT pins, the fist 24 bits go to the first LED, the next to the second and so on.

I have written code in C for multiple PICs. It is highly dependent in the clock speed, which has to be at least 8M instructions per second to get consistent results. I will post the code in my next post, but be aware, it will not work as is with Arduino.

Bob
 

BobTPH

Joined Jun 5, 2013
8,813
Here is my code, written for PIC24;

Code:
void one()
{
    DATAOUT = 1;
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    DATAOUT = 0;
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
}

void zero()
{
    DATAOUT = 1;
    __asm("NOP");
    __asm("NOP");
    DATAOUT = 0;
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
    __asm("NOP");
}

void shift_out(unsigned char c)
{
    if (c & 0x80) one(); else zero();
    if (c & 0x40) one(); else zero();
    if (c & 0x20) one(); else zero();
    if (c & 0x10) one(); else zero();
    if (c & 0x08) one(); else zero();
    if (c & 0x04) one(); else zero();
    if (c & 0x02) one(); else zero();
    if (c & 0x01) one(); else zero();
}

void rgb(unsigned char r, unsigned char g, unsigned char b)
{
    shift_out(g);
    shift_out(r);
    shift_out(b);
}
You call the rgb function once for each LED in the string, then pause for at least 50 usec to end the data sequence and latch the new data.

Note that the one and zero functions are critical, each of the lines in them must execute in 1 instruction cycle at 8 MHz.

Also note that the shift_out function is written that way, without a loop, to be fast enough not to mess up the timing.

And DATAOUT is a macro set to whatever is used to write to the port and pin that is connected to DIN.

Similar code has been used on PIC16 as well.

Good luck!

Bob
 

Thread Starter

q12x

Joined Sep 25, 2015
1,658
First, thank you for your response, mister @BobTPH . I know some things but to a point.
- Please tell me what is your programming compiler?
I used in the past PIC C, Pickit2, Mplab v8.46, Arduino, and a tiny bit of assembler.
I only want to drive 1 single led. Digital control is the only way?
 

du00000001

Joined Nov 10, 2020
117
Remove this silly 1k (or 10 k) series resistor from the positive supply pin of the WS2812B! This is not the way it is meant to be operated (and might even damage the DIN pin on the long run).

Take your fancy Arduino and look for some demo application (e.g. this one https://funduino.de/nr-17-ws2812-neopixel - sorry, this one is in German). Follow the instructions to the letter, copy the sketch code, where necessary install the libraries required and then start experimenting with controlling the output per varying some analog input voltage.
For such "experiments" the Arduino is really fine. I assume you had this 1k/10k resistor in series with the WS2812B - exactly the point that rendered an otherwise perfect setup non-working. And show me only ONE Arduino example that has a 10 k resistor in series with the WS2812B's supply. (In series with the DIN pin: yes - as some kind of the protection. But not in series with the pos. supply pin.)
 

BobTPH

Joined Jun 5, 2013
8,813
First, thank you for your response, mister @BobTPH . I know some things but to a point.
- Please tell me what is your programming compiler?
I used in the past PIC C, Pickit2, Mplab v8.46, Arduino, and a tiny bit of assembler.
I only want to drive 1 single led. Digital control is the only way?
My code was compiled with XC8 and XC16.

If you are using Arduino, you could write the equivalent for the Arduino compiler, or, as the previous poster said, find the code on the internet.

And yes, digital control is the only way to operate these.

I posted my code in hopes it might get you to understand what is needed and do the same yourself.

Bob
 

ElectricSpidey

Joined Dec 2, 2017
2,758
If you do want to learn about driving addressable LEDs, do yourself a big favor and start with the 2 line control ones, not the single line ones.
 

Thread Starter

q12x

Joined Sep 25, 2015
1,658
As promised, my progress:
Alright, after a quick german lesson, from the link before, given by mister @du00000001 (I shamlessly used google Translate, but I was amazed how well it translated into english !!! good for them) I did installed a new library into arduino, but this time through it's manager:
In Arduino: "Sketch> Include library> Manage libraries ..."
search for “Adafruit NeoPixel” and install it.
That's pretty much what I did. Before your help, I did installed 2 other libraries but manually and from youtube. Those libraries must be outdated or just not as compatible as I might want to believe.
I tried the most simple examples I could find from this new library (from it's total of 9)
1630077331821.png
and I further simplify the code of one that started to actually work (but on it's own logic).
So I extracted and filtered a very simple code that is circling between RGB and White light from this one single RGB chip !!! I call this an immense progress and I thank you from my hearth. At least it confirms they work properly.
Also here is my quick and dirty test program that is doing exactly what I wanted in the first place:

C#:
#include <Adafruit_NeoPixel.h>

// Which pin on the Arduino is connected to the NeoPixels?
#define LED_PIN 6
// How many NeoPixels are attached to the Arduino?
#define LED_COUNT 1
// NeoPixel brightness, 0 (min) to 255 (max)
#define BRIGHTNESS 50 // Set BRIGHTNESS to about 1/5 (max = 255)

// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800);

void setup() {
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(BRIGHTNESS);

 // colorWipe(strip.Color(255,  255,   255)     , 50); //color test
}


void loop() {
  RGBplay();
}


int wait = 1000;
void RGBplay()
{
    // Fill along the length of the strip in various colors...
  colorWipe(strip.Color(255,  0,  0)     , 50); // Red
    delay (wait);
  colorWipe(strip.Color(  0,255,  0)     , 50); // Green
    delay(wait);
  colorWipe(strip.Color(  0,  0,255)     , 50); // Blue
    delay(wait);
  colorWipe(strip.Color(255,255,255)     , 50);// RGB white
//colorWipe(strip.Color(  0,  0,  0, 255), 50); // True white (not RGB white)
    delay(wait);
}


void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}
 

Thread Starter

q12x

Joined Sep 25, 2015
1,658
I personally, consider Arduino package, as a quick Digital test to get the idea of something.
But to actually implement in a stand alone product, by itself, that's really the end goal I'm after. And the only way I know how is with PIC's. And as mister @BobTPH kindly helped me with his code, I must step on his steps...hopefully. This is a bit over my head, but... I'll try my best, and hopefully with your help on some more trivial code than what you wrote. Because I did use mplab before, but not really that much. I know "something", but not enough, I still stumble in it. I do have PIC C which is quite good, but I think I must convert "somehow" your code into that. Hmmm, it's an option. i'll update you on this last track as well.
All I have ready to use in my electronic arsenal, are these 100pcs Neopixels, I think 200pcs of pic 12f508 (smd and DIP8), my trusty Pickit2 and its prototype board. And the software, all that I mentioned already PIC C, Pickit2, Mplab v8.46, Arduino, and a tiny bit of assembler. I also have MPLAB X in which you actually program with your XC8 and XC16. compilers. Im not sure if my 12F508 is even compatible with MPLAB X, because I tried it before but... problems. It worked very well for me, this PIC C which is my direction to try into it, next.
Thank you again, great results so far ! Super Awesome.
 

BobTPH

Joined Jun 5, 2013
8,813
I don't think 12f508 is fast enough. It’s max frequency is 20 MHz, which results in a 5 MHz instruction clock. You need an 8 MHz instruction clock. Also, you would need a crystal to run it at full speed.

A newer pic is the PIC12F1840, which can run at 32 MHz without a crystal, giving you an 8 MHz instruction clock.

Bob
 

du00000001

Joined Nov 10, 2020
117
I personally, consider Arduino package, as a quick Digital test to get the idea of something.
But to actually implement in a stand alone product, by itself, that's really the end goal I'm after.
<...snipped...>
Consider the Arduino (Uno) an ATmega128 with some convenience built around it.
It should be possible to create a generic ATmega128 project in MPLAB X (or Atmel Studio) and port the Arduino implementation to the generic project. Which would still use the same compiler, so inter-compiler porting issues should not rise.
While I love PIC16s very much (their oh-chip peripherals are way superior), the ATmega on the Arduino is twice as fast (16 MIPS vs. 8 MIPS for the fastest PIC16s) and capable to run even faster (20 MIPS). PICs faster than 8 MIPS are available (not in the PIC1x families, but as PIC24s and dsPIC33s), but these play in another league.

While it should be possible to implement a timing with T0H == T1L == 0.4 µs and T1H == T0L == 0.4 µs, issuing this from a device with an instruction cycle of 0.2 µs might prove too ambitious (2/4 instructions per time increment - not enough to implement a variable timing). An 8 MIPS device (instruction cycle 0.125 µs) should be able to implement 0.375/0.500 and 0.750/0.875 µs times - any combination within the timing limits of the WS2812B. (Measure the Arduino's timing to get a quick assessment of what it's generating!).
So the PIC12F508 might be able to create a very limited number of different colors - the timing for each hard-coded as a sequence of assembly instructions - but nothing dynamic. Switching to an 8 MIPS or 16 MIPS device greatly improves your options.
 

Ian0

Joined Aug 7, 2020
9,671
If your microcontroller has a SPI output you can use it to generate the required waveform.
If you send 0b110 the LED reads it as a 1 and if you send 0b100 it reads it as a zero.
Set your SPI to 12-bits and then you can output 4 bits of data to the LED.
(I prefer the 2-line control versions as well)
 

BobTPH

Joined Jun 5, 2013
8,813
If your microcontroller has a SPI output you can use it to generate the required waveform.
If you send 0b110 the LED reads it as a 1 and if you send 0b100 it reads it as a zero.
Set your SPI to 12-bits and then you can output 4 bits of data to the LED.
(I prefer the 2-line control versions as well)
Yrs, I believe that could work, have never tried it since the simple code I posted earlier has worked fine for me.

Bob
 

BobTPH

Joined Jun 5, 2013
8,813
An 8 MIPS device (instruction cycle 0.125 µs) should be able to implement 0.375/0.500 and 0.750/0.875 µs times - any combination within the timing limits of the WS2812B. (
Yep, that is exactly what my code does., and it has worked flawlessly on multiple devices using pic16 and pic24.

I tried to do it at 4MHz, but the timings were too far off and it partially worked, but was unreliable. Maybe I will try 5Mhz later.

Bob
 

du00000001

Joined Nov 10, 2020
117
Yep, that is exactly what my code does., and it has worked flawlessly on multiple devices using pic16 and pic24.

I tried to do it at 4MHz, but the timings were too far off and it partially worked, but was unreliable. Maybe I will try 5Mhz later.

Bob
I'd expect that 4 MIPS with 500/750 µs timing should work. But with that you're limited to a selection of hard-coded sequences as there would just be enough power for a SetBit/ClearBit followed by 1 or 2 NOPs (thinking in PIC16 - SetBit/ClearBit might even take 2 cycles on some architectures). Whether such a limited operation might make sense: depends on the application.
 
Top