I just started with WS2811, I found 2 libraries to control it which are FastLed and Adafruit Neonpixel.
I want to know how the data moves from a led to another but when reading these two libraries, I cannot figure it out.
Can anyone help me with writing a short code with using only digitalWrite, analogWrite, delay function to set color RGB (127, 50, 70) for 10 leds. Initial states of these 10 leds are all white color. The delay time for each setting is 0.5s.
Yes, but I want to understand the theory of it because I want to control the led strip WS2811 by another MCU not Arduino. I want to rewrite the library FastLed & Neonpixel to reduce the size of codes.
The LEDs needs very fast pulses at less than 1us in width, variations in the width defines if it 0 or 1. One chip needs 24 pulses, that is the same as 24 bits (8 for each color). When you have more chips in series you need more pulses, 24 for each chip. That means with 10 led you need to generate 240 pulses each better than with us precision.
The datasheets for each chip lists the precise timing requirements, but is is usual about 400 and 800us for 0 and 1, the low uses the opposite time, but is usually not very critical. To signal the end of bits you simply hold the dataline low for some time (50us) and all the chips will update the led output.
On the Atmega chips it is fairly tricky to write the code because it can only do up to 16 assembler instructions in a us, on faster processor it gets easier, but watch out for interrupts!
daonguyen3154:
Yes, but I want to understand the theory of it because I want to control the led strip WS2811 by another MCU not Arduino. I want to rewrite the library FastLed & Neonpixel to reduce the size of codes.
Thanks for your replies.
I'm not actually sure which type of 3 colour serially fed LEDs tape I used but I did this on a PIC using the SPI register to output the data. Set the SPI clock speed such that the time for it to send a complete byte is the same duration that the LEDs need to receive 2 bits. I encoded 2 bits to be sent as 8 bits to load into the SPI register as follows:
For a 0 I put 0001 into the register and for a 1 I put 0111 into the register. As each bit to transmit is encoded as 4 bits to the SPI Tx register you send 2 bits at a time. However, timings are tight and you have to have the next byte ready to load into the SPI register as soon as the last one has shifted out.
This works because using 0001 and 0111 gives the different pulse widths the LEDs see as 0 and 1.
Here's the function that generates the data for the SPI register, which I am offering 'as is' with no support. This was written for a PIC18F46K22, but I would think the same or similar would work for others. Of course you've not said which micro-controller you are using (or I missed it), so this might not be what you need, but it will at least give you something to think about.
void LED_output() {
unsigned char i;
unsigned char SPI_byte;
for (i = 0; i < LED_number; i++) {
if (LED[i].G & 0x40) SPI_byte = 0x0e; //Byte order is GRB because that is what the LEDs require
else SPI_byte = 0x08; //Bit order is 6, 7, 4, 5, 2, 3, 0, 1
if (LED[i].G & 0x80) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].G & 0x10) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].G & 0x20) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].G & 0x04) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].G & 0x08) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].G & 0x01) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].G & 0x02) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].R & 0x40) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].R & 0x80) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].R & 0x10) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].R & 0x20) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].R & 0x04) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].R & 0x08) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].R & 0x01) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].R & 0x02) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].B & 0x40) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].B & 0x80) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].B & 0x10) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].B & 0x20) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].B & 0x04) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].B & 0x08) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
if (LED[i].B & 0x01) SPI_byte = 0x0e;
else SPI_byte = 0x08;
if (LED[i].B & 0x02) SPI_byte |= 0xe0;
else SPI_byte |= 0x80;
SSP2BUF = SPI_byte;
__delay_us(SPI_delay_us);
}
//INTCONbits.GIE = 1;
//PIE1bits.RC1IE = 1;
}
Have a look at the Adafruit_NeoPixel library, the assembly language is fairly straightforward and well documented, with options for various CPU speeds. The FastLED library gets a bit more cryptic, unless you are extremely familiar with preprocessor directives for the compiler, and is spread out amount multiple files making it harder to follow.
The data movement from one LED to another is fairly simple, each LED needs 24 bits for itself, so it takes the first 24 bits of data it receives as its own data, then any additional data is passed through to its output data pin. If you look at the data stream on a logic analyzer you would see the data at each successive LED is 24 bits shorter than the previous LED, until the last LED in the string generates no data on its output.
HKJ-lygte:
The LEDs needs very fast pulses at less than 1us in width, variations in the width defines if it 0 or 1. One chip needs 24 pulses, that is the same as 24 bits (8 for each color). When you have more chips in series you need more pulses, 24 for each chip. That means with 10 led you need to generate 240 pulses each better than with us precision.
The datasheets for each chip lists the precise timing requirements, but is is usual about 400 and 800us for 0 and 1, the low uses the opposite time, but is usually not very critical. To signal the end of bits you simply hold the dataline low for some time (50us) and all the chips will update the led output.
On the Atmega chips it is fairly tricky to write the code because it can only do up to 16 assembler instructions in a us, on faster processor it gets easier, but watch out for interrupts!