diff --git a/Inc/ws2812b.h b/Inc/ws2812b.h index ff8eb2f..f8541e4 100644 --- a/Inc/ws2812b.h +++ b/Inc/ws2812b.h @@ -11,20 +11,38 @@ #ifndef WS2812B_H_ #define WS2812B_H_ -// For 6 MHz SPI + DMA +/* Includes */ +#include -#define WS2812B_LEDS 35 +/* Defintions */ +#define WS2812B_LEDS (1) -typedef struct ws2812b_color { - uint8_t red, green, blue; +/* Data Structures */ +typedef union __attribute__((packed, aligned(4))) ws2812b_color_u { + struct __attribute__((packed, aligned(4))) rgbx_s { + uint8_t green; + uint8_t red; + uint8_t blue; + uint8_t x; + } rgbx; + struct __attribute__((packed, aligned(4))) rgb_s { + uint8_t _pad; + uint8_t green; + uint8_t red; + uint8_t blue; + } rgb; + uint32_t u32; + uint8_t u8[4]; } ws2812b_color; +/* Function Prototypes */ void WS2812B_Init(SPI_HandleTypeDef * spi_handler); -void WS2812B_SetDiodeColor(int16_t diode_id, uint32_t color); -void WS2812B_SetDiodeColorStruct(int16_t diode_id, ws2812b_color color); -void WS2812B_SetDiodeRGB(int16_t diode_id, uint8_t R, uint8_t G, uint8_t B); -void WS2812B_SetDiodeHSV(int16_t diode_id, uint16_t Hue, uint8_t Saturation, uint8_t Brightness); -uint32_t WS2812B_GetColor(int16_t diode_id); +void WS2812B_SetDiodeColor(uint16_t diode_id, uint32_t color); +void WS2812B_SetDiodeColorStruct(uint16_t diode_id, ws2812b_color color); +void WS2812B_SetDiodeRGB(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b); +void WS2812B_SetDiodeRGBX(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b, uint8_t x); +void WS2812B_SetDiodeHSV(uint16_t diode_id, uint16_t hue, uint8_t sat, uint8_t brt); +uint32_t WS2812B_GetColor(uint16_t diode_id); uint8_t* WS2812B_GetPixels(void); void WS2812B_Refresh(); diff --git a/Inc/ws2812b_fx.h b/Inc/ws2812b_fx.h index a27e322..628253f 100644 --- a/Inc/ws2812b_fx.h +++ b/Inc/ws2812b_fx.h @@ -14,8 +14,8 @@ #ifndef WS2812B_FX_H_ #define WS2812B_FX_H_ -#define DEFAULT_COLOR 0x00FF000000 -#define NUM_COLORS 3 +#define DEFAULT_COLOR 0x00F0000000 +#define NUM_COLORS 4 #define SPEED_MIN 10 #define DEFAULT_SPEED 150 diff --git a/Src/ws2812b.c b/Src/ws2812b.c index 4835565..690e0e8 100644 --- a/Src/ws2812b.c +++ b/Src/ws2812b.c @@ -8,21 +8,68 @@ * mateusz@msalamon.pl */ +/* Includes */ #include "main.h" #include "spi.h" #include "dma.h" #include "gpio.h" #include "math.h" - #include "ws2812b.h" -#define zero 0b11000000 -#define one 0b11111000 +/* Definitions */ +#define ZERO (0b11000000) +#define ONE (0b11111000) +#define WORD_SIZE (32U) +#define BUFFER_SIZE (WORD_SIZE * 2) + +/* Macros */ +#define return_if_fail(cond) if(!(cond)) { return; } +#define return_val_if_fail(cond, val) if(!(cond)) { return (val); } +#define return_null_if_fail(cond) return_val_if_fail((cond), NULL) + +/* Private Constants */ +static const uint8_t _sineTable[256] = { + 128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173, + 176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215, + 218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244, + 245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255, + 255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246, + 245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220, + 218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179, + 176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131, + 128,124,121,118,115,112,109,106,103,100, 97, 93, 90, 88, 85, 82, + 79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40, + 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11, + 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, + 10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, + 37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76, + 79, 82, 85, 88, 90, 93, 97,100,103,106,109,112,115,118,121,124}; + +static const uint8_t _gammaTable[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, + 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, + 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, + 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, + 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28, 29, 29, + 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 75, + 76, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, + 97, 99,100,102,103,105,106,108,109,111,112,114,115,117,119,120, + 122,124,125,127,129,130,132,134,136,137,139,141,143,145,146,148, + 150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180, + 182,184,186,188,191,193,195,197,199,202,204,206,209,211,213,215, + 218,220,223,225,227,230,232,235,237,240,242,245,247,250,252,255}; +/* Public Global Variables */ SPI_HandleTypeDef *hspi_ws2812b; ws2812b_color ws2812b_array[WS2812B_LEDS]; -static uint8_t buffer[48]; +/* Private Global Variables */ +static uint8_t buffer[BUFFER_SIZE]; static uint16_t CurrentLed; static uint8_t ResetSignal; @@ -31,35 +78,40 @@ void WS2812B_Init(SPI_HandleTypeDef * spi_handler) hspi_ws2812b = spi_handler; } -void WS2812B_SetDiodeColor(int16_t diode_id, uint32_t color) +void WS2812B_SetDiodeColor(uint16_t diode_id, uint32_t color) { - if(diode_id >= WS2812B_LEDS || diode_id < 0) return; - ws2812b_array[diode_id].red = ((color>>16)&0x000000FF); - ws2812b_array[diode_id].green = ((color>>8)&0x000000FF); - ws2812b_array[diode_id].blue = (color&0x000000FF); + return_if_fail(diode_id < WS2812B_LEDS); + ws2812b_array[diode_id].u32 = color; } -void WS2812B_SetDiodeColorStruct(int16_t diode_id, ws2812b_color color) +void WS2812B_SetDiodeColorStruct(uint16_t diode_id, ws2812b_color color) { - if(diode_id >= WS2812B_LEDS || diode_id < 0) return; + return_if_fail(diode_id < WS2812B_LEDS); ws2812b_array[diode_id] = color; } -void WS2812B_SetDiodeRGB(int16_t diode_id, uint8_t R, uint8_t G, uint8_t B) +void WS2812B_SetDiodeRGB(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b) +{ + return_if_fail(diode_id < WS2812B_LEDS); + ws2812b_array[diode_id].rgb.red = r; + ws2812b_array[diode_id].rgb.green = g; + ws2812b_array[diode_id].rgb.blue = b; +} + +void WS2812B_SetDiodeRGBX(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b, uint8_t x) { - if(diode_id >= WS2812B_LEDS || diode_id < 0) return; - ws2812b_array[diode_id].red = R; - ws2812b_array[diode_id].green = G; - ws2812b_array[diode_id].blue = B; + return_if_fail(diode_id < WS2812B_LEDS); + ws2812b_array[diode_id].rgbx.red = r; + ws2812b_array[diode_id].rgbx.green = g; + ws2812b_array[diode_id].rgbx.blue = b; + ws2812b_array[diode_id].rgbx.x = x; } -uint32_t WS2812B_GetColor(int16_t diode_id) +uint32_t WS2812B_GetColor(uint16_t diode_id) { - uint32_t color = 0; - color |= ((ws2812b_array[diode_id].red&0xFF)<<16); - color |= ((ws2812b_array[diode_id].green&0xFF)<<8); - color |= (ws2812b_array[diode_id].blue&0xFF); - return color; + return_val_if_fail(diode_id < WS2812B_LEDS, 0); + + return ws2812b_array[diode_id].u32; } uint8_t* WS2812B_GetPixels(void) @@ -73,59 +125,61 @@ uint8_t* WS2812B_GetPixels(void) // Saturation 0-255 // Birghtness(Value) 0-255 // -void WS2812B_SetDiodeHSV(int16_t diode_id, uint16_t Hue, uint8_t Saturation, uint8_t Brightness) +void WS2812B_SetDiodeHSV(uint16_t diode_id, uint16_t hue, uint8_t sat, uint8_t brt) { - if(diode_id >= WS2812B_LEDS || diode_id < 0) return; - uint16_t Sector, Fracts, p, q, t; + uint16_t sector, fract, p, q, t; - if(Saturation == 0) + return_if_fail(diode_id < WS2812B_LEDS); + + if(sat == 0) { - ws2812b_array[diode_id].red = Brightness; - ws2812b_array[diode_id].green = Brightness; - ws2812b_array[diode_id]. blue = Brightness; + ws2812b_array[diode_id].rgb.red = brt; + ws2812b_array[diode_id].rgb.green = brt; + ws2812b_array[diode_id].rgb.blue = brt; } else { - if(Hue >= 360) Hue = 359; + if(hue >= 360) hue = 359; - Sector = Hue / 60; // Sector 0 to 5 - Fracts = Hue % 60; - p = (Brightness * (255 - Saturation)) / 256; - q = (Brightness * (255 - (Saturation * Fracts)/60)) / 256; - t = (Brightness * (255 - (Saturation * (59 - Fracts))/60)) / 256; + sector = hue / 60; // Sector 0 to 5 + fract = hue % 60; + p = (brt * (255 - sat)) / 256; + q = (brt * (255 - (sat * fract) / 60)) / 256; + t = (brt * (255 - (sat * (59 - fract)) / 60)) / 256; - switch(Sector) + switch(sector) { case 0: - ws2812b_array[diode_id].red = Brightness; - ws2812b_array[diode_id].green = (uint8_t)t; - ws2812b_array[diode_id]. blue = (uint8_t)p; + ws2812b_array[diode_id].rgb.red = brt; + ws2812b_array[diode_id].rgb.green = (uint8_t)t; + ws2812b_array[diode_id].rgb.blue = (uint8_t)p; break; case 1: - ws2812b_array[diode_id].red = (uint8_t)q; - ws2812b_array[diode_id].green = Brightness; - ws2812b_array[diode_id]. blue = (uint8_t)p; + ws2812b_array[diode_id].rgb.red = (uint8_t)q; + ws2812b_array[diode_id].rgb.green = brt; + ws2812b_array[diode_id].rgb.blue = (uint8_t)p; break; case 2: - ws2812b_array[diode_id].red = (uint8_t)p; - ws2812b_array[diode_id].green = Brightness; - ws2812b_array[diode_id]. blue = (uint8_t)t; + ws2812b_array[diode_id].rgb.red = (uint8_t)p; + ws2812b_array[diode_id].rgb.green = brt; + ws2812b_array[diode_id].rgb.blue = (uint8_t)t; break; case 3: - ws2812b_array[diode_id].red = (uint8_t)p; - ws2812b_array[diode_id].green = (uint8_t)q; - ws2812b_array[diode_id]. blue = Brightness; + ws2812b_array[diode_id].rgb.red = (uint8_t)p; + ws2812b_array[diode_id].rgb.green = (uint8_t)q; + ws2812b_array[diode_id].rgb.blue = brt; break; case 4: - ws2812b_array[diode_id].red = (uint8_t)t; - ws2812b_array[diode_id].green = (uint8_t)p; - ws2812b_array[diode_id]. blue = Brightness; + ws2812b_array[diode_id].rgb.red = (uint8_t)t; + ws2812b_array[diode_id].rgb.green = (uint8_t)p; + ws2812b_array[diode_id].rgb.blue = brt; break; - default: // case 5: - ws2812b_array[diode_id].red = Brightness; - ws2812b_array[diode_id].green = (uint8_t)p; - ws2812b_array[diode_id]. blue = (uint8_t)q; + case 5: + default: + ws2812b_array[diode_id].rgb.red = brt; + ws2812b_array[diode_id].rgb.green = (uint8_t)p; + ws2812b_array[diode_id].rgb.blue = (uint8_t)q; break; } } @@ -136,11 +190,10 @@ void WS2812B_Refresh() CurrentLed = 0; ResetSignal = 0; - for(uint8_t i = 0; i < 48; i++) + for(uint8_t i = 0; i < BUFFER_SIZE; i++) buffer[i] = 0x00; - HAL_SPI_Transmit_DMA(hspi_ws2812b, buffer, 48); // Additional 3 for reset signal + HAL_SPI_Transmit_DMA(hspi_ws2812b, buffer, BUFFER_SIZE); while(HAL_DMA_STATE_READY != HAL_DMA_GetState(hspi_ws2812b->hdmatx)); - } void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi) @@ -149,7 +202,7 @@ void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi) { if(!ResetSignal) { - for(uint8_t k = 0; k < 24; k++) // To 72 impulses of reset + for(uint8_t k = 0; k < WORD_SIZE; k++) { buffer[k] = 0x00; } @@ -163,35 +216,14 @@ void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi) } else { - uint8_t j = 0; - //GREEN - for(int8_t k=7; k>=0; k--) - { - if((ws2812b_array[CurrentLed].green & (1<=0; k--) + uint8_t i = 0; + for(int8_t j = WORD_SIZE - 1; j >= 0; j--) { - if((ws2812b_array[CurrentLed].red & (1<=0; k--) - { - if((ws2812b_array[CurrentLed].blue & (1<=0; k--) - { - if((ws2812b_array[CurrentLed].green & (1<=0; k--) - { - if((ws2812b_array[CurrentLed].red & (1<=0; k--) + uint8_t i = WORD_SIZE; + for(int8_t j = WORD_SIZE - 1; j >= 0; j--) { - if((ws2812b_array[CurrentLed].blue & (1<= NUM_COLORS) return FX_ERROR; - *r = mColor_w[id].red; - *g = mColor_w[id].green; - *b = mColor_w[id].blue; + *r = mColor_w[id].rgb.red; + *g = mColor_w[id].rgb.green; + *b = mColor_w[id].rgb.blue; return FX_OK; } @@ -674,16 +670,14 @@ void WS2812BFX_HSVtoRGB(uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g // void WS2812BFX_SetColorHSV(uint8_t id, uint16_t h, uint8_t s, uint8_t v) { - WS2812BFX_HSVtoRGB(h, s, v, &mColor_w[id].red, &mColor_w[id].green, &mColor_w[id].blue); - mColor[id] = ((mColor_w[id].red<<16)|(mColor_w[id].green<<8)|mColor_w[id]. blue); + WS2812BFX_HSVtoRGB(h, s, v, &mColor_w[id].rgb.red, &mColor_w[id].rgb.green, &mColor_w[id].rgb.blue); + mColor[id] = ((mColor_w[id].rgb.red<<16)|(mColor_w[id].rgb.green<<8)|mColor_w[id].rgb.blue); } void WS2812BFX_SetColor(uint8_t id, uint32_t c) { mColor[id] = c; - mColor_w[id].red = ((c>>16)&0x000000FF); - mColor_w[id].green = ((c>>8)&0x000000FF); - mColor_w[id].blue = (c&0x000000FF); + mColor_w[id].u32 = c; } FX_STATUS WS2812BFX_SetAll(uint16_t Segment, uint32_t c) @@ -691,7 +685,7 @@ FX_STATUS WS2812BFX_SetAll(uint16_t Segment, uint32_t c) if(Segment >= mSegments) return FX_ERROR; for(uint16_t i = 0; i < (Ws28b12b_Segments[Segment].IdStop - Ws28b12b_Segments[Segment].IdStart + 1); i++) { - WS2812B_SetDiodeRGB(Ws28b12b_Segments[Segment].IdStart + i, ((c>>16)&0xFF), ((c>>8)&0xFF), (c&0xFF)); + WS2812B_SetDiodeColor(Ws28b12b_Segments[Segment].IdStart + i, c); } return FX_OK; } @@ -878,7 +872,7 @@ void to_color(uint8_t from) uint16_t h; uint8_t s, v, r, g, b; - WS2812BFX_RGBtoHSV(Ws28b12b_Segments[mActualSegment].ModeColor_w[0].red, Ws28b12b_Segments[mActualSegment].ModeColor_w[0].green, Ws28b12b_Segments[mActualSegment].ModeColor_w[0].blue, &h, &s, &v); + WS2812BFX_RGBtoHSV(Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.red, Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.green, Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.blue, &h, &s, &v); if(from) WS2812BFX_HSVtoRGB(h, s - Ws28b12b_Segments[mActualSegment].CounterModeStep, v, &r, &g, &b); @@ -986,9 +980,9 @@ void mode_breath(void) else if(lum <= 150) delay = 11; // 5 else delay = 10; // 4 - uint8_t r = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].red * lum / 256; - uint8_t g = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].green * lum / 256; - uint8_t b = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].blue * lum / 256; + uint8_t r = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.red * lum / 256; + uint8_t g = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.green * lum / 256; + uint8_t b = Ws28b12b_Segments[mActualSegment].ModeColor_w[0].rgb.blue * lum / 256; WS2812BFX_SetAllRGB(mActualSegment, r, g, b); Ws28b12b_Segments[mActualSegment].CounterModeStep += 2;