Browse Source

rewrite to provide generic interface to ws281x addressable LEDS

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 code
master
parent
commit
69ff076b0e
  1. 51
      Inc/ws2812b.h
  2. 153
      Inc/ws2812b_fx.h
  3. 47
      Inc/ws281x.h
  4. 271
      Src/ws2812b.c
  5. 2042
      Src/ws2812b_fx.c
  6. 213
      Src/ws281x.c

51
Inc/ws2812b.h

@ -1,51 +0,0 @@ @@ -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_ */

153
Inc/ws2812b_fx.h

@ -1,153 +0,0 @@ @@ -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_ */

47
Inc/ws281x.h

@ -0,0 +1,47 @@ @@ -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_ */

271
Src/ws2812b.c

@ -1,271 +0,0 @@ @@ -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++;
}
}
}

2042
Src/ws2812b_fx.c

File diff suppressed because it is too large Load Diff

213
Src/ws281x.c

@ -0,0 +1,213 @@ @@ -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…
Cancel
Save