I'm using Atmel's Atmega328P-PU and its CPU speed is set to 8MHz. This code actually worked fine when I 1st wrote it but I had to change some stuff in UART section so had to compile and flush it again but this time it was done from Linux using avrdude command line tools instead of Windows 7(which was on my friends PC and got deleted).
This is data timing diagram for WS2812B
Everything in code works fine except for sending '1' and '0' to LED and it happens in function set_leds_color. Weird thing is that if I leave the __builtin_avr_delay_cycles(); values as they were before my UART code updates (and as are shown in code) it always sets LED's color to white kind of like it would always send only '1' to led (255,255,255). Even if I set delay for '0' to __builtin_avr_delay_cycles(1) nothing changes - any color is displayed as white. Now the interesting part is that if I remove this delay for '0' so code become like this
Code: Select all
//send 0
else{
DATA_PORT = high_data;
DATA_PORT = low_data;
}
Here is my final code
Code: Select all
#include <avr/io.h>
#include <util/delay.h>
#define DATA_PORT PORTD
#define DATA_PIN PD2
#define DATA_DDR DDRD
/*
UART stuff
*/
void fill_array(unsigned int* arr, unsigned int color)
{
for(int i = 0; i < 8; ++i)
arr[i] = color & (1 << (7 - i));
}
void set_color(unsigned int* arr, unsigned int red, unsigned int green, unsigned int blue)
{
fill_array(arr, green);
fill_array(&arr[8], red);
fill_array(&arr[16], blue);
}
void set_leds_color(unsigned int red, unsigned int green, unsigned int blue)
{
//prepare 24 color bits to send to LED
unsigned int rgb_array[24];
set_color(rgb_array, red, green, blue);
int high_data = DATA_PORT | (1 << DATA_PIN);
int low_data = DATA_PORT & (~(1 << DATA_PIN));
for(int i = 0; i < 24; ++i){
//send 1
if(rgb_array[i]){
DATA_PORT = high_data;
__builtin_avr_delay_cycles(6); //1 clock cycle is 0.125us
DATA_PORT = low_data;
}
//send 0
else{
DATA_PORT = high_data;
__builtin_avr_delay_cycles(3); //1 clock cycle is 0.125us
DATA_PORT = low_data;
}
}
}
int main(void)
{
DATA_DDR = (1 << DATA_PIN);
DATA_PORT &= ~(1 << DATA_PIN);
initialize_UART();
while(1)
{
int color_code[3];
if(receive_color_from_uart(color_code))
{
set_leds_color(color_code[0], color_code[1], color_code[2]);
}
}
}