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