* WS2812 LED strip on TIM1_CH1_UP using pin PE9 and DMA.

* Applied suggestions

* linux and Windows have different approach

* linux and Windows have different approach

---------

Co-authored-by: benas-gavea <bbrazdziunas@gavea.co.uk>
Co-authored-by: rusefillc <sdfsdfqsf2334234234>
This commit is contained in:
rusefillc 2023-04-03 11:31:07 -04:00 committed by GitHub
parent c4fa460c29
commit 1f3b3e82fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 233 additions and 3 deletions

View File

@ -37,6 +37,8 @@ DDEFS += -DTS_SECONDARY_UxART_PORT=SD3
DDEFS += -DSTM32_I2C_USE_I2C3=TRUE
DDEFS += -DEFI_WS2812=TRUE
ifndef IS_RE_BOOTLOADER
DDEFS += -DHAL_USE_EEPROM=TRUE
endif

View File

@ -7,7 +7,8 @@ HW_LAYER_DRIVERS_INC = \
$(DRIVERS_DIR)/sent \
$(DRIVERS_DIR)/serial \
$(DRIVERS_DIR)/i2c \
$(DRIVERS_DIR)/lcd
$(DRIVERS_DIR)/lcd \
$(DRIVERS_DIR)/led
HW_LAYER_DRIVERS_CORE = \
@ -33,4 +34,5 @@ HW_LAYER_DRIVERS_CPP = \
$(DRIVERS_DIR)/gpio/l9779.cpp \
$(DRIVERS_DIR)/gpio/protected_gpio.cpp \
$(DRIVERS_DIR)/sent/sent_hw_icu.cpp \
$(DRIVERS_DIR)/lcd/HD44780.cpp
$(DRIVERS_DIR)/lcd/HD44780.cpp \
$(DRIVERS_DIR)/led/WS2812.cpp

View File

@ -0,0 +1,174 @@
/**
* @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,
.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 */

View File

@ -0,0 +1,25 @@
/**
* @file ws2812.h
*
* @date 25.03.2025
* @author Benas Brazdziunas
*/
#pragma once
typedef struct {
uint8_t red;
uint8_t green;
uint8_t blue;
} WS2812_RGB_t;
void initWS2812();
void clearWS2812One(uint32_t num);
void clearWS2812All();
void setWS2812One(uint32_t num, WS2812_RGB_t rgb_col);
void setWS2812All(WS2812_RGB_t rgb_col);
void setWS2812Brightness(uint8_t num);
void calcBuf();

View File

@ -0,0 +1,20 @@
#define WS2812_LED_N 22 // Number of LEDs
#define WS2812_PORT GPIOE
#define WS2812_PIN 9
#define WS2812_TIM_N 1 // timer, 1-11
#define WS2812_TIM_CH 0 // timer channel, 0-3
#define WS2812_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) //DMA2 Stream 5 // DMA stream for TIMx_UP (look up in reference manual under DMA Channel selection)
#define WS2812_DMA_CHANNEL 6 // DMA channel for TIMx_UP
#define WS2812_PWM_FREQUENCY (STM32_SYSCLK / 2) /**< Clock frequency of PWM, must be valid with respect to system clock! */
#define WS2812_PWM_PERIOD (WS2812_PWM_FREQUENCY / 800000)
#define WS2812_DUTYCYCLE_0 (WS2812_PWM_FREQUENCY / (1000000000 / 220))
#define WS2812_DUTYCYCLE_1 (WS2812_PWM_FREQUENCY / (1000000000 / 580))
#define CONCAT_SYMBOLS(s1, s2) s1##s2
#define CONCAT_EXPANDED_SYMBOLS(s1, s2) CONCAT_SYMBOLS(s1, s2)
#define WS2812_PWM_DRIVER CONCAT_EXPANDED_SYMBOLS(PWMD, WS2812_TIM_N)
#define WS2812_BUFLEN ((WS2812_LED_N + 4) * 24)

View File

@ -55,6 +55,9 @@
#if EFI_MC33816
#include "mc33816.h"
#endif /* EFI_MC33816 */
#if EFI_WS2812
#include "WS2812.h"
#endif /* EFI_WS2812 */
#if EFI_MAP_AVERAGING
#include "map_averaging.h"
@ -575,6 +578,10 @@ void initHardware() {
initHip9011();
#endif /* EFI_HIP_9011 */
#if EFI_WS2812
initWS2812();
#endif /* EFI_LED_WS2812 */
#if EFI_MEMS
initAccelerometer();
#endif

View File

@ -207,7 +207,7 @@
* PWM driver system settings.
*/
#define STM32_PWM_USE_ADVANCED FALSE
#define STM32_PWM_USE_TIM1 FALSE
#define STM32_PWM_USE_TIM1 TRUE
#define STM32_PWM_USE_TIM2 FALSE
#ifndef STM32_PWM_USE_TIM3