Что такое адресные RGB светодиоды WS2812
Адресные светодиоды — светодиоды, которые управляются световым сигналом по 1 линии данных. С контроллера приходит пакет данных на первый адресный RGB LED. Пакет данных содержит в себе все цвета всех светодиодов в цепочке. Первый светодиод забирает себе первые 24Bit из пакета данных и отправляет оставшиеся данные второму светодиоду. И так далее…
Светодиоды бывают в разных корпусах и также продаются распаянные на гибкие ленты.


Схема подключения WS2812

Логический уровень WS2812 5V. Они могут управляться логическим сигналом с уровнем 3,3V только на плате или на коротких (до пары метров) проводах при условии питания RGB LED не более 5V.
Протокол данных WS2812



Настройка частоты таймера и включение DMA
Частота работы адресных RGB светодиодов WS2812 800kHz.
Чтобы рассчитать делители таймера, воспользуйтесь этой формулой
Counter Period = ( Timer Clock / (Prescaler + 1) / 800000 ) — 1
Counter Period = ( 64000000 / (0 + 1) / 800000 ) — 1 = 79


Длину испольсов 0 и 1 для WS2812 нужно подобрать с помощью осциллографа или логического анализатора.
Для 0 Pulse должен быть ~450nS
Для 1 Pulse должен быть ~800nS
Полный период 1250nS (800kHz)
Для STM32G0 Timer DMA (с настройками тактирования таймеров, какие показаны на скриншоте выше)
WS2812 0: Pulse = 30
WS2812 1: Pulse = 53
Количество импульсов для каждого RGB LED WS2812 = 24 + в конце серии импульсов (для всех LED) 50uS задержка (сигнал LOW).
Теперь, чтобы таймер STM32 в режиме PWM Generation отправлял RGB светодиодам импульсы разной длины нужно включить DMA

Для STM32G0 в качестве массива с длинами импульсов можно использовать 8Bit массив (Byte). В других сериях STM32 Byte массив может некорректно работать. В таких случаях укажите не Byte, а Half Word и используйте массив uint16_t, а не uint8_t.
1 2 | uint8_t pwmData[LEDPWMDataLength]; uint16_t pwmData[LEDPWMDataLength]; |
Настройка параметров GPIO для Data Pin for WS2812

ВАЖНО: Не рекомендуется оставлять линию данных для RGB LED WS2812 без подтяжки (комментарии по этому моменту в видео).
Программируем RGB LED WS2812 на STM32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | ... /* USER CODE BEGIN 0 */ #define MAXIMAL_LEDC 23 uint8_t LED_Data[MAXIMAL_LEDC][3]; volatile uint8_t t_RGBLEDDataWasSent = 0; #define LEDPWMDataLength (24 * MAXIMAL_LEDC) + 50 uint8_t pwmData[LEDPWMDataLength]; void WS2812_ResetPWM_Array(void) { uint16_t i = 0; while (i < LEDPWMDataLength) { pwmData[i] = 0; i++; } } void WS2812_Send(void) { uint32_t indx=0; uint32_t color; for (int i= 0; i<MAXIMAL_LEDC; i++) { color = ((LED_Data[i][0]<<16) | (LED_Data[i][1]<<8) | (LED_Data[i][2])); for (int j=23; j>=0; j--) { if (color&(1<<j)) { pwmData[indx] = 53; // 2/3 of 90 } else pwmData[indx] = 30; // 1/3 of 90 indx++; } } t_RGBLEDDataWasSent = 0; HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_4, (uint32_t *)pwmData, LEDPWMDataLength); while (!t_RGBLEDDataWasSent) {}; } void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { if(htim->Instance == TIM1) { HAL_TIM_PWM_Stop_DMA(&htim1, TIM_CHANNEL_4); t_RGBLEDDataWasSent = 1; } } void SETLedS(uint8_t R, uint8_t G, uint8_t B) { uint8_t i = 0; while (i < MAXIMAL_LEDC) { LED_Data[i][0] = G; LED_Data[i][1] = R; LED_Data[i][2] = B; i++; } WS2812_Send(); } void Set_LED(int LEDnum, int Red, int Green, int Blue) { LED_Data[LEDnum][0] = Green; LED_Data[LEDnum][1] = Red; LED_Data[LEDnum][2] = Blue; } /* USER CODE END 0 */ ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ... /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ WS2812_ResetPWM_Array(); while (1) { SETLedS(0, 2, 0); HAL_Delay(1000); SETLedS(0, 0, 20); HAL_Delay(1000); SETLedS(2, 0, 0); HAL_Delay(1000); /* USER CODE END WHILE */ ... |
#define MAXIMAL_LEDC 23 — количество используемых RGB LED светодиодов
WS2812_ResetPWM_Array(); — сброс массива с данными для PWM Generation DMA
SETLedS(uint8_t R, uint8_t G, uint8_t B) — установить цвет для ВСЕХ светодиодов
Set_LED(int LEDnum, int Red, int Green, int Blue) — установить цвет для светодиода с индексом LEDnum
В видео подробно пояснено, как пользоваться функциями для WS2812.
