1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-05-22     yuanjie      first version, function
9  */
10 
11 /**
12  *  WS2812B serial LED data timing flow:
13  *  | T0H | H | 350ns  | ±150ns   |
14  *  | T0L | L | 800ns  | ±150ns   |
15  *  | T1H | H | 700ns  | ±150ns   |
16  *  | T1L | L | 600ns  | ±150ns   |
17  *  | RES | L | ≥50us  | --       |
18  *  When using TIM peripheral, to meet 800kHz (1250ns) refresh rate:
19  *  - period is:  1250ns
20  *  - logic 0 is: 400ns(H) + 900ns(L)
21  *  - logic 1 is: 900ns(H) + 400ns(L)
22  */
23 
24 #include <rtdevice.h>
25 #include <board.h>
26 #include <drv_matrix_led.h>
27 #include <drv_common.h>
28 #include <drv_gpio.h>
29 
30 #ifndef LED_NUM
31 #define LED_NUM     19 // LED灯珠个数
32 #endif
33 #define LED_MATRIX_EN_PIN   GET_PIN(F, 2)
34 
35 TIM_HandleTypeDef htim3;
36 DMA_HandleTypeDef hdma_tim3_ch2;
37 
38 rt_align(RT_ALIGN_SIZE) uint8_t led_buffer[LED_NUM * 24 * 2];
39 
40 extern void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
41 
42 // 模拟bit码: 2为逻辑0, 7为逻辑1
43 const uint8_t tile[] = {2, 7};
44 
45 
46 // 常见颜色定义
47 
48 const RGBColor_TypeDef DARK = {0, 0, 0};
49 const RGBColor_TypeDef GREEN = {255, 0, 0};
50 const RGBColor_TypeDef RED = {0, 255, 0};
51 const RGBColor_TypeDef BLUE = {0, 0, 255};
52 const RGBColor_TypeDef WHITE = {255, 255, 255};
53 const RGBColor_TypeDef LT_RED = {0, 32, 0};
54 const RGBColor_TypeDef LT_GREEN = {32, 0, 0};
55 const RGBColor_TypeDef LT_BLUE = {0, 0, 32};
56 const RGBColor_TypeDef LT_WHITE = {16, 16, 16};
57 
58 // 灯颜色缓存
59 RGBColor_TypeDef RGB_Data[LED_NUM] = {0};
60 
61 void led_matrix_rst();
62 /**
63  * @brief This function handles DMA2 stream3 global interrupt.
64  */
DMA1_Stream5_IRQHandler(void)65 void DMA1_Stream5_IRQHandler(void)
66 {
67     HAL_DMA_IRQHandler(&hdma_tim3_ch2);
68 }
69 
HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef * htim)70 void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
71 {
72     if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
73     {
74         __HAL_TIM_SetCompare(htim, TIM_CHANNEL_2,0); //占空比清0
75     }
76 }
77 /**
78  * @brief matrix Initialization Function
79  * @param None
80  * @retval None
81  */
matrix_init(void)82 static int matrix_init(void)
83 {
84     TIM_MasterConfigTypeDef sMasterConfig = {0};
85     TIM_OC_InitTypeDef sConfigOC = {0};
86 
87     /* TIM3_CH2 Init */
88     __HAL_RCC_TIM3_CLK_ENABLE();
89 
90     htim3.Instance = TIM3;
91     htim3.Init.Prescaler = 10-1;
92     htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
93     htim3.Init.Period = 10-1;    // 840kHz
94     htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
95     htim3.Init.RepetitionCounter = 0;
96     htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
97     if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
98     {
99         Error_Handler();
100     }
101     sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
102     sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
103     if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
104     {
105         Error_Handler();
106     }
107     sConfigOC.OCMode = TIM_OCMODE_PWM1;
108     sConfigOC.Pulse = 0;
109     sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
110     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
111     if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
112     {
113         Error_Handler();
114     }
115 
116 
117     HAL_TIM_MspPostInit(&htim3);
118 
119     /* TIM3 DMA Init */
120     __HAL_RCC_DMA1_CLK_ENABLE();
121 
122     hdma_tim3_ch2.Instance = DMA1_Stream5;
123     hdma_tim3_ch2.Init.Channel = DMA_CHANNEL_5;
124     hdma_tim3_ch2.Init.Direction = DMA_MEMORY_TO_PERIPH;
125     hdma_tim3_ch2.Init.PeriphInc = DMA_PINC_DISABLE;
126     hdma_tim3_ch2.Init.MemInc = DMA_MINC_ENABLE;
127     hdma_tim3_ch2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
128     hdma_tim3_ch2.Init.MemDataAlignment = DMA_PDATAALIGN_HALFWORD;
129     hdma_tim3_ch2.Init.Mode = DMA_NORMAL;
130     hdma_tim3_ch2.Init.Priority = DMA_PRIORITY_HIGH;
131     hdma_tim3_ch2.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
132     if (HAL_DMA_Init(&hdma_tim3_ch2) != HAL_OK)
133     {
134         Error_Handler();
135     }
136     __HAL_LINKDMA(&htim3, hdma[TIM_DMA_ID_CC2], hdma_tim3_ch2);
137 
138     /* NVIC configuration for DMA transfer complete interrupt */
139     HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
140     HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
141 
142     rt_pin_mode(LED_MATRIX_EN_PIN, PIN_MODE_OUTPUT);
143     rt_pin_write(LED_MATRIX_EN_PIN, PIN_LOW);
144     led_matrix_rst();
145     return RT_EOK;
146 
147 }
148 
149 INIT_APP_EXPORT(matrix_init);
150 
151 /**
152  * @brief           设置灯带颜色发送缓存
153  * @param[in]       ID 颜色
154  */
Set_LEDColor(uint16_t LedId,RGBColor_TypeDef Color)155 void Set_LEDColor(uint16_t LedId, RGBColor_TypeDef Color)
156 {
157     RGB_Data[LedId].G = Color.G;
158     RGB_Data[LedId].R = Color.R;
159     RGB_Data[LedId].B = Color.B;
160 }
161 
162 /**
163  * @brief           TIM发送控制ws2812
164  * @param[in]       待发送缓存
165  */
TIM_Send_WS2812(uint8_t * rgb_buffer,uint32_t size)166 static void TIM_Send_WS2812(uint8_t *rgb_buffer, uint32_t size)
167 {
168     // 判断上次DMA有没有传输完成
169     while (HAL_DMA_GetState(&hdma_tim3_ch2) != HAL_DMA_STATE_READY);
170     // 发送一个24bit的RGB数据
171     HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_2, (uint32_t *)rgb_buffer, size);
172 
173 }
174 
175 /**
176  * @brief           控制WS2812
177  * @param[in]       待发送缓存
178  */
179 
RGB_Reflash(void)180 void RGB_Reflash(void)
181 {
182     uint8_t dat_b,dat_r,dat_g;
183     // 将数组颜色转化为24个要发送的字节数据
184     for (uint16_t i = 0; i < LED_NUM; i++)
185     {
186         dat_g = RGB_Data[i].G;
187         dat_r = RGB_Data[i].R;
188         dat_b = RGB_Data[i].B;
189         for (uint16_t j = 0; j < 8; j++) {
190             led_buffer[(14 + (i * 48))-(j<<1)] = tile[dat_g & 0x01];
191             led_buffer[(14 + (i * 48))-(j<<1) + 1] = 0;
192             led_buffer[(30 + (i * 48))-(j<<1)] = tile[dat_r & 0x01];
193             led_buffer[(30 + (i * 48))-(j<<1) + 1] = 0;
194             led_buffer[(46 + (i * 48))-(j<<1)] = tile[dat_b & 0x01];
195             led_buffer[(46 + (i * 48))-(j<<1) + 1] = 0;
196             dat_g >>=1;
197             dat_r >>=1;
198             dat_b >>=1;
199         }
200     }
201     TIM_Send_WS2812(led_buffer, sizeof(led_buffer) / 2);
202 
203 }
led_matrix_rst()204 void led_matrix_rst()
205 {
206     for (uint32_t i = 0; i < (LED_NUM * 24); i++)
207     {
208         led_buffer[ (i<<1) ] = 3;
209         led_buffer[ (i<<1) + 1] = 0;
210     }
211     TIM_Send_WS2812(led_buffer, sizeof(led_buffer) / 2 );
212 }
213 
MSH_CMD_EXPORT(led_matrix_rst,Test led matrix on board)214 MSH_CMD_EXPORT(led_matrix_rst, Test led matrix on board)
215 
216 void led_matrix_fill(RGBColor_TypeDef Color)
217 {
218     rt_memset(RGB_Data, 0x00, sizeof(RGB_Data));
219     for (uint8_t i = 0; i < LED_NUM; i++)
220     {
221         Set_LEDColor(i, Color);
222     }
223     RGB_Reflash();
224 }
225 
led_matrix_fill_test(uint8_t index)226 void led_matrix_fill_test(uint8_t index)
227 {
228     switch (index)
229     {
230     case 0:
231         led_matrix_fill(LT_RED);
232         break;
233     case 1:
234         led_matrix_fill(LT_GREEN);
235         break;
236     case 2:
237         led_matrix_fill(LT_BLUE);
238         break;
239     case 3:
240         led_matrix_fill(LT_WHITE);
241         break;
242     default:
243         break;
244     }
245 }
246 
led_matrix_test1()247 void led_matrix_test1()
248 {
249     rt_memset(RGB_Data, 0x00, sizeof(RGB_Data));
250     Set_LEDColor(0, RED);
251     Set_LEDColor(1, GREEN);
252     Set_LEDColor(2, BLUE);
253     Set_LEDColor(3, RED);
254     Set_LEDColor(4, GREEN);
255     Set_LEDColor(5, BLUE);
256     Set_LEDColor(6, RED);
257     Set_LEDColor(7, GREEN);
258     Set_LEDColor(8, BLUE);
259     Set_LEDColor(9, WHITE);
260     // led_matrix_rst();
261     RGB_Reflash();
262 }
MSH_CMD_EXPORT(led_matrix_test1,Test led matrix on board)263 MSH_CMD_EXPORT(led_matrix_test1, Test led matrix on board)
264 
265 void led_matrix_test2()
266 {
267     rt_memset(RGB_Data, 0x00, sizeof(RGB_Data));
268     Set_LEDColor(0, BLUE);
269     Set_LEDColor(1, RED);
270     Set_LEDColor(2, GREEN);
271     Set_LEDColor(3, BLUE);
272     Set_LEDColor(4, RED);
273     Set_LEDColor(5, GREEN);
274     Set_LEDColor(6, BLUE);
275     Set_LEDColor(7, RED);
276     Set_LEDColor(8, GREEN);
277     Set_LEDColor(9, RED);
278 
279     Set_LEDColor(14, GREEN);
280     Set_LEDColor(15, GREEN);
281     Set_LEDColor(16, BLUE);
282     Set_LEDColor(17, RED);
283     Set_LEDColor(18, WHITE);
284 
285     RGB_Reflash();
286 }
MSH_CMD_EXPORT(led_matrix_test2,Test led matrix on board)287 MSH_CMD_EXPORT(led_matrix_test2, Test led matrix on board)
288 
289 void led_matrix_test3()
290 {
291     for (uint8_t i = 0; i < 4; i++)
292     {
293         led_matrix_fill_test(i);
294         rt_thread_mdelay(1000);
295     }
296     led_matrix_rst();
297 }
298 
MSH_CMD_EXPORT(led_matrix_test3,Test led matrix on board)299 MSH_CMD_EXPORT(led_matrix_test3, Test led matrix on board)
300 
301 void led_matrix_show_color(uint8_t r, uint8_t g, uint8_t b)
302 {
303     RGBColor_TypeDef color = {g,r,b};
304     led_matrix_fill(color);
305 }
306