178 lines
5.7 KiB
C++
178 lines
5.7 KiB
C++
/**
|
|
* @file WS2812.cpp
|
|
* @brief WS2812 RGB LED driver
|
|
*
|
|
* @date 25.03.2023
|
|
* @author Benas Brazdziunas
|
|
*/
|
|
|
|
#include "pch.h"
|
|
|
|
#if EFI_WS2812
|
|
|
|
#include "WS2812.h"
|
|
#include "ws2812_conf.h"
|
|
|
|
|
|
static WS2812_RGB_t WS2812_LED_BUF[WS2812_LED_N];
|
|
static uint32_t WS2812_TIM_BUF[WS2812_BUFLEN];
|
|
static uint8_t WS2812_BRIGHTNESS = 20;
|
|
|
|
void initWS2812()
|
|
{
|
|
palSetPadMode(WS2812_PORT, WS2812_PIN, PAL_MODE_ALTERNATE(1));
|
|
|
|
static const PWMConfig ws2812_pwm_config = {
|
|
.frequency = WS2812_PWM_FREQUENCY,
|
|
.period = WS2812_PWM_PERIOD,
|
|
.callback = NULL,
|
|
.channels = {
|
|
[0] = {.mode = WS2812_TIM_CH == 0 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED, .callback = NULL}, // Turn on the channel we care about
|
|
[1] = {.mode = WS2812_TIM_CH == 1 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED, .callback = NULL}, // Turn on the channel we care about
|
|
[2] = {.mode = WS2812_TIM_CH == 2 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED, .callback = NULL}, // Turn on the channel we care about
|
|
[3] = {.mode = WS2812_TIM_CH == 3 ? PWM_OUTPUT_ACTIVE_HIGH : PWM_OUTPUT_DISABLED, .callback = NULL}, // Turn on the channel we care about
|
|
},
|
|
.cr2 = 0,
|
|
#if STM32_PWM_USE_ADVANCED
|
|
.bdtr = 0,
|
|
#endif
|
|
.dier = TIM_DIER_UDE, // DMA on update event for next period
|
|
};
|
|
|
|
const stm32_dma_stream_t *dma = dmaStreamAlloc(WS2812_DMA_STREAM, 10, NULL, NULL);
|
|
dmaStreamSetPeripheral(dma, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_TIM_CH]));
|
|
dmaStreamSetMemory0(dma, WS2812_TIM_BUF);
|
|
dmaStreamSetTransactionSize(dma, WS2812_BUFLEN);
|
|
// M2P: Memory 2 Periph; PL: Priority Level
|
|
dmaStreamSetMode(dma,
|
|
STM32_DMA_CR_CHSEL(WS2812_DMA_CHANNEL) |
|
|
STM32_DMA_CR_DIR_M2P |
|
|
STM32_DMA_CR_PSIZE_WORD |
|
|
STM32_DMA_CR_MSIZE_WORD |
|
|
STM32_DMA_CR_MINC |
|
|
STM32_DMA_CR_CIRC |
|
|
STM32_DMA_CR_PL(3)
|
|
);
|
|
|
|
dmaStreamEnable(dma);
|
|
pwmStart(&PWMD1, &ws2812_pwm_config);
|
|
pwmEnableChannel(&PWMD1, WS2812_TIM_CH, 0); //(WS2812_PWM_PERIOD/2)
|
|
|
|
//TEST FUNCTIONALITY
|
|
clearWS2812All();
|
|
setWS2812Brightness(5);
|
|
setWS2812All((WS2812_RGB_t){255, 0, 0});
|
|
setWS2812One(19,(WS2812_RGB_t){0, 0, 255});
|
|
setWS2812One(9,(WS2812_RGB_t){0, 255, 0});
|
|
clearWS2812One(18);
|
|
}
|
|
|
|
/**
|
|
* Set one LEDs to 0 (off)
|
|
*/
|
|
void clearWS2812One(uint32_t num)
|
|
{
|
|
if (num < WS2812_LED_N)
|
|
{
|
|
WS2812_LED_BUF[num] = (WS2812_RGB_t){0, 0, 0};
|
|
}
|
|
calcBuf();
|
|
}
|
|
|
|
/**
|
|
* Set all LEDs to 0 (off)
|
|
*/
|
|
void clearWS2812All()
|
|
{
|
|
for (uint16_t num = 0; num < WS2812_LED_N; num++)
|
|
{
|
|
WS2812_LED_BUF[num] = (WS2812_RGB_t){0, 0, 0};
|
|
}
|
|
calcBuf();
|
|
}
|
|
|
|
/**
|
|
* Set one LED (R, G, B values).
|
|
*/
|
|
void setWS2812One(uint32_t num, WS2812_RGB_t rgb_col)
|
|
{
|
|
if (num < WS2812_LED_N)
|
|
{
|
|
WS2812_LED_BUF[num] = rgb_col;
|
|
}
|
|
calcBuf();
|
|
}
|
|
|
|
/**
|
|
* Set all LEDs (R, G, B values).
|
|
*/
|
|
void setWS2812All(WS2812_RGB_t rgb_col)
|
|
{
|
|
for (uint16_t num = 0; num < WS2812_LED_N; num++)
|
|
{
|
|
WS2812_LED_BUF[num] = rgb_col;
|
|
}
|
|
calcBuf();
|
|
}
|
|
|
|
/**
|
|
* Set all LEDs Brightness.
|
|
*/
|
|
void setWS2812Brightness(uint8_t num)
|
|
{
|
|
num = num >= 100 ? 100 : num;
|
|
num = num <= 0 ? 0 : num;
|
|
WS2812_BRIGHTNESS = num;
|
|
calcBuf();
|
|
}
|
|
|
|
/**
|
|
* Calculate Timer DMA buffer
|
|
*/
|
|
void calcBuf()
|
|
{
|
|
uint32_t pos = 0;
|
|
// set timings for all LEDs
|
|
for (uint32_t num = 0; num < WS2812_LED_N; num++)
|
|
{
|
|
WS2812_RGB_t led = WS2812_LED_BUF[num];
|
|
float brightness = WS2812_BRIGHTNESS / 100.0;
|
|
|
|
led.red = (uint8_t)(led.red * brightness);
|
|
led.green = (uint8_t)(led.green * brightness);
|
|
led.blue = (uint8_t)(led.blue * brightness);
|
|
|
|
// Col:Green , Bit:7..0
|
|
WS2812_TIM_BUF[pos++] = ((led.green & 0x80) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.green & 0x40) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.green & 0x20) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.green & 0x10) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.green & 0x08) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.green & 0x04) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.green & 0x02) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.green & 0x01) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
|
|
// Col:Red , Bit:7..0
|
|
WS2812_TIM_BUF[pos++] = ((led.red & 0x80) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.red & 0x40) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.red & 0x20) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.red & 0x10) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.red & 0x08) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.red & 0x04) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.red & 0x02) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.red & 0x01) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
|
|
// Col:Blue , Bit:7..0
|
|
WS2812_TIM_BUF[pos++] = ((led.blue & 0x80) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.blue & 0x40) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.blue & 0x20) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.blue & 0x10) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.blue & 0x08) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.blue & 0x04) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.blue & 0x02) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
WS2812_TIM_BUF[pos++] = ((led.blue & 0x01) != 0) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
|
|
}
|
|
}
|
|
|
|
#endif /* EFI_WS2812 */
|