Browse Source
			
			
			
			
				
		supports WS2811, WS2812, WS2813, SK6812, and SK6812RGBW families does not yet map colors correctly (e.g. WS2812 orders colors 'GRB' whereas others use RGB) removed ws2812b_fx codemaster
				 6 changed files with 260 additions and 2517 deletions
			
			
		| @ -1,51 +0,0 @@ | |||||||
| /*
 |  | ||||||
|  * ws2812b.h |  | ||||||
|  * |  | ||||||
|  *  The MIT License. |  | ||||||
|  *  Created on: 14.07.2017 |  | ||||||
|  *      Author: Mateusz Salamon |  | ||||||
|  *      www.msalamon.pl |  | ||||||
|  *      mateusz@msalamon.pl |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef WS2812B_H_ |  | ||||||
| #define WS2812B_H_ |  | ||||||
| 
 |  | ||||||
| /* Includes */ |  | ||||||
| #include <stdint.h> |  | ||||||
| 
 |  | ||||||
| /* Defintions */ |  | ||||||
| #define WS2812B_LEDS (1) |  | ||||||
| 
 |  | ||||||
| /* 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 ws2812_init(SPI_HandleTypeDef *hspi); |  | ||||||
| void ws2812_set_led_color_val(uint16_t diode_id, uint32_t color); |  | ||||||
| void ws2812_set_led_color(uint16_t diode_id, ws2812b_color color); |  | ||||||
| void ws2812_set_led_rgb(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b); |  | ||||||
| void ws2812_set_led_rgbx(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b, uint8_t x); |  | ||||||
| void ws2812_set_led_hsv(uint16_t diode_id, uint16_t hue, uint8_t sat, uint8_t value); |  | ||||||
| uint32_t ws2812_get_color(uint16_t diode_id); |  | ||||||
| uint8_t *ws2812_get_pixels(); |  | ||||||
| void ws2812_refresh(); |  | ||||||
| uint8_t sine8(uint8_t x); |  | ||||||
| uint8_t gamma8(uint8_t x); |  | ||||||
| 
 |  | ||||||
| #endif /* WS2812B_H_ */ |  | ||||||
| @ -1,153 +0,0 @@ | |||||||
| /*
 |  | ||||||
|  * ws2812b_fx.h |  | ||||||
|  * |  | ||||||
|  *  Library based on Harm Aldick's Arduino library |  | ||||||
|  *  https://github.com/kitesurfer1404/WS2812FX
 |  | ||||||
|  * |  | ||||||
|  *  The MIT License. |  | ||||||
|  *  Created on: 20.10.2018 |  | ||||||
|  *      Author: Mateusz Salamon |  | ||||||
|  *      www.msalamon.pl |  | ||||||
|  *      mateusz@msalamon.pl |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef WS2812B_FX_H_ |  | ||||||
| #define WS2812B_FX_H_ |  | ||||||
| 
 |  | ||||||
| /* Includes */ |  | ||||||
| #include <stdint.h> |  | ||||||
| 
 |  | ||||||
| /* Definitions */ |  | ||||||
| #define DEFAULT_COLOR (0x00F0000000) |  | ||||||
| #define NUM_COLORS    (4) |  | ||||||
| #define SPEED_MIN     (10) |  | ||||||
| #define DEFAULT_SPEED (150) |  | ||||||
| #define SPEED_MAX     (65535) |  | ||||||
| #define MODE_COUNT    (59) |  | ||||||
| #define DEFAULT_MODE  (0) |  | ||||||
| #define FADE_RATE     (2) |  | ||||||
| /* some common colors */ |  | ||||||
| #define RED        (0xFF0000U) |  | ||||||
| #define GREEN      (0x00FF00U) |  | ||||||
| #define BLUE       (0x0000FFU) |  | ||||||
| #define WHITE      (0xFFFFFFU) |  | ||||||
| #define BLACK      (0x000000U) |  | ||||||
| #define YELLOW     (0xFFFF00U) |  | ||||||
| #define CYAN       (0x00FFFFU) |  | ||||||
| #define MAGENTA    (0xFF00FFU) |  | ||||||
| #define PURPLE     (0x400080U) |  | ||||||
| #define ORANGE     (0xFF3000U) |  | ||||||
| #define PINK       (0xFF1493U) |  | ||||||
| 
 |  | ||||||
| /* Data Structures */ |  | ||||||
| typedef enum { |  | ||||||
| 	FX_OK    = 0, |  | ||||||
| 	FX_ERROR = 1 |  | ||||||
| } FX_STATUS; |  | ||||||
| typedef enum { |  | ||||||
| 	FX_MODE_STATIC, |  | ||||||
| 	FX_MODE_WHITE_TO_COLOR, |  | ||||||
| 	FX_MODE_BLACK_TO_COLOR, |  | ||||||
| 	FX_MODE_BLINK, |  | ||||||
| 	FX_MODE_BLINK_RAINBOW, |  | ||||||
| 	FX_MODE_STROBE, |  | ||||||
| 	FX_MODE_STROBE_RAINBOW, |  | ||||||
| 	FX_MODE_BREATH, |  | ||||||
| 	FX_MODE_COLOR_WIPE, |  | ||||||
| 	FX_MODE_COLOR_WIPE_INV, |  | ||||||
| 	FX_MODE_COLOR_WIPE_REV, |  | ||||||
| 	FX_MODE_COLOR_WIPE_REV_INV, |  | ||||||
| 	FX_MODE_COLOR_WIPE_RANDOM, |  | ||||||
| 	FX_MODE_COLOR_SWEEP_RANDOM, |  | ||||||
| 	FX_MODE_RANDOM_COLOR, |  | ||||||
| 	FX_MODE_SINGLE_DYNAMIC, |  | ||||||
| 	FX_MODE_MULTI_DYNAMIC, |  | ||||||
| 	FX_MODE_RAINBOW, |  | ||||||
| 	FX_MODE_RAINBOW_CYCLE, |  | ||||||
| 	FX_MODE_FADE, |  | ||||||
| 	FX_MODE_SCAN, |  | ||||||
| 	FX_MODE_DUAL_SCAN, |  | ||||||
| 	FX_MODE_THEATER_CHASE, |  | ||||||
| 	FX_MODE_THEATER_CHASE_RAINBOW, |  | ||||||
| 	FX_MODE_RUNNING_LIGHTS, |  | ||||||
| 	FX_MODE_TWINKLE, |  | ||||||
| 	FX_MODE_TWINKLE_RANDOM, |  | ||||||
| 	FX_MODE_TWINKLE_FADE, |  | ||||||
| 	FX_MODE_TWINKLE_FADE_RANDOM, |  | ||||||
| 	FX_MODE_SPARKLE, |  | ||||||
| 	FX_MODE_FLASH_SPARKLE, |  | ||||||
| 	FX_MODE_HYPER_SPARKLE, |  | ||||||
| 	FX_MODE_MULTI_STROBE, |  | ||||||
| 	FX_MODE_CHASE_WHITE, |  | ||||||
| 	FX_MODE_CHASE_COLOR, |  | ||||||
| 	FX_MODE_CHASE_RANDOM, |  | ||||||
| 	FX_MODE_CHASE_RAINBOW, |  | ||||||
| 	FX_MODE_CHASE_FLASH, |  | ||||||
| 	FX_MODE_CHASE_FLASH_RANDOM, |  | ||||||
| 	FX_MODE_CHASE_RAINBOW_WHITE, |  | ||||||
| 	FX_MODE_CHASE_BLACKOUT, |  | ||||||
| 	FX_MODE_CHASE_BLACKOUT_RAINBOW, |  | ||||||
| 	FX_MODE_RUNNING_COLOR, |  | ||||||
| 	FX_MODE_RUNNING_RED_BLUE, |  | ||||||
| 	FX_MODE_RUNNING_RANDOM, |  | ||||||
| 	FX_MODE_LARSON_SCANNER, |  | ||||||
| 	FX_MODE_COMET, |  | ||||||
| 	FX_MODE_FIREWORKS, |  | ||||||
| 	FX_MODE_FIREWORKS_RANDOM, |  | ||||||
| 	FX_MODE_MERRY_CHRISTMAS, |  | ||||||
| 	FX_MODE_FIRE_FLICKER, |  | ||||||
| 	FX_MODE_FIRE_FLICKER_SOFT, |  | ||||||
| 	FX_MODE_FIRE_FLICKER_INTENSE, |  | ||||||
| 	FX_MODE_CIRCUS_COMBUSTUS, |  | ||||||
| 	FX_MODE_HALLOWEEN, |  | ||||||
| 	FX_MODE_BICOLOR_CHASE, |  | ||||||
| 	FX_MODE_TRICOLOR_CHASE, |  | ||||||
| 	FX_MODE_QUADCOLOR_CHASE, |  | ||||||
| 	FX_MODE_ICU |  | ||||||
| } fx_mode; |  | ||||||
| 
 |  | ||||||
| /* Function Prototypes */ |  | ||||||
| FX_STATUS WS2812BFX_Init(uint16_t Segments); |  | ||||||
| FX_STATUS WS2812BFX_SegmentIncrease(void); |  | ||||||
| FX_STATUS WS2812BFX_SegmentDecrease(void); |  | ||||||
| uint8_t WS2812BFX_GetSegmentsQuantity(void); |  | ||||||
| 
 |  | ||||||
| void WS2812BFX_SysTickCallback(void); |  | ||||||
| void WS2812BFX_Callback(void); |  | ||||||
| 
 |  | ||||||
| FX_STATUS WS2812BFX_Start(uint16_t Segment); |  | ||||||
| FX_STATUS WS2812BFX_Stop(uint16_t Segment); |  | ||||||
| FX_STATUS WS2812BFX_IsRunning(uint16_t Segment, uint8_t *Running); |  | ||||||
| 
 |  | ||||||
| FX_STATUS WS2812BFX_SetMode(uint16_t Segment, fx_mode Mode); |  | ||||||
| FX_STATUS WS2812BFX_GetMode(uint16_t Segment, fx_mode *Mode); |  | ||||||
| FX_STATUS WS2812BFX_NextMode(uint16_t Segment); |  | ||||||
| FX_STATUS WS2812BFX_PrevMode(uint16_t Segment); |  | ||||||
| FX_STATUS WS2812BFX_SetReverse(uint16_t Segment, uint8_t Reverse); |  | ||||||
| FX_STATUS WS2812BFX_GetReverse(uint16_t Segment, uint8_t *Reverse); |  | ||||||
| 
 |  | ||||||
| FX_STATUS WS2812BFX_SetSegmentSize(uint16_t Segment, uint16_t Start, uint16_t Stop); |  | ||||||
| FX_STATUS WS2812BFX_GetSegmentSize(uint16_t Segment, uint16_t *Start, uint16_t *Stop); |  | ||||||
| FX_STATUS WS2812BFX_SegmentIncreaseEnd(uint16_t Segment); |  | ||||||
| FX_STATUS WS2812BFX_SegmentDecreaseEnd(uint16_t Segment); |  | ||||||
| FX_STATUS WS2812BFX_SegmentIncreaseStart(uint16_t Segment); |  | ||||||
| FX_STATUS WS2812BFX_SegmentDecreaseStart(uint16_t Segment); |  | ||||||
| 
 |  | ||||||
| FX_STATUS WS2812BFX_SetSpeed(uint16_t Segment, uint16_t Speed); |  | ||||||
| FX_STATUS WS2812BFX_GetSpeed(uint16_t Segment, uint16_t *Speed); |  | ||||||
| FX_STATUS WS2812BFX_IncreaseSpeed(uint16_t Segment, uint16_t Speed); |  | ||||||
| FX_STATUS WS2812BFX_DecreaseSpeed(uint16_t Segment, uint16_t Speed); |  | ||||||
| 
 |  | ||||||
| void WS2812BFX_SetColorStruct(uint8_t id, ws2812b_color c); |  | ||||||
| void WS2812BFX_SetColorRGB(uint8_t id, uint8_t r, uint8_t g, uint8_t b); |  | ||||||
| FX_STATUS WS2812BFX_GetColorRGB(uint8_t id, uint8_t *r, uint8_t *g, uint8_t *b); |  | ||||||
| void WS2812BFX_SetColorHSV(uint8_t id, uint16_t h, uint8_t s, uint8_t v); |  | ||||||
| void WS2812BFX_SetColor(uint8_t id, uint32_t c); |  | ||||||
| 
 |  | ||||||
| FX_STATUS WS2812BFX_SetAll(uint16_t Segment, uint32_t c); |  | ||||||
| FX_STATUS WS2812BFX_SetAllRGB(uint16_t Segment, uint8_t r, uint8_t g, uint8_t b); |  | ||||||
| 
 |  | ||||||
| void WS2812BFX_RGBtoHSV(uint8_t r, uint8_t g, uint8_t b, uint16_t *h, uint8_t *s, uint8_t *v); |  | ||||||
| void WS2812BFX_HSVtoRGB(uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b); |  | ||||||
| 
 |  | ||||||
| #endif /* WS2812B_FX_H_ */ |  | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | /*
 | ||||||
|  |  * ws281x.h | ||||||
|  |  * | ||||||
|  |  *  The MIT License. | ||||||
|  |  *  Created on: 14.07.2017 | ||||||
|  |  *      Author: Mateusz Salamon | ||||||
|  |  *      www.msalamon.pl | ||||||
|  |  *      mateusz@msalamon.pl | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef WS281X_H_ | ||||||
|  | #define WS281X_H_ | ||||||
|  | 
 | ||||||
|  | /* Includes */ | ||||||
|  | #include <stdint.h> | ||||||
|  | #include "main.h" | ||||||
|  | 
 | ||||||
|  | /* Defintions */ | ||||||
|  | 
 | ||||||
|  | /* Data Structures */ | ||||||
|  | typedef enum ws281x_type_e { | ||||||
|  | 	WS281X_TYPE_WS2811 = 0, | ||||||
|  | 	WS281X_TYPE_WS2812, | ||||||
|  | 	WS281X_TYPE_WS2812B, | ||||||
|  | 	WS281X_TYPE_SK6812, | ||||||
|  | 	WS281X_TYPE_SK6812RGBW, | ||||||
|  | 	WS281X_TYPE_WS2813B, | ||||||
|  | 	WS281X_TYPE_END | ||||||
|  | } ws281x_type_t; | ||||||
|  | typedef union __attribute__((packed, aligned(4))) ws281x_color_u { | ||||||
|  | 	struct __attribute__((packed, aligned(4))) rgbx_s { | ||||||
|  | 		uint8_t r; /* red */ | ||||||
|  | 		uint8_t g; /* green */ | ||||||
|  | 		uint8_t b; /* blue */ | ||||||
|  | 		uint8_t x; /* additional color channel - commonly white or warm white */ | ||||||
|  | 	} rgbx; | ||||||
|  | 	uint32_t u32; | ||||||
|  | 	uint8_t  u8[4]; | ||||||
|  | } ws281x_color_t; | ||||||
|  | typedef struct ws281x_s ws281x_t; | ||||||
|  | 
 | ||||||
|  | /* Function Prototypes */ | ||||||
|  | ws281x_t *ws281x_init(ws281x_type_t type, SPI_HandleTypeDef *hspi, ws281x_color_t *leds, int32_t num_leds); | ||||||
|  | void ws281x_refresh(ws281x_t *ws281x); | ||||||
|  | int32_t ws281x_set_led(ws281x_t *ws281x, uint16_t led_id, ws281x_color_t color); | ||||||
|  | 
 | ||||||
|  | #endif /* WS281X_H_ */ | ||||||
| @ -1,271 +0,0 @@ | |||||||
| /*
 |  | ||||||
|  * ws2812b.c |  | ||||||
|  * |  | ||||||
|  *  The MIT License. |  | ||||||
|  *  Created on: 14.07.2017 |  | ||||||
|  *      Author: Mateusz Salamon |  | ||||||
|  *      www.msalamon.pl |  | ||||||
|  *      mateusz@msalamon.pl |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| /* Includes */ |  | ||||||
| #include "main.h" |  | ||||||
| #include "spi.h" |  | ||||||
| #include "dma.h" |  | ||||||
| #include "gpio.h" |  | ||||||
| #include "math.h" |  | ||||||
| #include "ws2812b.h" |  | ||||||
| 
 |  | ||||||
| /* Definitions */ |  | ||||||
| #define ZERO (0b11000000) |  | ||||||
| #define  ONE (0b11111000) |  | ||||||
| #define WORD_SIZE   (32U) |  | ||||||
| #define BUFFER_SIZE (WORD_SIZE * 2) |  | ||||||
| 
 |  | ||||||
| /* Macros */ |  | ||||||
| #define ws2812_return_if_fail(cond) if(!(cond)) { return; } |  | ||||||
| #define ws2812_return_val_if_fail(cond, val) if(!(cond)) { return (val); } |  | ||||||
| #define ws2812_return_null_if_fail(cond) ws2812_return_val_if_fail((cond), NULL) |  | ||||||
| 
 |  | ||||||
| /* Private Constants */ |  | ||||||
| static const uint8_t sine_lut8[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 gamma_lut8[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]; |  | ||||||
| 
 |  | ||||||
| /* Private Global Variables */ |  | ||||||
| static uint8_t buffer[BUFFER_SIZE]; |  | ||||||
| static uint16_t curr_led; |  | ||||||
| static uint8_t reset_sig; |  | ||||||
| 
 |  | ||||||
| /* Function Definitions */ |  | ||||||
| void ws2812_init(SPI_HandleTypeDef *hspi) |  | ||||||
| { |  | ||||||
| 	hspi_ws2812b = hspi; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ws2812_set_led_color_val(uint16_t diode_id, uint32_t color) |  | ||||||
| { |  | ||||||
| 	ws2812_return_if_fail(diode_id < WS2812B_LEDS); |  | ||||||
| 	ws2812b_array[diode_id].u32 = color; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ws2812_set_led_color(uint16_t diode_id, ws2812b_color color) |  | ||||||
| { |  | ||||||
| 	ws2812_return_if_fail(diode_id < WS2812B_LEDS); |  | ||||||
| 	ws2812b_array[diode_id] = color; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ws2812_set_led_rgb(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b) |  | ||||||
| { |  | ||||||
| 	ws2812_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 ws2812_set_led_rgbx(uint16_t diode_id, uint8_t r, uint8_t g, uint8_t b, uint8_t x) |  | ||||||
| { |  | ||||||
| 	ws2812_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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * Set diode with HSV model |  | ||||||
|  * |  | ||||||
|  * Hue 0-359 |  | ||||||
|  * Saturation 0-255 |  | ||||||
|  * Value 0-255 |  | ||||||
|  */ |  | ||||||
| void ws2812_set_led_hsv(uint16_t diode_id, uint16_t hue, uint8_t sat, uint8_t value) |  | ||||||
| { |  | ||||||
| 	uint16_t sector, fract, p, q, t; |  | ||||||
| 
 |  | ||||||
| 	ws2812_return_if_fail(diode_id < WS2812B_LEDS); |  | ||||||
| 
 |  | ||||||
| 	if(sat == 0) |  | ||||||
| 	{ |  | ||||||
| 		ws2812b_array[diode_id].rgb.red   = value; |  | ||||||
| 		ws2812b_array[diode_id].rgb.green = value; |  | ||||||
| 		ws2812b_array[diode_id].rgb.blue  = value; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		if(hue >= 360) hue = 359; |  | ||||||
| 
 |  | ||||||
| 		sector = hue / 60; /* hexcone HSV model -- 6 sectors */ |  | ||||||
| 		fract = hue % 60; |  | ||||||
| 		p = (value * (255 - sat)) / 256; |  | ||||||
| 		q = (value * (255 - (sat * fract) / 60)) / 256; |  | ||||||
| 		t = (value * (255 - (sat * (59 - fract)) / 60)) / 256; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 		switch(sector) |  | ||||||
| 		{ |  | ||||||
| 		case 0: |  | ||||||
| 			ws2812b_array[diode_id].rgb.red   = value; |  | ||||||
| 			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].rgb.red   = (uint8_t)q; |  | ||||||
| 			ws2812b_array[diode_id].rgb.green = value; |  | ||||||
| 			ws2812b_array[diode_id].rgb.blue  = (uint8_t)p; |  | ||||||
| 			break; |  | ||||||
| 		case 2: |  | ||||||
| 			ws2812b_array[diode_id].rgb.red   = (uint8_t)p; |  | ||||||
| 			ws2812b_array[diode_id].rgb.green = value; |  | ||||||
| 			ws2812b_array[diode_id].rgb.blue  = (uint8_t)t; |  | ||||||
| 			break; |  | ||||||
| 		case 3: |  | ||||||
| 			ws2812b_array[diode_id].rgb.red   = (uint8_t)p; |  | ||||||
| 			ws2812b_array[diode_id].rgb.green = (uint8_t)q; |  | ||||||
| 			ws2812b_array[diode_id].rgb.blue  = value; |  | ||||||
| 			break; |  | ||||||
| 		case 4: |  | ||||||
| 			ws2812b_array[diode_id].rgb.red   = (uint8_t)t; |  | ||||||
| 			ws2812b_array[diode_id].rgb.green = (uint8_t)p; |  | ||||||
| 			ws2812b_array[diode_id].rgb.blue  = value; |  | ||||||
| 			break; |  | ||||||
| 		case 5: |  | ||||||
| 		default: |  | ||||||
| 			ws2812b_array[diode_id].rgb.red   = value; |  | ||||||
| 			ws2812b_array[diode_id].rgb.green = (uint8_t)p; |  | ||||||
| 			ws2812b_array[diode_id].rgb.blue  = (uint8_t)q; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint32_t ws2812_get_color(uint16_t diode_id) |  | ||||||
| { |  | ||||||
| 	ws2812_return_val_if_fail(diode_id < WS2812B_LEDS, 0); |  | ||||||
| 
 |  | ||||||
| 	return ws2812b_array[diode_id].u32; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t *ws2812_get_pixels() |  | ||||||
| { |  | ||||||
| 	return (uint8_t*)ws2812b_array; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ws2812_refresh() |  | ||||||
| { |  | ||||||
| 	curr_led = 0; |  | ||||||
| 	reset_sig = 0; |  | ||||||
| 
 |  | ||||||
| 	for(uint8_t i = 0; i < BUFFER_SIZE; i++) |  | ||||||
| 		buffer[i] = 0x00; |  | ||||||
| 	HAL_SPI_Transmit_DMA(hspi_ws2812b, buffer, BUFFER_SIZE); |  | ||||||
| 	while(HAL_DMA_STATE_READY != HAL_DMA_GetState(hspi_ws2812b->hdmatx)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t sine8(uint8_t x) |  | ||||||
| { |  | ||||||
| 	return sine_lut8[x]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t gamma8(uint8_t x) |  | ||||||
| { |  | ||||||
| 	return gamma_lut8[x]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* Private Function Definitions */ |  | ||||||
| void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi) |  | ||||||
| { |  | ||||||
| 	if(hspi == hspi_ws2812b) |  | ||||||
| 	{ |  | ||||||
| 		if(!reset_sig) |  | ||||||
| 		{ |  | ||||||
| 			for(uint8_t k = 0; k < WORD_SIZE; k++) |  | ||||||
| 			{ |  | ||||||
| 				buffer[k] = 0x00; |  | ||||||
| 			} |  | ||||||
| 			reset_sig = 1; /* End reset signal */ |  | ||||||
| 		} |  | ||||||
| 		else /* Odd LEDs 1, 3, 5, ... */ |  | ||||||
| 		{ |  | ||||||
| 			if(curr_led > WS2812B_LEDS) |  | ||||||
| 			{ |  | ||||||
| 				HAL_SPI_DMAStop(hspi_ws2812b); |  | ||||||
| 			} |  | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				uint8_t i = 0; |  | ||||||
| 				for(int8_t j = WORD_SIZE - 1; j >= 0; j--) |  | ||||||
| 				{ |  | ||||||
| 					if((ws2812b_array[curr_led].u32 & (1 << j)) == 0) |  | ||||||
| 						buffer[i] = ZERO; |  | ||||||
| 					else |  | ||||||
| 						buffer[i] = ONE; |  | ||||||
| 					i++; |  | ||||||
| 				} |  | ||||||
| 				curr_led++; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) |  | ||||||
| { |  | ||||||
| 	if(hspi == hspi_ws2812b) |  | ||||||
| 	{ |  | ||||||
| 		if(curr_led > WS2812B_LEDS) |  | ||||||
| 		{ |  | ||||||
| 			HAL_SPI_DMAStop(hspi_ws2812b); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			/* Even LEDs 0, 2, 4, ... */ |  | ||||||
| 			uint8_t i = WORD_SIZE; |  | ||||||
| 			for(int8_t j = WORD_SIZE - 1; j >= 0; j--) |  | ||||||
| 			{ |  | ||||||
| 				if((ws2812b_array[curr_led].u32 & (1 << j)) == 0) |  | ||||||
| 					buffer[i] = ZERO; |  | ||||||
| 				else |  | ||||||
| 					buffer[i] = ONE; |  | ||||||
| 				i++; |  | ||||||
| 			} |  | ||||||
| 			curr_led++; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -0,0 +1,213 @@ | |||||||
|  | /*
 | ||||||
|  |  * ws281x.c | ||||||
|  |  * | ||||||
|  |  *  The MIT License. | ||||||
|  |  *  Created on: 14.07.2017 | ||||||
|  |  *      Author: Mateusz Salamon | ||||||
|  |  *      www.msalamon.pl | ||||||
|  |  *      mateusz@msalamon.pl | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Includes */ | ||||||
|  | #include <ws281x.h> | ||||||
|  | 
 | ||||||
|  | /* Definitions */ | ||||||
|  | #define WS281X_MAX (16U) | ||||||
|  | #define ZERO (0b11000000) | ||||||
|  | #define  ONE (0b11111000) | ||||||
|  | 
 | ||||||
|  | /* Macros */ | ||||||
|  | #define ws281x_return_if_fail(cond) if(!(cond)) { return; } | ||||||
|  | #define ws281x_return_val_if_fail(cond, val) if(!(cond)) { return (val); } | ||||||
|  | #define ws281x_return_null_if_fail(cond) ws281x_return_val_if_fail((cond), NULL) | ||||||
|  | 
 | ||||||
|  | /* Data Structures */ | ||||||
|  | struct ws281x_s { | ||||||
|  | 	ws281x_type_t type; | ||||||
|  | 	SPI_HandleTypeDef *hspi; | ||||||
|  | 	ws281x_color_t *leds; | ||||||
|  | 	int32_t num_leds; | ||||||
|  | 	int32_t curr_led; | ||||||
|  | 	uint8_t wordlen; | ||||||
|  | 	uint8_t buf[64]; /* enough to hold even/odd 32-bit words */ | ||||||
|  | 	uint8_t reset; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Private Constants */ | ||||||
|  | 
 | ||||||
|  | /* Public Global Variables */ | ||||||
|  | 
 | ||||||
|  | /* Private Global Variables */ | ||||||
|  | static ws281x_t ws281x[WS281X_MAX]; | ||||||
|  | static int32_t ws281x_count = 0; | ||||||
|  | static uint8_t wordlen[WS281X_TYPE_END] = { | ||||||
|  | 	24, /* WS281X_TYPE_WS2811 */ | ||||||
|  | 	24, /* WS281X_TYPE_WS2812*/ | ||||||
|  | 	24, /* WS281X_TYPE_WS2812B */ | ||||||
|  | 	24, /* WS281X_TYPE_SK6812 */ | ||||||
|  | 	32, /* WS281X_TYPE_SK6812RGBW */ | ||||||
|  | 	24  /* WS281X_TYPE_WS2813B */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Function Prototypes */ | ||||||
|  | static ws281x_t *ws281x_lookup(SPI_HandleTypeDef *hspi); | ||||||
|  | static void ws281x_update_half(ws281x_t *ws281x, uint8_t even); | ||||||
|  | 
 | ||||||
|  | /* Function Definitions */ | ||||||
|  | /**
 | ||||||
|  |  * \brief Creates a new `ws281x_t` instance. | ||||||
|  |  * | ||||||
|  |  * This function initializes a new `ws281x_t` object which is controlled by | ||||||
|  |  * a SPI peripheral and DMA. | ||||||
|  |  * | ||||||
|  |  * \param type The type of addressable LED(s). | ||||||
|  |  * \param hspi Pointer to the SPI device handle. The `hspi` handle must be | ||||||
|  |  *             unique for each obect initialized. | ||||||
|  |  * \param leds Pointer to an array of `ws281x_color_t` which holds all of the | ||||||
|  |  *             LED color information. | ||||||
|  |  * \param num_leds The number of LEDs to control. | ||||||
|  |  * | ||||||
|  |  * \return Pointer to the created ws281x_t object, NULL on failure. | ||||||
|  |  */ | ||||||
|  | ws281x_t *ws281x_init(ws281x_type_t type, SPI_HandleTypeDef *hspi, ws281x_color_t *leds, int32_t num_leds) | ||||||
|  | { | ||||||
|  | 	ws281x_return_null_if_fail(ws281x_count < WS281X_MAX); | ||||||
|  | 	ws281x_return_null_if_fail(type < WS281X_TYPE_END); | ||||||
|  | 	ws281x_return_null_if_fail(hspi); | ||||||
|  | 	ws281x_return_null_if_fail(leds); | ||||||
|  | 	ws281x_return_null_if_fail(num_leds > 0); | ||||||
|  | 	ws281x_return_null_if_fail(ws281x_lookup(hspi) == NULL); | ||||||
|  | 
 | ||||||
|  | 	ws281x[ws281x_count].hspi = hspi; | ||||||
|  | 	ws281x[ws281x_count].type = type; | ||||||
|  | 	ws281x[ws281x_count].leds = leds; | ||||||
|  | 	ws281x[ws281x_count].num_leds = num_leds; | ||||||
|  | 	ws281x[ws281x_count].curr_led = 0; | ||||||
|  | 	ws281x[ws281x_count].wordlen = wordlen[type]; | ||||||
|  | 	ws281x[ws281x_count].reset = 0; | ||||||
|  | 
 | ||||||
|  | 	return &ws281x[ws281x_count++]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * \brief Refreshes the LED(s). | ||||||
|  |  * | ||||||
|  |  * All of the LEDs in the string are sent the current color information. | ||||||
|  |  * | ||||||
|  |  * \param ws281x Pointer to a `ws281x_t` object. | ||||||
|  |  */ | ||||||
|  | void ws281x_refresh(ws281x_t *ws281x) | ||||||
|  | { | ||||||
|  | 	uint8_t i; | ||||||
|  | 
 | ||||||
|  | 	ws281x_return_if_fail(ws281x); | ||||||
|  | 
 | ||||||
|  | 	ws281x->curr_led = 0; | ||||||
|  | 	ws281x->reset = 1; | ||||||
|  | 	for(i = 0; i < ws281x->wordlen * 2; i++) | ||||||
|  | 	{ | ||||||
|  | 		ws281x->buf[i] = 0x00; | ||||||
|  | 	} | ||||||
|  | 	HAL_SPI_Transmit_DMA(ws281x->hspi, ws281x->buf, ws281x->wordlen * 2); | ||||||
|  | 	while(HAL_DMA_GetState(ws281x->hspi->hdmatx) != HAL_DMA_STATE_READY); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * \brief Sets an LED color. | ||||||
|  |  * | ||||||
|  |  * This function sets the color of the LED at index `led_id`. | ||||||
|  |  * | ||||||
|  |  * \param ws281x Pointer to a `ws281x_t` object. | ||||||
|  |  * \param led_id Index of the LED which is to have its color assigned. | ||||||
|  |  * \param color A ws281x_color_t object which contains the color information | ||||||
|  |  *              to be assigned. | ||||||
|  |  * | ||||||
|  |  * \return `led_id` on success, -1 on failure. | ||||||
|  |  */ | ||||||
|  | int32_t ws281x_set_led(ws281x_t *ws281x, uint16_t led_id, ws281x_color_t color) | ||||||
|  | { | ||||||
|  | 	ws281x_return_val_if_fail(ws281x, -1); | ||||||
|  | 	ws281x_return_val_if_fail(led_id < ws281x->num_leds, -1); | ||||||
|  | 
 | ||||||
|  | 	ws281x->leds[led_id] = color; | ||||||
|  | 
 | ||||||
|  | 	return led_id; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Private Function Definitions */ | ||||||
|  | static ws281x_t *ws281x_lookup(SPI_HandleTypeDef *hspi) | ||||||
|  | { | ||||||
|  | 	int32_t i; | ||||||
|  | 
 | ||||||
|  | 	ws281x_return_val_if_fail(hspi, NULL); | ||||||
|  | 	ws281x_return_val_if_fail(ws281x_count > 0, NULL); | ||||||
|  | 
 | ||||||
|  | 	for(i = 0; i < ws281x_count; i++) | ||||||
|  | 	{ | ||||||
|  | 		if(ws281x[i].hspi == hspi) | ||||||
|  | 		{ | ||||||
|  | 			return &ws281x[i]; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void ws281x_update_half(ws281x_t *ws281x, uint8_t even) | ||||||
|  | { | ||||||
|  | 	uint8_t i = even ? ws281x->wordlen : 0; | ||||||
|  | 	int8_t j; | ||||||
|  | 
 | ||||||
|  | 	if(ws281x->curr_led > ws281x->num_leds) | ||||||
|  | 	{ | ||||||
|  | 		HAL_SPI_DMAStop(ws281x->hspi); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		for(j = ws281x->wordlen - 1; j >= 0; j--) | ||||||
|  | 		{ | ||||||
|  | 			if((ws281x->leds[ws281x->curr_led].u32 & (1 << j))) | ||||||
|  | 			{ | ||||||
|  | 				ws281x->buf[i] = ONE; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				ws281x->buf[i] = ZERO; | ||||||
|  | 			} | ||||||
|  | 			i++; | ||||||
|  | 		} | ||||||
|  | 		ws281x->curr_led++; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* HAL Callbacks */ | ||||||
|  | void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi) | ||||||
|  | { | ||||||
|  | 	ws281x_t *ws281x = ws281x_lookup(hspi); | ||||||
|  | 	uint8_t i; | ||||||
|  | 
 | ||||||
|  | 	ws281x_return_if_fail(ws281x); | ||||||
|  | 
 | ||||||
|  | 	if(ws281x->reset) | ||||||
|  | 	{ | ||||||
|  | 		for(i = 0; i < ws281x->wordlen; i++) | ||||||
|  | 		{ | ||||||
|  | 			ws281x->buf[i] = 0x00; | ||||||
|  | 		} | ||||||
|  | 		ws281x->reset = 0; | ||||||
|  | 	} | ||||||
|  | 	else /* odd LEDs -- 1, 3, 5, ... */ | ||||||
|  | 	{ | ||||||
|  | 		ws281x_update_half(ws281x, 0); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) | ||||||
|  | { | ||||||
|  | 	ws281x_t *ws281x = ws281x_lookup(hspi); | ||||||
|  | 
 | ||||||
|  | 	ws281x_return_if_fail(ws281x); | ||||||
|  | 
 | ||||||
|  | 	/* even LEDs -- 2, 4, 6, ... */ | ||||||
|  | 	ws281x_update_half(ws281x, 1); | ||||||
|  | } | ||||||
					Loading…
					
					
				
		Reference in new issue