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  * 2021-09-23     charlown           first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <board.h>
14 
15 #ifdef BSP_USING_PWM
16 
17 #define LOG_TAG "drv.pwm"
18 #include <drv_log.h>
19 
20 #ifndef ITEM_NUM
21 #define ITEM_NUM(items) sizeof(items) / sizeof(items[0])
22 #endif
23 
24 #define MAX_COUNTER 65535
25 #define MIN_COUNTER 2
26 #define MIN_PULSE 2
27 
28 struct rtdevice_pwm_device
29 {
30   struct rt_device_pwm parent;
31   TIM_TypeDef *periph;
32   rt_uint8_t channel[4];
33   char *name;
34 };
35 
36 /*
37 * channel = 0xFF: the channel is not use.
38 */
39 struct rtdevice_pwm_device pwm_device_list[] =
40     {
41 #ifdef BSP_USING_TIM1_PWM
42         {
43             .periph = TIM1,
44             .name = "pwm1",
45 #ifdef BSP_USING_TIM1_PWM_CH1
46             .channel[0] = TIM_Channel_1,
47 #else
48             .channel[0] = 0xFF,
49 #endif
50 
51 #ifdef BSP_USING_TIM1_PWM_CH2
52             .channel[1] = TIM_Channel_2,
53 #else
54             .channel[1] = 0xFF,
55 #endif
56 
57 #ifdef BSP_USING_TIM1_PWM_CH3
58             .channel[2] = TIM_Channel_3,
59 #else
60             .channel[2] = 0xFF,
61 #endif
62 
63 #ifdef BSP_USING_TIM1_PWM_CH4
64             .channel[3] = TIM_Channel_4,
65 #else
66             .channel[3] = 0xFF,
67 #endif
68         },
69 #endif
70 
71 #ifdef BSP_USING_TIM2_PWM
72         {
73             .periph = TIM2,
74             .name = "pwm2",
75 #ifdef BSP_USING_TIM2_PWM_CH1
76             .channel[0] = TIM_Channel_1,
77 #else
78             .channel[0] = 0xFF,
79 #endif
80 
81 #ifdef BSP_USING_TIM2_PWM_CH2
82             .channel[1] = TIM_Channel_2,
83 #else
84             .channel[1] = 0xFF,
85 #endif
86 
87 #ifdef BSP_USING_TIM2_PWM_CH3
88             .channel[2] = TIM_Channel_3,
89 #else
90             .channel[2] = 0xFF,
91 #endif
92 
93 #ifdef BSP_USING_TIM2_PWM_CH4
94             .channel[3] = TIM_Channel_4,
95 #else
96             .channel[3] = 0xFF,
97 #endif
98         },
99 #endif
100 
101 #ifdef BSP_USING_TIM3_PWM
102         {
103             .periph = TIM3,
104             .name = "pwm3",
105 #ifdef BSP_USING_TIM3_PWM_CH1
106             .channel[0] = TIM_Channel_1,
107 #else
108             .channel[0] = 0xFF,
109 #endif
110 
111 #ifdef BSP_USING_TIM3_PWM_CH2
112             .channel[1] = TIM_Channel_2,
113 #else
114             .channel[1] = 0xFF,
115 #endif
116 
117 #ifdef BSP_USING_TIM3_PWM_CH3
118             .channel[2] = TIM_Channel_3,
119 #else
120             .channel[2] = 0xFF,
121 #endif
122 
123 #ifdef BSP_USING_TIM3_PWM_CH4
124             .channel[3] = TIM_Channel_4,
125 #else
126             .channel[3] = 0xFF,
127 #endif
128         },
129 #endif
130 
131 #ifdef BSP_USING_TIM4_PWM
132         {
133             .periph = TIM4,
134             .name = "pwm4",
135 #ifdef BSP_USING_TIM4_PWM_CH1
136             .channel[0] = TIM_Channel_1,
137 #else
138             .channel[0] = 0xFF,
139 #endif
140 
141 #ifdef BSP_USING_TIM4_PWM_CH2
142             .channel[1] = TIM_Channel_2,
143 #else
144             .channel[1] = 0xFF,
145 #endif
146 
147 #ifdef BSP_USING_TIM4_PWM_CH3
148             .channel[2] = TIM_Channel_3,
149 #else
150             .channel[2] = 0xFF,
151 #endif
152 
153 #ifdef BSP_USING_TIM4_PWM_CH4
154             .channel[3] = TIM_Channel_4,
155 #else
156             .channel[3] = 0xFF,
157 #endif
158         },
159 #endif
160 };
161 
ch32f1_pwm_device_enable(struct rt_device_pwm * device,struct rt_pwm_configuration * configuration,rt_bool_t enable)162 static rt_err_t ch32f1_pwm_device_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration, rt_bool_t enable)
163 {
164   struct rtdevice_pwm_device *pwm_device;
165   rt_uint32_t channel_index;
166   rt_uint16_t ccx_state;
167 
168   pwm_device = (struct rtdevice_pwm_device *)device;
169   channel_index = configuration->channel;
170 
171   if (enable == RT_TRUE)
172   {
173     ccx_state = TIM_CCx_Enable;
174   }
175   else
176   {
177     ccx_state = TIM_CCx_Disable;
178   }
179 
180   if (channel_index <= 4 && channel_index > 0)
181   {
182     if (pwm_device->channel[channel_index - 1] == 0xFF)
183       return -RT_EINVAL;
184 
185     TIM_CCxCmd(pwm_device->periph, pwm_device->channel[channel_index - 1], ccx_state);
186   }
187   else
188   {
189     return -RT_EINVAL;
190   }
191 
192   TIM_Cmd(pwm_device->periph, ENABLE);
193 
194   return RT_EOK;
195 }
196 
ch32f1_pwm_device_get(struct rt_device_pwm * device,struct rt_pwm_configuration * configuration)197 static rt_err_t ch32f1_pwm_device_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
198 {
199   struct rtdevice_pwm_device *pwm_device;
200   rt_uint32_t arr_counter, ccr_counter, prescaler, sample_freq;
201   rt_uint32_t channel_index;
202   rt_uint32_t tim_clock;
203 
204   pwm_device = (struct rtdevice_pwm_device *)device;
205 
206   tim_clock = ch32f1_tim_clock_get(pwm_device->periph);
207   channel_index = configuration->channel;
208   arr_counter = pwm_device->periph->ATRLR + 1;
209   prescaler = pwm_device->periph->PSC + 1;
210 
211   sample_freq = (tim_clock / prescaler) / arr_counter;
212 
213   /* unit:ns */
214   configuration->period = 1000000000 / sample_freq;
215 
216   if (channel_index == 1)
217   {
218     ccr_counter = pwm_device->periph->CH1CVR + 1;
219     configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
220   }
221   else if (channel_index == 2)
222   {
223     ccr_counter = pwm_device->periph->CH2CVR + 1;
224     configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
225   }
226   else if (channel_index == 3)
227   {
228     ccr_counter = pwm_device->periph->CH3CVR + 1;
229     configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
230   }
231   else if (channel_index == 4)
232   {
233     ccr_counter = pwm_device->periph->CH4CVR + 1;
234     configuration->pulse = ((ccr_counter * 100) / arr_counter) * configuration->period / 100;
235   }
236   else
237     return -RT_EINVAL;
238 
239   return RT_EOK;
240 }
241 
ch32f1_pwm_device_set(struct rt_device_pwm * device,struct rt_pwm_configuration * configuration)242 static rt_err_t ch32f1_pwm_device_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
243 {
244   struct rtdevice_pwm_device *pwm_device;
245   rt_uint32_t arr_counter, ccr_counter, prescaler, sample_freq;
246   rt_uint32_t channel_index;
247   rt_uint32_t tim_clock;
248 
249   TIM_TimeBaseInitTypeDef TIM_TimeBaseInitType;
250   TIM_OCInitTypeDef TIM_OCInitType;
251 
252   pwm_device = (struct rtdevice_pwm_device *)device;
253 
254   tim_clock = ch32f1_tim_clock_get(pwm_device->periph);
255 
256   channel_index = configuration->channel;
257 
258   /* change to freq, unit:Hz */
259   sample_freq = 1000000000 / configuration->period;
260 
261   /*counter = (tim_clk / prescaler) / sample_freq */
262   /*normally, tim_clk is not need div, if arr_counter over 65536, need div.*/
263   prescaler = 1;
264 
265   arr_counter = (tim_clock / prescaler) / sample_freq;
266 
267   if (arr_counter > MAX_COUNTER)
268   {
269     /* need div tim_clock
270     * and round up the prescaler value.
271     * (tim_clock >> 16) = tim_clock / 65536
272     */
273     if ((tim_clock >> 16) % sample_freq == 0)
274       prescaler = (tim_clock >> 16) / sample_freq;
275     else
276       prescaler = (tim_clock >> 16) / sample_freq + 1;
277 
278     /*counter = (tim_clk / prescaler) / sample_freq */
279     arr_counter = (tim_clock / prescaler) / sample_freq;
280   }
281   /* ccr_counter = duty cycle * arr_counter */
282   ccr_counter = (configuration->pulse * 100 / configuration->period) * arr_counter / 100;
283 
284   /* check arr_counter > 1, cxx_counter > 1 */
285   if (arr_counter < MIN_COUNTER)
286   {
287     arr_counter = MIN_COUNTER;
288   }
289 
290   if (ccr_counter < MIN_PULSE)
291   {
292     ccr_counter = MIN_PULSE;
293   }
294 
295   /* TMRe base configuration */
296   TIM_TimeBaseStructInit(&TIM_TimeBaseInitType);
297   TIM_TimeBaseInitType.TIM_Period = arr_counter - 1;
298   TIM_TimeBaseInitType.TIM_Prescaler = prescaler - 1;
299   TIM_TimeBaseInitType.TIM_ClockDivision = TIM_CKD_DIV1;
300   TIM_TimeBaseInitType.TIM_CounterMode = TIM_CounterMode_Up;
301 
302   TIM_TimeBaseInit(pwm_device->periph, &TIM_TimeBaseInitType);
303 
304 
305   TIM_OCStructInit(&TIM_OCInitType);
306   TIM_OCInitType.TIM_OCMode = TIM_OCMode_PWM1;
307   TIM_OCInitType.TIM_OutputState = TIM_OutputState_Enable;
308   TIM_OCInitType.TIM_Pulse = ccr_counter - 1;
309   TIM_OCInitType.TIM_OCPolarity = TIM_OCPolarity_High;
310 
311   if (channel_index == 1)
312   {
313     TIM_OC1Init(pwm_device->periph, &TIM_OCInitType);
314     TIM_OC1PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
315   }
316   else if (channel_index == 2)
317   {
318     TIM_OC2Init(pwm_device->periph, &TIM_OCInitType);
319     TIM_OC2PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
320   }
321   else if (channel_index == 3)
322   {
323     TIM_OC3Init(pwm_device->periph, &TIM_OCInitType);
324     TIM_OC3PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
325   }
326   else if (channel_index == 4)
327   {
328     TIM_OC4Init(pwm_device->periph, &TIM_OCInitType);
329     TIM_OC4PreloadConfig(pwm_device->periph, TIM_OCPreload_Disable);
330   }
331   else
332   {
333     return -RT_EINVAL;
334   }
335 
336   TIM_ARRPreloadConfig(pwm_device->periph, ENABLE);
337   TIM_CtrlPWMOutputs(pwm_device->periph, ENABLE);
338 
339   return RT_EOK;
340 }
341 
drv_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)342 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
343 {
344   struct rt_pwm_configuration *configuration;
345 
346   configuration = (struct rt_pwm_configuration *)arg;
347 
348   switch (cmd)
349   {
350   case PWM_CMD_ENABLE:
351     return ch32f1_pwm_device_enable(device, configuration, RT_TRUE);
352   case PWM_CMD_DISABLE:
353     return ch32f1_pwm_device_enable(device, configuration, RT_FALSE);
354   case PWM_CMD_SET:
355     return ch32f1_pwm_device_set(device, configuration);
356   case PWM_CMD_GET:
357     return ch32f1_pwm_device_get(device, configuration);
358   default:
359     return -RT_EINVAL;
360   }
361 }
362 
363 static struct rt_pwm_ops pwm_ops =
364     {
365         .control = drv_pwm_control};
366 
rt_hw_pwm_init(void)367 static int rt_hw_pwm_init(void)
368 {
369   int result = RT_EOK;
370   int index = 0;
371   int channel_index;
372 
373   for (index = 0; index < ITEM_NUM(pwm_device_list); index++)
374   {
375     ch32f1_tim_clock_init(pwm_device_list[index].periph);
376     for (channel_index = 0; channel_index < sizeof(pwm_device_list[index].channel); channel_index++)
377     {
378       if (pwm_device_list[index].channel[channel_index] != 0xFF)
379       {
380         ch32f1_pwm_io_init(pwm_device_list[index].periph, pwm_device_list[index].channel[channel_index]);
381       }
382     }
383 
384     if (rt_device_pwm_register(&pwm_device_list[index].parent, pwm_device_list[index].name, &pwm_ops, RT_NULL) == RT_EOK)
385     {
386       LOG_D("%s register success", pwm_device_list[index].name);
387     }
388     else
389     {
390       LOG_D("%s register failed", pwm_device_list[index].name);
391       result = -RT_ERROR;
392     }
393   }
394 
395   return result;
396 }
397 
398 INIT_BOARD_EXPORT(rt_hw_pwm_init);
399 
400 #endif /* BSP_USING_PWM */
401