mirror of
https://github.com/ADElectronics/RTL00_WEB_WS2812.git
synced 2026-07-05 03:05:39 +00:00
SDK update
This commit is contained in:
parent
7ac60bf6e1
commit
68362feaa1
1153 changed files with 97410 additions and 592771 deletions
132
Firmware/Project/WS2812/ledeffectsserver.c
Normal file
132
Firmware/Project/WS2812/ledeffectsserver.c
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#include "ledeffectsserver.h"
|
||||
#include "ws2812.h"
|
||||
#include <flash_api.h>
|
||||
|
||||
volatile uint32_t cfg_updated = 0;
|
||||
ws2812_t *ws2812_cfg = NULL;
|
||||
strip_handler_t strip;
|
||||
SemaphoreHandle_t cfg_sema = NULL;
|
||||
|
||||
ctx_rainbow_t filt_rainbow;
|
||||
ctx_fade_t filt_fade;
|
||||
ctx_const_t filt_const;
|
||||
ctx_wave_t filt_wave;
|
||||
|
||||
void ledEffectsServer_Init()
|
||||
{
|
||||
ws2812_cfg = ws2812_Init(WS2812_LEDS_MAX);
|
||||
if (ws2812_cfg == NULL)
|
||||
{
|
||||
printf("[%s] ws2812_Init() failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ledFilter_Init(&strip, ws2812_cfg);
|
||||
|
||||
ledFilter_InitRainbow(&filt_rainbow);
|
||||
ledFilter_InitFade(&filt_fade);
|
||||
ledFilter_InitConstant(&filt_const);
|
||||
ledFilter_InitWave(&filt_wave);
|
||||
|
||||
ledFilter_SetDefualtValue(&strip, MAX_STRIP_BRIGHT);
|
||||
}
|
||||
|
||||
void ledEffectsServer_Task()
|
||||
{
|
||||
cfg_sema = xSemaphoreCreateMutex();
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (xSemaphoreTake(cfg_sema, 5 * configTICK_RATE_HZ))
|
||||
{
|
||||
ledFilter_Rainbow(&filt_rainbow, &strip);
|
||||
ledFilter_Constant(&filt_const, &strip);
|
||||
ledFilter_Wave(&filt_wave, &strip);
|
||||
ledFilter_Fade(&filt_fade, &strip);
|
||||
|
||||
|
||||
ws2812_Update(ws2812_cfg, strip.hsv_vals, strip.strip_len, strip.delay);
|
||||
xSemaphoreGive(cfg_sema);
|
||||
}
|
||||
WDGRefresh();
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
void ledEffectsServer_LoadConfigFromFlash()
|
||||
{
|
||||
flash_t flash;
|
||||
|
||||
printf("[%s] reading config from flash\n", __func__);
|
||||
device_mutex_lock(RT_DEV_LOCK_FLASH);
|
||||
flash_stream_read(&flash, LED_SETTINGS_SECTOR, sizeof(strip_cfg), (uint8_t *)&strip_cfg);
|
||||
device_mutex_unlock(RT_DEV_LOCK_FLASH);
|
||||
}
|
||||
|
||||
void ledEffectsServer_SaveConfigToFlash()
|
||||
{
|
||||
flash_t flash;
|
||||
|
||||
printf("[%s] saving config to flash\n", __func__);
|
||||
|
||||
cfg_updated = 0;
|
||||
|
||||
device_mutex_lock(RT_DEV_LOCK_FLASH);
|
||||
flash_erase_sector(&flash, LED_SETTINGS_SECTOR);
|
||||
flash_stream_write(&flash, LED_SETTINGS_SECTOR, sizeof(strip_cfg), (uint8_t *)&strip_cfg);
|
||||
device_mutex_unlock(RT_DEV_LOCK_FLASH);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
struct blinken_cfg *blinken_get_config(void)
|
||||
{
|
||||
blinken_cfg_t *cfg = NULL;
|
||||
|
||||
if(strip_cfg.magic == BLINKEN_CFG_MAGIC)
|
||||
{
|
||||
cfg = malloc(sizeof(*cfg));
|
||||
if(cfg != NULL)
|
||||
{
|
||||
memmove(cfg, &strip_cfg, sizeof(*cfg));
|
||||
}
|
||||
}
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
|
||||
int blinken_set_config(blinken_cfg_t *cfg)
|
||||
{
|
||||
int result;
|
||||
BaseType_t status;
|
||||
|
||||
result = 0;
|
||||
if(cfg == NULL || cfg->magic != BLINKEN_CFG_MAGIC)
|
||||
{
|
||||
result = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
status = xSemaphoreTake(cfg_sema, 15 * configTICK_RATE_HZ);
|
||||
if(status != pdTRUE)
|
||||
{
|
||||
printf("[%s] Timeout waiting for config sema.\n", __func__);
|
||||
result = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = init_handler(&handler, cfg, ws2812_cfg, true);
|
||||
if(result == 0)
|
||||
{
|
||||
memmove(&strip_cfg, cfg, sizeof(strip_cfg));
|
||||
save_config();
|
||||
}
|
||||
|
||||
xSemaphoreGive(cfg_sema);
|
||||
|
||||
error:
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
18
Firmware/Project/WS2812/ledeffectsserver.h
Normal file
18
Firmware/Project/WS2812/ledeffectsserver.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _LEDEFFECTSSERVER_H_
|
||||
#define _LEDEFFECTSSERVER_H_
|
||||
|
||||
#include "ledfilters.h"
|
||||
|
||||
|
||||
// Ïóáëè÷íûå êîíôèíãè ôèëüòðîâ
|
||||
extern strip_handler_t strip;
|
||||
extern ctx_rainbow_t filt_rainbow;
|
||||
extern ctx_fade_t filt_fade;
|
||||
extern ctx_const_t filt_const;
|
||||
extern ctx_wave_t filt_wave;
|
||||
|
||||
void ledEffectsServer_Init();
|
||||
void ledEffectsServer_Task();
|
||||
|
||||
#endif // _LEDEFFECTSSERVER_H_
|
||||
|
||||
320
Firmware/Project/WS2812/ledfilters.c
Normal file
320
Firmware/Project/WS2812/ledfilters.c
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
#include "ledfilters.h"
|
||||
|
||||
extern uint32_t cfg_updated;
|
||||
|
||||
uint8_t sin_table[256] = {
|
||||
0x80, 0x83, 0x86, 0x89, 0x8C, 0x90, 0x93, 0x96,
|
||||
0x99, 0x9C, 0x9F, 0xA2, 0xA5, 0xA8, 0xAB, 0xAE,
|
||||
0xB1, 0xB3, 0xB6, 0xB9, 0xBC, 0xBF, 0xC1, 0xC4,
|
||||
0xC7, 0xC9, 0xCC, 0xCE, 0xD1, 0xD3, 0xD5, 0xD8,
|
||||
0xDA, 0xDC, 0xDE, 0xE0, 0xE2, 0xE4, 0xE6, 0xE8,
|
||||
0xEA, 0xEB, 0xED, 0xEF, 0xF0, 0xF1, 0xF3, 0xF4,
|
||||
0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFA, 0xFB, 0xFC,
|
||||
0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFD,
|
||||
0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xF9, 0xF8, 0xF6,
|
||||
0xF5, 0xF4, 0xF3, 0xF1, 0xF0, 0xEF, 0xED, 0xEB,
|
||||
0xEA, 0xE8, 0xE6, 0xE4, 0xE2, 0xE0, 0xDE, 0xDC,
|
||||
0xDA, 0xD8, 0xD5, 0xD3, 0xD1, 0xCE, 0xCC, 0xC9,
|
||||
0xC7, 0xC4, 0xC1, 0xBF, 0xBC, 0xB9, 0xB6, 0xB3,
|
||||
0xB1, 0xAE, 0xAB, 0xA8, 0xA5, 0xA2, 0x9F, 0x9C,
|
||||
0x99, 0x96, 0x93, 0x90, 0x8C, 0x89, 0x86, 0x83,
|
||||
0x80, 0x7D, 0x7A, 0x77, 0x74, 0x70, 0x6D, 0x6A,
|
||||
0x67, 0x64, 0x61, 0x5E, 0x5B, 0x58, 0x55, 0x52,
|
||||
0x4F, 0x4D, 0x4A, 0x47, 0x44, 0x41, 0x3F, 0x3C,
|
||||
0x39, 0x37, 0x34, 0x32, 0x2F, 0x2D, 0x2B, 0x28,
|
||||
0x26, 0x24, 0x22, 0x20, 0x1E, 0x1C, 0x1A, 0x18,
|
||||
0x16, 0x15, 0x13, 0x11, 0x10, 0x0F, 0x0D, 0x0C,
|
||||
0x0B, 0x0A, 0x08, 0x07, 0x06, 0x06, 0x05, 0x04,
|
||||
0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03,
|
||||
0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x0A,
|
||||
0x0B, 0x0C, 0x0D, 0x0F, 0x10, 0x11, 0x13, 0x15,
|
||||
0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24,
|
||||
0x26, 0x28, 0x2B, 0x2D, 0x2F, 0x32, 0x34, 0x37,
|
||||
0x39, 0x3C, 0x3F, 0x41, 0x44, 0x47, 0x4A, 0x4D,
|
||||
0x4F, 0x52, 0x55, 0x58, 0x5B, 0x5E, 0x61, 0x64,
|
||||
0x67, 0x6A, 0x6D, 0x70, 0x74, 0x77, 0x7A, 0x7D
|
||||
};
|
||||
|
||||
#pragma region Áàçîâûå ôóíêöèè ïî ðàáîòå ñ ôèëüòðàìè
|
||||
int32_t ledFilter_Init(strip_handler_t *strip, ws2812_t *ws2812)
|
||||
{
|
||||
if(strip->check != LEDFILTERS_CFG_CHECKWORD)
|
||||
{
|
||||
memset(strip, 0xff, sizeof(strip_handler_t));
|
||||
strip->check = LEDFILTERS_CFG_CHECKWORD;
|
||||
strip->strip_len = DEF_STRIP_LEN;
|
||||
strip->delay = 10; // îáùàÿ ñêîðîñòü
|
||||
strip->brightness = MAX_STRIP_BRIGHT;
|
||||
strip->enable = 1;
|
||||
strip->try_enable = 0;
|
||||
cfg_updated = 1;
|
||||
}
|
||||
|
||||
if(strip->strip_len > MAX_STRIP_LEN)
|
||||
{
|
||||
strip->strip_len = MAX_STRIP_LEN;
|
||||
cfg_updated = 1;
|
||||
}
|
||||
|
||||
if(strip->delay > MAX_STRIP_DELAY)
|
||||
{
|
||||
strip->delay = MAX_STRIP_DELAY;
|
||||
cfg_updated = 1;
|
||||
}
|
||||
|
||||
if(strip->brightness > MAX_STRIP_BRIGHT)
|
||||
{
|
||||
strip->brightness = MAX_STRIP_BRIGHT;
|
||||
cfg_updated = 1;
|
||||
}
|
||||
|
||||
strip->hsv_vals = malloc(sizeof(ws2812_hsv_t) * strip->strip_len);
|
||||
if (strip->hsv_vals == NULL)
|
||||
{
|
||||
printf("[%s] malloc() failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(strip->hsv_vals, 0x0, sizeof(ws2812_hsv_t) * strip->strip_len);
|
||||
|
||||
ws2812_SetLen(ws2812, strip->strip_len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ledFilter_SetDefualtValue(strip_handler_t *strip, uint8_t val)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < strip->strip_len; i++)
|
||||
{
|
||||
strip->hsv_vals[i].value = val;
|
||||
}
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Rainbow
|
||||
void ledFilter_InitRainbow(ctx_rainbow_t *ctx)
|
||||
{
|
||||
if (ctx->valid != LEDFILTERS_CFG_CHECKWORD)
|
||||
{
|
||||
ctx->valid = LEDFILTERS_CFG_CHECKWORD;
|
||||
ctx->hue_steps = WS2812_LEDS_MAX / 2; // Âî ñêîëüêî ñâåòîäèîäîâ âìåñòèòü âñþ ðàäóãó
|
||||
ctx->cycle_steps = 1;
|
||||
ctx->enabled = 1;
|
||||
cfg_updated = 1;
|
||||
}
|
||||
|
||||
ctx->curr_hue = 0;
|
||||
}
|
||||
|
||||
void ledFilter_Rainbow(ctx_rainbow_t *ctx, strip_handler_t *strip)
|
||||
{
|
||||
uint32_t i, j;
|
||||
ws2812_hsv_t tmp_hsv;
|
||||
uint8_t tmp_hue;
|
||||
|
||||
if (ctx->enabled == 0 || strip->enable == 0) return;
|
||||
|
||||
tmp_hue = ctx->curr_hue;
|
||||
tmp_hsv.sat = 255;
|
||||
|
||||
for (i = 0, j = ctx->hue_steps; i < strip->strip_len; i++)
|
||||
{
|
||||
if (i == j)
|
||||
{
|
||||
j += ctx->hue_steps;
|
||||
tmp_hue = ctx->curr_hue;
|
||||
}
|
||||
|
||||
tmp_hsv.hue = tmp_hue;
|
||||
tmp_hsv.value = strip->hsv_vals[i].value;
|
||||
strip->hsv_vals[i] = tmp_hsv;
|
||||
tmp_hue += 255/ ctx->hue_steps;
|
||||
//tmp_hue %= 256;
|
||||
}
|
||||
|
||||
ctx->curr_hue += ctx->cycle_steps;
|
||||
ctx->curr_hue %= 256;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Fade
|
||||
void ledFilter_InitFade(ctx_fade_t *ctx)
|
||||
{
|
||||
if (ctx->valid != LEDFILTERS_CFG_CHECKWORD)
|
||||
{
|
||||
ctx->valid = LEDFILTERS_CFG_CHECKWORD;
|
||||
ctx->min = 0;
|
||||
ctx->max = 255;
|
||||
ctx->steps = LEDFILTERS_MAX_STEPS;
|
||||
ctx->enabled = 0;
|
||||
cfg_updated = 1;
|
||||
}
|
||||
|
||||
if (ctx->steps == 0)
|
||||
{
|
||||
ctx->enabled = 0;
|
||||
}
|
||||
|
||||
ctx->curr_val = 0;
|
||||
ctx->curr_step = 0;
|
||||
}
|
||||
|
||||
void ledFilter_Fade(ctx_fade_t *ctx, strip_handler_t *strip)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (ctx->enabled == 0 || strip->enable == 0) return;
|
||||
|
||||
if (ctx->curr_val == 0)
|
||||
{
|
||||
for (i = 0; i < strip->strip_len; i++)
|
||||
{
|
||||
if (strip->hsv_vals[i].value > ctx->min)
|
||||
{
|
||||
if (strip->hsv_vals[i].value > (255 / ctx->steps))
|
||||
strip->hsv_vals[i].value -= (255 / ctx->steps);
|
||||
else
|
||||
{
|
||||
strip->hsv_vals[i].value = 0;
|
||||
ctx->curr_step = ctx->steps;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->curr_step = ctx->steps;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < strip->strip_len; i++)
|
||||
{
|
||||
if (strip->hsv_vals[i].value <= ctx->max)
|
||||
{
|
||||
if (strip->hsv_vals[i].value + (255 / ctx->steps) > ctx->max)
|
||||
{
|
||||
strip->hsv_vals[i].value = ctx->max;
|
||||
ctx->curr_step = ctx->steps;
|
||||
}
|
||||
else
|
||||
strip->hsv_vals[i].value += (255 / ctx->steps);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->curr_step = ctx->steps;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx->curr_step++;
|
||||
|
||||
if (ctx->curr_step >= ctx->steps)
|
||||
{
|
||||
if (ctx->curr_val) ctx->curr_val = 0;
|
||||
else ctx->curr_val = 1;
|
||||
ctx->curr_step = 0;
|
||||
}
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Wave
|
||||
void ledFilter_InitWave(ctx_wave_t *ctx)
|
||||
{
|
||||
if (ctx->valid != LEDFILTERS_CFG_CHECKWORD)
|
||||
{
|
||||
ctx->valid = LEDFILTERS_CFG_CHECKWORD;
|
||||
ctx->enabled = 0;
|
||||
ctx->wave_steps = 20;
|
||||
ctx->angle = 0;
|
||||
ctx->step = 1;
|
||||
cfg_updated = 1;
|
||||
}
|
||||
|
||||
//for (uint16_t i = 0; i < 255; i++)
|
||||
// sin_table[i] = (uint16_t)(sin((double)(((double)i + 2.0) * M_PI)/ 255.0) * UINT8_MAX);
|
||||
}
|
||||
|
||||
void ledFilter_Wave(ctx_wave_t *ctx, strip_handler_t *strip)
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint8_t tmp_angle = 0;
|
||||
if (ctx->enabled == 0 || strip->enable == 0) return;
|
||||
|
||||
tmp_angle = ctx->angle;
|
||||
for (i = 0, j = ctx->wave_steps; i < strip->strip_len; i++)
|
||||
{
|
||||
if (i == j)
|
||||
{
|
||||
j += ctx->wave_steps;
|
||||
tmp_angle = ctx->angle;
|
||||
}
|
||||
strip->hsv_vals[i].value = sin_table[tmp_angle];
|
||||
tmp_angle += 255 / ctx->wave_steps;
|
||||
//tmp_angle %= 256;
|
||||
}
|
||||
|
||||
ctx->angle += ctx->step;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Constant
|
||||
void ledFilter_InitConstant(ctx_const_t *ctx)
|
||||
{
|
||||
if (ctx->valid != LEDFILTERS_CFG_CHECKWORD)
|
||||
{
|
||||
ctx->valid = LEDFILTERS_CFG_CHECKWORD;
|
||||
ctx->hue = 128;
|
||||
ctx->sat = 255;
|
||||
ctx->value = 255;
|
||||
ctx->enabled = 0;
|
||||
ctx->update = 0;
|
||||
cfg_updated = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ledFilter_Constant(ctx_const_t *ctx, strip_handler_t *strip)
|
||||
{
|
||||
uint32_t i;
|
||||
if (strip->try_enable)
|
||||
{
|
||||
for (i = 0; i < strip->strip_len; i++)
|
||||
{
|
||||
if (strip->hsv_vals[i].value < strip->brightness)
|
||||
strip->hsv_vals[i].value++;
|
||||
else
|
||||
{
|
||||
strip->enable = 1;
|
||||
strip->try_enable = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (strip->enable == 0)
|
||||
{
|
||||
for (i = 0; i < strip->strip_len; i++)
|
||||
{
|
||||
if (strip->hsv_vals[i].value > 0)
|
||||
strip->hsv_vals[i].value--;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (ctx->enabled == 0) return;
|
||||
|
||||
if (ctx->update > 0)
|
||||
{
|
||||
for (i = 0; i < strip->strip_len; i++)
|
||||
{
|
||||
strip->hsv_vals[i].hue = ctx->hue;
|
||||
strip->hsv_vals[i].sat = ctx->sat;
|
||||
strip->hsv_vals[i].value = ctx->value;
|
||||
}
|
||||
|
||||
ctx->update = 0;
|
||||
}
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
92
Firmware/Project/WS2812/ledfilters.h
Normal file
92
Firmware/Project/WS2812/ledfilters.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
#ifndef _LEDFILTERS_H_
|
||||
#define _LEDFILTERS_H_
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "macro_common.h"
|
||||
#include <autoconf.h>
|
||||
#include <platform_opts.h>
|
||||
#include <platform_stdlib.h>
|
||||
#include "device_lock.h"
|
||||
#include "ws2812.h"
|
||||
|
||||
#define LEDFILTERS_CFG_CHECKWORD 0x4C414D50 // "LAMP"
|
||||
#define LEDFILTERS_MAX_STEPS 250 // 255 MAX !
|
||||
|
||||
#define DEF_STRIP_LEN WS2812_LEDS_MAX
|
||||
#define MAX_STRIP_LEN WS2812_LEDS_MAX
|
||||
#define MAX_STRIP_BRIGHT 255
|
||||
#define MAX_STRIP_DELAY 500
|
||||
|
||||
#pragma region Rainbow
|
||||
typedef struct
|
||||
{
|
||||
uint8_t enabled;
|
||||
uint32_t valid;
|
||||
uint32_t hue_steps; // кол.во светодиодов, в которое вместить радугу
|
||||
uint8_t cycle_steps; // типа скорости
|
||||
uint8_t curr_hue;
|
||||
} ctx_rainbow_t;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Fade
|
||||
typedef struct
|
||||
{
|
||||
uint8_t enabled;
|
||||
uint32_t valid;
|
||||
uint32_t steps;
|
||||
uint32_t min;
|
||||
uint32_t max;
|
||||
uint32_t curr_val;
|
||||
int32_t curr_step;
|
||||
} ctx_fade_t;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Wave
|
||||
typedef struct
|
||||
{
|
||||
uint8_t enabled;
|
||||
uint32_t valid;
|
||||
uint8_t wave_steps;
|
||||
uint8_t step;
|
||||
uint8_t angle;
|
||||
} ctx_wave_t;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Constant
|
||||
typedef struct
|
||||
{
|
||||
uint8_t enabled;
|
||||
uint8_t hue;
|
||||
uint8_t sat;
|
||||
uint8_t value;
|
||||
uint8_t update;
|
||||
uint32_t valid;
|
||||
} ctx_const_t;
|
||||
#pragma endregion
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t check;
|
||||
ws2812_hsv_t *hsv_vals;
|
||||
uint32_t strip_len;
|
||||
uint32_t brightness;
|
||||
uint32_t delay;
|
||||
uint8_t enable;
|
||||
uint8_t try_enable;
|
||||
} strip_handler_t;
|
||||
|
||||
int32_t ledFilter_Init(strip_handler_t *strip, ws2812_t *ws2812);
|
||||
|
||||
void ledFilter_InitRainbow(ctx_rainbow_t *ctx);
|
||||
void ledFilter_Rainbow(ctx_rainbow_t *ctx, strip_handler_t *strip);
|
||||
void ledFilter_InitFade(ctx_fade_t *ctx);
|
||||
void ledFilter_Fade(ctx_fade_t *ctx, strip_handler_t *strip);
|
||||
void ledFilter_InitWave(ctx_wave_t *ctx);
|
||||
void ledFilter_Wave(ctx_wave_t *ctx, strip_handler_t *strip);
|
||||
void ledFilter_InitConstant(ctx_const_t *ctx);
|
||||
void ledFilter_Constant(ctx_const_t *ctx, strip_handler_t *strip);
|
||||
void ledFilter_SetDefualtValue(strip_handler_t *strip, uint8_t val);
|
||||
|
||||
#endif // _LEDFILTERS_H_
|
||||
329
Firmware/Project/WS2812/ws2812.c
Normal file
329
Firmware/Project/WS2812/ws2812.c
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
#include "ws2812.h"
|
||||
|
||||
/* Quick and dirty, we use one big DMA buffer for the whole strip length.
|
||||
* TODO: use smaller DMA buffer and fill in bit patterns on the fly */
|
||||
uint8_t dma_buffer[WS2812_DMABUF_LEN(WS2812_LEDS_MAX)];
|
||||
|
||||
/* scale uint8 value from range 2-255 to range 0-scale */
|
||||
static inline uint8_t WS2812_Scale(uint8_t value, uint8_t scale)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = value * scale;
|
||||
tmp /= 256;
|
||||
|
||||
return (uint8_t)tmp;
|
||||
}
|
||||
|
||||
// wake up waiting tasks when DMA transfer is complete
|
||||
static void master_tr_done_callback(void *pdata, SpiIrq event)
|
||||
{
|
||||
BaseType_t task_woken, result;
|
||||
ws2812_t *cfg;
|
||||
|
||||
task_woken = pdFALSE;
|
||||
cfg = (ws2812_t *) pdata;
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case SpiRxIrq:
|
||||
break;
|
||||
|
||||
case SpiTxIrq:
|
||||
result = xEventGroupSetBitsFromISR(cfg->events, BIT_DONE, &task_woken);
|
||||
if(result == pdPASS)
|
||||
{
|
||||
portYIELD_FROM_ISR(task_woken);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DBG_8195A("WS2812: Unknown SPI irq event!\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void WS2812_HSV2RGB(ws2812_hsv_t *hsv, ws2812_rgb_t *rgb)
|
||||
{
|
||||
//uint8_t r, g, b;
|
||||
uint8_t hue, sat, val;
|
||||
uint8_t base, sector, offset;
|
||||
uint8_t rise, fall;
|
||||
|
||||
// scale hue to range 0- 3*64. Makes subsequent calculations easier
|
||||
hue = WS2812_Scale(hsv->hue, 192);
|
||||
sat = hsv->sat;
|
||||
val = hsv->value;
|
||||
|
||||
sector = hue / 64;
|
||||
offset = hue % 64;
|
||||
|
||||
// get common white base level and remaining colour amplitude
|
||||
base = 255 - sat;
|
||||
|
||||
rise = (offset * sat * 4) / 256;
|
||||
fall = 255 - base - rise;
|
||||
|
||||
rise = (rise * val) / 256;
|
||||
fall = (fall * val) / 256;
|
||||
base = (base * val) / 256;
|
||||
|
||||
rgb->r = base;
|
||||
rgb->g = base;
|
||||
rgb->b = base;
|
||||
|
||||
switch (sector)
|
||||
{
|
||||
case 0:
|
||||
rgb->r += fall;
|
||||
rgb->g += rise;
|
||||
break;
|
||||
case 1:
|
||||
rgb->g += fall;
|
||||
rgb->b += rise;
|
||||
break;
|
||||
case 2:
|
||||
rgb->r += rise;
|
||||
rgb->b += fall;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert a RGB byte into SPI data stream with 2 bits per byte
|
||||
static uint8_t *WS2812_RGB2PWM(uint8_t *dst, const uint8_t colour)
|
||||
{
|
||||
uint8_t cnt, data = colour;
|
||||
|
||||
for (cnt = 0; cnt < 4; cnt++)
|
||||
{
|
||||
switch (data & 0xC0)
|
||||
{
|
||||
case 0x00:
|
||||
*dst = WS2812_BITS_00;
|
||||
break;
|
||||
case 0x40:
|
||||
*dst = WS2812_BITS_01;
|
||||
break;
|
||||
case 0x80:
|
||||
*dst = WS2812_BITS_10;
|
||||
break;
|
||||
case 0xC0:
|
||||
*dst = WS2812_BITS_11;
|
||||
break;
|
||||
}
|
||||
dst++;
|
||||
data <<= 2;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
int32_t WS2812_Tx(ws2812_t *cfg, uint16_t delay)
|
||||
{
|
||||
EventBits_t rcvd_events;
|
||||
TickType_t timeout;
|
||||
BaseType_t status;
|
||||
|
||||
// wait for any SPI transfer to finish
|
||||
while(cfg->spi_master.state & SPI_STATE_TX_BUSY)
|
||||
{
|
||||
vTaskDelay(0);
|
||||
}
|
||||
|
||||
// obey requested delay
|
||||
if(delay > 0)
|
||||
{
|
||||
vTaskDelay(delay);
|
||||
}
|
||||
|
||||
// lock the DMA buffer mutex while it is transferred
|
||||
status = xSemaphoreTake(cfg->mutex, configTICK_RATE_HZ);
|
||||
if(status != pdTRUE)
|
||||
{
|
||||
printf("WS2812: [%s] Timeout waiting for config mutex.\n", __func__);
|
||||
xSemaphoreGive(cfg->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(cfg->dma_buff == NULL || cfg->buff_len == 0)
|
||||
{
|
||||
printf("WS2812: [%s] DMA buffer invalid\n", __func__);
|
||||
xSemaphoreGive(cfg->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xEventGroupClearBits(cfg->events, BIT_DONE);
|
||||
spi_master_write_stream_dma(&cfg->spi_master, (char *)(cfg->dma_buff), cfg->buff_len);
|
||||
|
||||
timeout = 1000 / portTICK_PERIOD_MS;
|
||||
rcvd_events = xEventGroupWaitBits(
|
||||
cfg->events,
|
||||
BIT_DONE, // wait for DMA TX done
|
||||
pdTRUE, // clear event bit
|
||||
pdFALSE, // do not wait for all bits to be set
|
||||
timeout );
|
||||
|
||||
if(!(rcvd_events & BIT_DONE))
|
||||
{
|
||||
printf("WS2812: [%s] DMA timeout\n", __func__);
|
||||
xSemaphoreGive(cfg->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xSemaphoreGive(cfg->mutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t ws2812_Update(ws2812_t *cfg, ws2812_hsv_t hsv_values[], uint32_t strip_len, uint16_t delay)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t *bufp;
|
||||
uint16_t len;
|
||||
BaseType_t status;
|
||||
ws2812_rgb_t rgb;
|
||||
|
||||
// Æäåì, ïîêà îñâîáîäèòñÿ áóôôåð DMA
|
||||
while(cfg->spi_master.state & SPI_STATE_TX_BUSY)
|
||||
{
|
||||
vTaskDelay(0);
|
||||
}
|
||||
|
||||
status = xSemaphoreTake(cfg->mutex, configTICK_RATE_HZ);
|
||||
if(status != pdTRUE)
|
||||
{
|
||||
printf("WS2812: [%s] Timeout waiting for config mutex.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
bufp = &(cfg->dma_buff[0]);
|
||||
|
||||
// Ïðîâåðêà íà âìåùàåìîñòü è êîïèðîâàíèå
|
||||
len = min(strip_len, cfg->strip_len);
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
WS2812_HSV2RGB(&hsv_values[i], &rgb);
|
||||
bufp = WS2812_RGB2PWM(bufp, rgb.g);
|
||||
bufp = WS2812_RGB2PWM(bufp, rgb.r);
|
||||
bufp = WS2812_RGB2PWM(bufp, rgb.b);
|
||||
}
|
||||
|
||||
// Âñå íå èñïîëüçóåìûå ïèêñåëè - âûêëþ÷àåì
|
||||
if(cfg->strip_len > len)
|
||||
{
|
||||
memset(bufp, WS2812_BITS_00, cfg->strip_len - len);
|
||||
bufp += cfg->strip_len - len;
|
||||
}
|
||||
|
||||
memset(bufp, 0x0, WS2812_RESET_LEN);
|
||||
xSemaphoreGive(cfg->mutex);
|
||||
|
||||
return WS2812_Tx(cfg, delay);
|
||||
}
|
||||
|
||||
ws2812_t *ws2812_Init(uint16_t strip_len)
|
||||
{
|
||||
int32_t result;
|
||||
ws2812_t *cfg;
|
||||
|
||||
result = 0;
|
||||
|
||||
cfg = malloc(sizeof(ws2812_t));
|
||||
if(cfg == NULL)
|
||||
{
|
||||
printf("WS2812: [%s] malloc for cfg failed\n", __func__);
|
||||
result = -1;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
memset(cfg, 0x0, sizeof(ws2812_t));
|
||||
|
||||
cfg->mutex = xSemaphoreCreateMutex();
|
||||
if(cfg->mutex == NULL)
|
||||
{
|
||||
printf("WS2812: [%s] Mutex creation failed\n", __func__);
|
||||
result = -1;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
cfg->events = xEventGroupCreate();
|
||||
if(cfg->events == NULL)
|
||||
{
|
||||
printf("WS2812: [%s] Creating event group failed\n", __func__);
|
||||
result = -1;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
spi_init(&(cfg->spi_master), WS2812_SPI_MOSI, WS2812_SPI_MISO, WS2812_SPI_SCLK, WS2812_SPI_CS);
|
||||
spi_format(&(cfg->spi_master), 8, 3, 0);
|
||||
spi_frequency(&(cfg->spi_master), WS2812_SPI_FREQ);
|
||||
spi_irq_hook(&(cfg->spi_master), (spi_irq_handler)master_tr_done_callback, (uint32_t)cfg);
|
||||
|
||||
result = ws2812_SetLen(cfg, strip_len);
|
||||
if(!result)
|
||||
{
|
||||
printf("WS2812: [%s] ws2812_set_len() failed\n", __func__);
|
||||
}
|
||||
|
||||
err_out:
|
||||
if(!result && cfg != NULL)
|
||||
{
|
||||
if(cfg->mutex != NULL)
|
||||
{
|
||||
vQueueDelete(cfg->mutex);
|
||||
}
|
||||
|
||||
if(cfg->events != NULL)
|
||||
{
|
||||
vEventGroupDelete(cfg->events);
|
||||
}
|
||||
|
||||
if(cfg->dma_buff != NULL)
|
||||
{
|
||||
free(cfg->dma_buff);
|
||||
}
|
||||
|
||||
free(cfg);
|
||||
cfg = NULL;
|
||||
}
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
int32_t ws2812_SetLen(ws2812_t *cfg, uint16_t strip_len)
|
||||
{
|
||||
BaseType_t status;
|
||||
uint32_t reset_off;
|
||||
|
||||
if(cfg == NULL)
|
||||
{
|
||||
printf("WS2812: [%s] no config given\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// lock the config mutex
|
||||
status = xSemaphoreTake(cfg->mutex, configTICK_RATE_HZ);
|
||||
if(status != pdTRUE)
|
||||
{
|
||||
printf("WS2812: [%s] Timeout waiting for config mutex.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(strip_len <= WS2812_LEDS_MAX)
|
||||
{
|
||||
/* TODO: use dynamically allocated buffer */
|
||||
cfg->dma_buff = dma_buffer;
|
||||
|
||||
/* initialise LEDs to off and add reset pulse at end of strip */
|
||||
reset_off = WS2812_DMABUF_LEN(strip_len) - WS2812_RESET_LEN;
|
||||
memset(&(cfg->dma_buff[0]), WS2812_BITS_00, reset_off);
|
||||
memset(&(cfg->dma_buff[reset_off]), 0x0, WS2812_RESET_LEN);
|
||||
cfg->strip_len = strip_len;
|
||||
cfg->buff_len = WS2812_DMABUF_LEN(strip_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("WS2812: [%s] Strip too long for DMA buffer\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xSemaphoreGive(cfg->mutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
64
Firmware/Project/WS2812/ws2812.h
Normal file
64
Firmware/Project/WS2812/ws2812.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#ifndef _WS2812_H_
|
||||
#define _WS2812_H_
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "event_groups.h"
|
||||
#include <spi_api.h>
|
||||
#include <spi_ex_api.h>
|
||||
#include <autoconf.h>
|
||||
#include <platform_stdlib.h>
|
||||
#include "semphr.h"
|
||||
#include "event_groups.h"
|
||||
#include "macro_common.h"
|
||||
|
||||
#define WS2812_LEDS_MAX 228
|
||||
#define WS2812_RESET_LEN (50 / 2)
|
||||
#define WS2812_DMABUF_LEN(x) ((x) * 3 * 4 + WS2812_RESET_LEN)
|
||||
|
||||
#define WS2812_SPI_FREQ 3400000 // и делённое на 4 (4 бита SPI за 1 бит WS8212) ~~ в итоге 800кГц
|
||||
#define WS2812_SPI_MOSI PC_2 // SPI0
|
||||
#define WS2812_SPI_MISO PC_3
|
||||
#define WS2812_SPI_SCLK PC_1
|
||||
#define WS2812_SPI_CS PC_0
|
||||
|
||||
// Events to signal completion of DMA transfer
|
||||
#define BIT_START (1 << 0)
|
||||
#define BIT_DONE (1 << 1)
|
||||
|
||||
// посылается 2 бита протокола WS2812 за один байт SPI, один бит WS2812 за 4 бита SPI.
|
||||
#define WS2812_BITS_00 0x88
|
||||
#define WS2812_BITS_01 0x8e
|
||||
#define WS2812_BITS_10 0xe8
|
||||
#define WS2812_BITS_11 0xee
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
} ws2812_rgb_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t hue;
|
||||
uint8_t sat;
|
||||
uint8_t value;
|
||||
} ws2812_hsv_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
spi_t spi_master;
|
||||
EventGroupHandle_t *events;
|
||||
SemaphoreHandle_t *mutex;
|
||||
uint8_t *dma_buff;
|
||||
size_t buff_len;
|
||||
uint16_t strip_len;
|
||||
} ws2812_t;
|
||||
|
||||
ws2812_t *ws2812_Init(uint16_t len);
|
||||
int32_t ws2812_SetLen(ws2812_t *cfg, uint16_t len);
|
||||
//int32_t WS2812_DeInit(WS2812_t *cfg);
|
||||
int32_t ws2812_Update(ws2812_t *cfg, ws2812_hsv_t hsv[], uint32_t len, uint16_t delay);
|
||||
|
||||
#endif // _WS2812_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue