Library for addressable STM32 LEDs
Driver for STM32 to implement the protocol targeted LEDs (WS2812, WS2811, SK6812etc.), with rational using buffer memory and DMA.
Link to the library on GitHub:
Video on YouTube:
Connection and setup
On a pin DIN the first LED (beginning of the tape) receives a signal generated by the STM32. Due to the difference in supply voltages, the signal follows raise to a level of 5 volts using a special translator chips logic or by setting the GPIO pin in the mode open drainby pulling it up with a resistor.
IMPORTANT!
When using Open Drain, you need to make sure that the pin can withstand 5 volts. You can find out in the datasheet on your MK.
Example:
Timer setting in CubeMX
RESTRICTIONS: Due to the nature of the timers, the minimum stable frequency of the microcontroller is 32 MHz.
First you need to set the timer in mode PWM. Pay attention to the settings marked with arrows.
Sending values to the timer is done using DMAso let’s configure this block as well.
The leg must have top speed from available. If the mode is selected open drainthen don’t forget to switch.
Also check that the generation DMA_Init worth higher than TIM_Init. Otherwise, the timer will not know about DMA, the signal will not be generated.
Library setup
Let’s generate the code, add files libraries to the project. Let’s open .h-file and see what you can customize.
#define WS2811 ///< Семейство: {WS2811S, WS2811F, WS2812, SK6812}
// WS2811S — RGB, 400kHz;
// WS2811F — RGB, 800kHz;
// WS2812 — GRB, 800kHz;
// SK6812 — RGBW, 800kHz
#define NUM_PIXELS 4 ///< Кол-во диодов в цепочке
// Гамма-коррекция, должна чинить красный и зелёный, пробуйте и смотрите
#define USE_GAMMA_CORRECTION 1
#define TIM_NUM 2 ///< Номер таймера
#define TIM_CH TIM_CHANNEL_2 ///< ШИМ-канал таймера
#define DMA_HANDLE hdma_tim2_ch2 ///< Канал DMA
// Канал DMA можно найти в main.c / tim.c
Function Reference
Now, to check, you can try score project and look at the available features. All methods return enum statuses.
typedef enum ARGB_STATE {
ARGB_BUSY = 0, ///< DMA-отправка в процессе
ARGB_READY = 1, ///< DMA Готов к отправке
ARGB_OK = 2, ///< Успешное выполнение функции
ARGB_PARAM_ERR = 3, ///< Ошибка входных параметров
} ARGB_STATE;
ARGB_STATE ARGB_Init(void); // Инициализация
ARGB_STATE ARGB_Clear(void); // Очистка ленты
ARGB_STATE ARGB_SetBrightness(u8_t br); // Установить глобальную яркость
ARGB_STATE ARGB_SetRGB(u16_t i, u8_t r, u8_t g, u8_t b); // Зажечь диод в RGB
ARGB_STATE ARGB_SetHSV(u16_t i, u8_t hue, u8_t sat, u8_t val); // Зажечь диод в HSV
ARGB_STATE ARGB_SetWhite(u16_t i, u8_t w); // Зажечь белый компонент (для RGBW)
ARGB_STATE ARGB_FillRGB(u8_t r, u8_t g, u8_t b); // Залить всё в RGB
ARGB_STATE ARGB_FillHSV(u8_t hue, u8_t sat, u8_t val); // Залить всё в HSV
ARGB_STATE ARGB_FillWhite(u8_t w); // Заливка белого компонента (для RGBW)
ARGB_STATE ARGB_Ready(void); // Получить статус DMA
ARGB_STATE ARGB_Show(void); // Обновить диоды
Usage example
void main(void) {
ARGB_Init();
ARGB_Clear();
while (ARGB_Show() == ARGB_BUSY) ; // Вариант 1
ARGB_SetRGB(0, 255, 0, 128);
ARGB_SetHSV(1, 230, 250, 255);
while (!ARGB_Show()) ; // Вариант 2
ARGB_SetRGB(3, 200, 0, 200);
// Вариант 3:
while (ARGB_GetState() != ARGB_READY) ;
ARGB_Show();
}
Description
Addressable tape LEDs are used for various indications, both household and commercial. key difference from conventional RGB diodes in that they can be lit separatelyeach with its own color.
This behavior is due to the fact that each diode has a chip driver. Outside, as in the case of WS2811, or inside, as in WS2812 and others.
The chip receives a signal, remembers the first pulses, and transmits the rest further along the chain.
Data protocol
The glow of everyone subpixel is encoded 8 bits. Those. for RGB (WS281X) 24 bitsfor RGBW (SK6812) 32 bits.
The bit code is given by the pulse length, i.e. duty cycle.
There is also a code RET – a pause, indicating the end of the transmission.
For all controllers different timings:
WS2811 (slow) | WS2811 (fast, SET=1) | WS2812(b) | SK6812 | |
Frequency | 400 kHz | 800 kHz | 800 kHz | 800 kHz |
Period (T) | 2.5 µs | 1.25 µs | 1.25 µs | 1.25 µs |
T0H | 0.5 µs (20%) | 0.25 µs (20%) | 0.35 µs (28%) | 0.3 µs (24%) |
T1H | 1.2 µs (48%) | 0.6 µs (48%) | 0.7 µs (56%) | 0.6 µs (48%) |
T0L | 2.0 µs | 1.0 µs | 0.8 µs | 0.9 µs |
T1L | 1.3 µs | 0.65 µs | 0.6 µs | 0.6 µs |
Tolerance | +/- 150 ns | +/- 150 ns | +/- 150 ns | +/- 150 ns |
RET | > 50 µs (20T) | > 50 µs (40T) | > 50 µs (40T) | > 80 µs (64T) |
Implementation on STM32
Most of the solutions are based on the use of empty cycles. It means that the whole the processor slows down for the duration of the signal. This method not only wastes a lot of CPU time, but also risks breaking if an interrupt occurs.
Let’s calculate the signal transmission length for 1 diode: 1.25 µs * 24 bits = 30 µs.
For n diodes: T=30*n+50 ms.
30 diodes – already 1 millisecond.
In other words, the delay protocol should only be used for small number of diodes so as not to interfere with the main program.
It was because of this problem that I first turned to the STM32.
Other options use a tire SPIwhich is tuned to the frequency 800 kHz. I did not check, but many write about a noticeable loss in signal accuracy.
What to do?
In almost all STM32 microcontrollers, there is a block DMA (Direct Memory Access). It allows you to transfer data between periphery and memory in different directions without the participation of the processor.
Used as an execution peripheral timerconfigured in mode PWM.
buffer array
Any method of signal transmission implies a buffer in which values are stored duty cycle signal.
There are many buffer options on the web just below all diodes. Most often, the duty cycle is 8-bit, so this will weigh N diodes * 24 bytes. Already under 100 diodes he will take more than 2 KB of RAM.
And if you write the duty cycle with the width 32 bitsas required by some MK series, under 100 diodes the buffer will be more 9 KB.
The implementation of my method was not invented by me. She is very cunningly memory is used.
buffer here double. The first one has the size N diodes * 3 bytes. It stores the color in the view RGB.
The second buffer is for duty cycles. It is fixed and takes only 48 bytesor 64 bytes for RGBW. It contains all 2 diodes.
Interrupts DMA allow one part of the buffer to be filled while the other part is being sent. Using this approach, it is possible to stretch the diode chain almost up to infinityas long as there is enough memory for the primary buffer or refresh rate.
Logic transformation
The fact is that the addressable diodes perceive the signal based on the voltage of their supply.
Opening the datasheet WS2812bwe will see lines like this:
Min | Max | |
VIH | 0.7VDD | — |
VIL | — | 0.3VDD |