Driving WS2812B by Nuvoton M031 series SPI

Enes ALTUN
4 min readOct 30, 2021

WS2812B is a 5050 LED that has internal controller. It supports non-return-to-zero communication mode. You can control hundreds of RGB LEDs by 24bit serial interface up to 800Kbps. If you want to drive WS2812B strips by MCU, there are a few different methods. But here we will drive them by using SPI method.

Firstly we should learn how we will organise ‘1’ and ‘0’ bits. Cause in serial communations, time of data levels have meanings. So when we check the datasheet of WS2812, we can see period of a bit is about 1.25us. If we keep high on level 1 for 0.85us and level 0 for 0.4us, it means this bit is ‘1’. But if we keep high on level 1 for 0.4us and level 0 for 0.85us, so it means this bit is ‘0’. We have to send 24bit data with this method. After sending 24bit data, we should keep data on level ‘0’ for above 50us. This means our communication lasts 1.25us X 24 x n (LED number) + 50us.

And we need to send 24 bits cascade for a LED. First 8bits of data means green, second 8bits of data means red and last 8bits of data means blue color.

So if we learnt driving protocol of WS2812B, lets check out SPI driving method by MCU.

As you see above image, we should send 3bit in SPI in exchange for 1bit in WS2812B representation. Thats why we should send 24bit for every 3 colors and 72bit for total color data.

Every 1bit of SPI lasts 0.4us. So we should set our SPI clock :

1/0.4us = 2.5MHz = 2500000 Hz

#define SPI_CLK_FREQ 2500000 // SPI clock frequency

#define LED_NUMBER 10 // LED number we use

SPI init must be :

/* Configure as a master, clock idle low, 24-bit transaction, drive output on falling clock edge and latch input on rising edge. */

SPI_Open(SPI0, SPI_MASTER, SPI_MODE_0,24, SPI_CLK_FREQ);

/* Enable the automatic hardware slave select function. Select the SS pin and configure as low-active. */

SPI_EnableAutoSS(SPI0, SPI_SS, SPI_SS_ACTIVE_LOW);

Then we should write a function which converts 8bit color data to 24bit SPI data.

unsigned int data_bit8_to_bit24(uint8_t data){
uint32_t conv_data=0;
int8_t x=0;
uint32_t bit0=4; //100
uint32_t bit1=6; //110

for(x=7;x>=0;x — ){
if (data&(1<<x))
conv_data=conv_data|(bit1<<(3*x));
else
conv_data=conv_data|(bit0<<(3*x));
}
return conv_data;
}

Now we should write a function to control any LED we choose. We should enter first LED number we should control, then green ratio, red ratio and blue ratio. So our function will be like below.

void send_led_commands(uint8_t Led_number, uint8_t G,uint8_t R,uint8_t B){
uint8_t led_counter=0;
uint32_t dataG,dataR,dataB=0;

dataG=data_bit8_to_bit24(G); //Transform 8bit green data to 24bit data
dataR=data_bit8_to_bit24(R); //Transform 8bit red data to 24bit data
dataB=data_bit8_to_bit24(B); //Transform 8bit blue data to 24bit data

for(led_counter=0;led_counter<Led_number;led_counter++){
SPI_WRITE_TX(SPI0,0x924924); //Send 0 bit turn off green color
SPI_WRITE_TX(SPI0, 0x924924); //Send 0 bit turn off red color
SPI_WRITE_TX(SPI0, 0x924924); //Send 0 bit turn off blue color
while(SPI_IS_BUSY(SPI0)); // wait for end of data sending
}

SPI_WRITE_TX(SPI0, dataG); // Send green color code
SPI_WRITE_TX(SPI0, dataR); // Send red color code
SPI_WRITE_TX(SPI0, dataB); // Send blue color code
while(SPI_IS_BUSY(SPI0)); //wait for end of data sending

CLK_SysTickDelay(200); //wait for 200us for reset code
}

By this code block above, we can control every single LED on strip. For tests, i bought 10pcs LED and write a simple function which goes red color to green color.

while(1){

for(counter=LED_NUMBER-1;counter>=0;counter — ){
send_led_commands(counter,255-counter*28,counter*28,0);
CLK_SysTickDelay(100000); //wait 100 miliseconds
}

CLK_SysTickDelay(1000000); //wait 3 seconds
CLK_SysTickDelay(1000000);
CLK_SysTickDelay(1000000);

send_array_clear(); //Turn off all LEDs on strip

CLK_SysTickDelay(1000000); //wait 1 second

}

Result :

we can change color as we want.

You can find sample code on my GitHub account.

Some fun with WS2812B strips

I really like making projects with LEDs. Cause visual projects are in demand by every people. However i love reading books or work in soft light. Fireplaces and candles are good light sources for my mood. They chill most people. Especially on rainy days :)

So i wanted to make a DIY candle with WS2812B strip. I used 33 pcs LED for this. And finally i made an awesome electronic candle. Also it is clean and smokeless. You can see video below.

--

--

Enes ALTUN

“Learn from yesterday, live for today, hope for tomorrow.”