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 * 2022-09-10 MXH the first version
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13
14 #ifdef BSP_USING_HWTIMER
15 #define DBG_TAG "TIM"
16 #define DBG_LVL DBG_LOG
17 #include <rtdbg.h>
18
19 #include "drv_hwtimer.h"
20 #include "board.h"
21
22 #ifdef RT_USING_HWTIMER
23
24 enum
25 {
26 #ifdef BSP_USING_TIM1
27 TIM1_INDEX,
28 #endif
29 #ifdef BSP_USING_TIM2
30 TIM2_INDEX,
31 #endif
32 #ifdef BSP_USING_TIM3
33 TIM3_INDEX,
34 #endif
35 #ifdef BSP_USING_TIM4
36 TIM4_INDEX,
37 #endif
38 #ifdef BSP_USING_TIM5
39 TIM5_INDEX,
40 #endif
41 #ifdef BSP_USING_TIM6
42 TIM6_INDEX,
43 #endif
44 #ifdef BSP_USING_TIM7
45 TIM7_INDEX,
46 #endif
47 #ifdef BSP_USING_TIM8
48 TIM8_INDEX,
49 #endif
50 #ifdef BSP_USING_TIM9
51 TIM9_INDEX,
52 #endif
53 #ifdef BSP_USING_TIM10
54 TIM10_INDEX,
55 #endif
56 };
57
58 static struct ch32_hwtimer ch32_hwtimer_obj[] =
59 {
60 #ifdef BSP_USING_TIM1
61 TIM1_CONFIG,
62 #endif
63
64 #ifdef BSP_USING_TIM2
65 TIM2_CONFIG,
66 #endif
67
68 #ifdef BSP_USING_TIM3
69 TIM3_CONFIG,
70 #endif
71
72 #ifdef BSP_USING_TIM4
73 TIM4_CONFIG,
74 #endif
75
76 #ifdef BSP_USING_TIM5
77 TIM5_CONFIG,
78 #endif
79
80 #ifdef BSP_USING_TIM6
81 TIM6_CONFIG,
82 #endif
83
84 #ifdef BSP_USING_TIM7
85 TIM7_CONFIG,
86 #endif
87
88 #ifdef BSP_USING_TIM8
89 TIM8_CONFIG,
90 #endif
91
92 #ifdef BSP_USING_TIM9
93 TIM9_CONFIG,
94 #endif
95
96 #ifdef BSP_USING_TIM10
97 TIM10_CONFIG,
98 #endif
99 };
100
101 /* APBx timer clocks frequency doubler state related to APB1CLKDivider value */
ch32_get_pclk_doubler(rt_uint32_t * pclk1_doubler,rt_uint32_t * pclk2_doubler)102 void ch32_get_pclk_doubler(rt_uint32_t *pclk1_doubler, rt_uint32_t *pclk2_doubler)
103 {
104 RT_ASSERT(pclk1_doubler != RT_NULL);
105 RT_ASSERT(pclk2_doubler != RT_NULL);
106
107 *pclk1_doubler = 1;
108 *pclk2_doubler = 1;
109
110 if((RCC->CFGR0 & RCC_PPRE1) == RCC_PPRE1_DIV1)
111 {
112 *pclk1_doubler = 1;
113 }
114 else
115 {
116 *pclk1_doubler = 2;
117 }
118
119 if((RCC->CFGR0 & RCC_PPRE2) == RCC_PPRE2_DIV1)
120 {
121 *pclk2_doubler = 1;
122 }
123 else
124 {
125 *pclk2_doubler = 2;
126 }
127 }
128
ch32_hwtimer_init(struct rt_hwtimer_device * timer,rt_uint32_t state)129 static void ch32_hwtimer_init(struct rt_hwtimer_device *timer, rt_uint32_t state)
130 {
131 RT_ASSERT(timer != RT_NULL);
132 TIM_HandleTypeDef *tim = RT_NULL;
133 RCC_ClocksTypeDef RCC_ClockStruct;
134 NVIC_InitTypeDef NVIC_InitStruct;
135 struct ch32_hwtimer *tim_device = RT_NULL;
136 rt_uint32_t prescaler_value = 0;
137 rt_uint32_t pclk1_doubler, pclk2_doubler;
138
139 RCC_GetClocksFreq(&RCC_ClockStruct);
140 ch32_get_pclk_doubler(&pclk1_doubler, &pclk2_doubler);
141
142 if(state)
143 {
144 tim = (TIM_HandleTypeDef *)timer->parent.user_data;
145 tim_device = (struct ch32_hwtimer *)timer;
146
147 #if defined (SOC_RISCV_SERIES_CH32V2)
148 if(tim->instance == TIM1)
149 #elif defined(SOC_RISCV_SERIES_CH32V3)
150 if(tim->instance == TIM1 || tim->instance == TIM8 ||
151 tim->instance == TIM9 || tim->instance == TIM10)
152 #else
153 #error " unsupported CH32 series! "
154 if(RT_NULL)
155 #endif
156 {
157 RCC_APB2PeriphClockCmd(tim->rcc, ENABLE);
158 prescaler_value = (RCC_ClockStruct.PCLK2_Frequency * pclk2_doubler / 10000) - 1;
159 }
160 else
161 {
162 RCC_APB1PeriphClockCmd(tim->rcc, ENABLE);
163 prescaler_value = (RCC_ClockStruct.PCLK1_Frequency * pclk1_doubler / 10000) - 1;
164 }
165 tim->init.TIM_Prescaler = prescaler_value;
166 tim->init.TIM_ClockDivision = TIM_CKD_DIV1;
167 tim->init.TIM_Period = 10000 - 1;
168 tim->init.TIM_RepetitionCounter = 0;
169
170 if(timer->info->cntmode == HWTIMER_CNTMODE_UP)
171 {
172 tim->init.TIM_CounterMode = TIM_CounterMode_Up;
173 }
174 else
175 {
176 tim->init.TIM_CounterMode = TIM_CounterMode_Down;
177 }
178 #if defined (SOC_RISCV_SERIES_CH32V3)
179 /* TIM6 and TIM7 only support counter up mode */
180 if(tim->instance == TIM6 || tim->instance == TIM7)
181 {
182 tim->init.TIM_CounterMode = TIM_CounterMode_Up;
183 }
184 #endif
185 TIM_TimeBaseInit(tim->instance, &tim->init);
186
187 NVIC_InitStruct.NVIC_IRQChannel = tim_device->irqn;
188 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
189 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
190 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
191 NVIC_Init(&NVIC_InitStruct);
192
193 TIM_ClearITPendingBit(tim->instance, TIM_IT_Update);
194 TIM_ITConfig(tim->instance, TIM_IT_Update, ENABLE);
195 }
196 }
197
ch32_hwtimer_start(struct rt_hwtimer_device * timer,rt_uint32_t cnt,rt_hwtimer_mode_t mode)198 static rt_err_t ch32_hwtimer_start(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
199 {
200 RT_ASSERT(timer != RT_NULL);
201 TIM_HandleTypeDef *tim = RT_NULL;
202 tim = (TIM_HandleTypeDef *)timer->parent.user_data;
203
204 /* set tim cnt */
205 tim->instance->CNT = 0;
206 /* set tim arr */
207 tim->instance->ATRLR = cnt - 1;
208 tim->init.TIM_Period = cnt - 1;
209
210 if (mode == HWTIMER_MODE_ONESHOT)
211 {
212 /* set timer to single mode */
213 tim->instance->CTLR1 &= (rt_uint16_t) ~((rt_uint16_t)TIM_OPM);
214 tim->instance->CTLR1 |= TIM_OPMode_Single;
215 }
216 else
217 {
218 tim->instance->CTLR1 &= (rt_uint16_t) ~((rt_uint16_t)TIM_OPM);
219 tim->instance->CTLR1 |= TIM_OPMode_Repetitive;
220 }
221
222 /* start timer */
223 TIM_Cmd(tim->instance, ENABLE);
224
225 return RT_EOK;
226 }
227
ch32_hwtimer_stop(struct rt_hwtimer_device * timer)228 static void ch32_hwtimer_stop(struct rt_hwtimer_device *timer)
229 {
230 RT_ASSERT(timer != RT_NULL);
231 TIM_HandleTypeDef *tim = RT_NULL;
232
233 tim = (TIM_HandleTypeDef *)timer->parent.user_data;
234
235 /* stop timer */
236 TIM_Cmd(tim->instance, DISABLE);
237
238 /* set tim cnt */
239 tim->instance->CNT = 0;
240 }
241
ch32_hwtimer_count_get(struct rt_hwtimer_device * timer)242 static rt_uint32_t ch32_hwtimer_count_get(struct rt_hwtimer_device *timer)
243 {
244 RT_ASSERT(timer != RT_NULL);
245 TIM_HandleTypeDef *tim = RT_NULL;
246 tim = (TIM_HandleTypeDef *)timer->parent.user_data;
247
248 return tim->instance->CNT;
249 }
250
ch32_hwtimer_control(struct rt_hwtimer_device * timer,rt_uint32_t cmd,void * args)251 static rt_err_t ch32_hwtimer_control(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args)
252 {
253 RT_ASSERT(timer != RT_NULL);
254 RT_ASSERT(args != RT_NULL);
255
256 TIM_HandleTypeDef *tim = RT_NULL;
257 rt_err_t result = RT_EOK;
258 rt_uint32_t pclk1_doubler, pclk2_doubler;
259
260 tim = (TIM_HandleTypeDef *)timer->parent.user_data;
261
262 switch (cmd)
263 {
264 case HWTIMER_CTRL_FREQ_SET:
265 {
266 rt_uint32_t freq;
267 rt_uint16_t val;
268 RCC_ClocksTypeDef RCC_ClockStruct;
269
270 /* set timer frequence */
271 freq = *((rt_uint32_t *)args);
272
273 ch32_get_pclk_doubler(&pclk1_doubler, &pclk2_doubler);
274 RCC_GetClocksFreq(&RCC_ClockStruct);
275
276 #if defined (SOC_RISCV_SERIES_CH32V2)
277 if(tim->instance == TIM1)
278 #elif defined(SOC_RISCV_SERIES_CH32V3)
279 if(tim->instance == TIM1 || tim->instance == TIM8 ||
280 tim->instance == TIM9 || tim->instance == TIM10)
281 #else
282 #error " unsupported CH32 series! "
283 if(RT_NULL)
284 #endif
285 {
286 val = RCC_ClockStruct.PCLK2_Frequency * pclk2_doubler / freq;
287 }
288 else
289 {
290 val = RCC_ClockStruct.PCLK1_Frequency * pclk1_doubler / freq;
291 }
292
293 /* Update frequency value */
294 TIM_PrescalerConfig(tim->instance, val - 1, TIM_PSCReloadMode_Immediate);
295
296 result = RT_EOK;
297 break;
298 }
299
300 case HWTIMER_CTRL_MODE_SET:
301 {
302 if (*(rt_hwtimer_mode_t *)args == HWTIMER_MODE_ONESHOT)
303 {
304 /* set timer to single mode */
305 tim->instance->CTLR1 &= (rt_uint16_t) ~((rt_uint16_t)TIM_OPM);
306 tim->instance->CTLR1 |= TIM_OPMode_Single;
307 }
308 else
309 {
310 tim->instance->CTLR1 &= (rt_uint16_t) ~((rt_uint16_t)TIM_OPM);
311 tim->instance->CTLR1 |= TIM_OPMode_Repetitive;
312 }
313 break;
314 }
315
316 case HWTIMER_CTRL_INFO_GET:
317 {
318 *(rt_hwtimer_mode_t *)args = tim->instance->CNT;
319 break;
320 }
321
322 case HWTIMER_CTRL_STOP:
323 {
324 ch32_hwtimer_stop(timer);
325 break;
326 }
327
328 default:
329 {
330 result = -RT_EINVAL;
331 break;
332 }
333 }
334
335 return result;
336 }
337
338 static const struct rt_hwtimer_info ch32_hwtimer_info = TIM_DEV_INFO_CONFIG;
339 static const struct rt_hwtimer_ops ch32_hwtimer_ops =
340 {
341 ch32_hwtimer_init,
342 ch32_hwtimer_start,
343 ch32_hwtimer_stop,
344 ch32_hwtimer_count_get,
345 ch32_hwtimer_control
346 };
347
ch32_hwtimer_isr(struct rt_hwtimer_device * device)348 static void ch32_hwtimer_isr(struct rt_hwtimer_device *device)
349 {
350 RT_ASSERT(device != RT_NULL);
351 struct ch32_hwtimer *hwtimer = RT_NULL;
352 hwtimer = rt_container_of(device, struct ch32_hwtimer, device);
353
354 if(TIM_GetITStatus(hwtimer->handle.instance, TIM_IT_Update) != RESET)
355 {
356 rt_device_hwtimer_isr(device);
357 TIM_ClearITPendingBit(hwtimer->handle.instance, TIM_IT_Update);
358 }
359 }
360
361 #ifdef BSP_USING_TIM1
362 void TIM1_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM1_UP_IRQHandler(void)363 void TIM1_UP_IRQHandler(void)
364 {
365 GET_INT_SP();
366 rt_interrupt_enter();
367 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM1_INDEX].device));
368 rt_interrupt_leave();
369 FREE_INT_SP();
370 }
371 #endif /* BSP_USING_TIM1 */
372
373 #ifdef BSP_USING_TIM2
374 void TIM2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM2_IRQHandler(void)375 void TIM2_IRQHandler(void)
376 {
377 GET_INT_SP();
378 rt_interrupt_enter();
379 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM2_INDEX].device));
380 rt_interrupt_leave();
381 FREE_INT_SP();
382 }
383 #endif /* BSP_USING_TIM2 */
384
385 #ifdef BSP_USING_TIM3
386 void TIM3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM3_IRQHandler(void)387 void TIM3_IRQHandler(void)
388 {
389 GET_INT_SP();
390 rt_interrupt_enter();
391 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM3_INDEX].device));
392 rt_interrupt_leave();
393 FREE_INT_SP();
394 }
395 #endif /* BSP_USING_TIM3 */
396
397 #ifdef BSP_USING_TIM4
398 void TIM4_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM4_IRQHandler(void)399 void TIM4_IRQHandler(void)
400 {
401 GET_INT_SP();
402 rt_interrupt_enter();
403 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM4_INDEX].device));
404 rt_interrupt_leave();
405 FREE_INT_SP();
406 }
407 #endif /* BSP_USING_TIM4 */
408
409 #ifdef BSP_USING_TIM5
410 void TIM5_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM5_IRQHandler(void)411 void TIM5_IRQHandler(void)
412 {
413 GET_INT_SP();
414 rt_interrupt_enter();
415 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM5_INDEX].device));
416 rt_interrupt_leave();
417 FREE_INT_SP();
418 }
419 #endif /* BSP_USING_TIM5 */
420
421 #ifdef BSP_USING_TIM6
422 void TIM6_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM6_IRQHandler(void)423 void TIM6_IRQHandler(void)
424 {
425 GET_INT_SP();
426 rt_interrupt_enter();
427 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM6_INDEX].device));
428 rt_interrupt_leave();
429 FREE_INT_SP();
430 }
431 #endif /* BSP_USING_TIM6 */
432
433 #ifdef BSP_USING_TIM7
434 void TIM7_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM7_IRQHandler(void)435 void TIM7_IRQHandler(void)
436 {
437 GET_INT_SP();
438 rt_interrupt_enter();
439 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM7_INDEX].device));
440 rt_interrupt_leave();
441 FREE_INT_SP();
442 }
443 #endif /* BSP_USING_TIM7 */
444
445 #ifdef BSP_USING_TIM8
446 void TIM8_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM8_UP_IRQHandler(void)447 void TIM8_UP_IRQHandler(void)
448 {
449 GET_INT_SP();
450 rt_interrupt_enter();
451 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM8_INDEX].device));
452 rt_interrupt_leave();
453 FREE_INT_SP();
454 }
455 #endif /* BSP_USING_TIM8 */
456
457 #ifdef BSP_USING_TIM9
458 void TIM9_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM9_UP_IRQHandler(void)459 void TIM9_UP_IRQHandler(void)
460 {
461 GET_INT_SP();
462 rt_interrupt_enter();
463 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM9_INDEX].device));
464 rt_interrupt_leave();
465 FREE_INT_SP();
466 }
467 #endif /* BSP_USING_TIM9 */
468
469 #ifdef BSP_USING_TIM10
470 void TIM10_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
TIM10_UP_IRQHandler(void)471 void TIM10_UP_IRQHandler(void)
472 {
473 GET_INT_SP();
474 rt_interrupt_enter();
475 ch32_hwtimer_isr(&(ch32_hwtimer_obj[TIM10_INDEX].device));
476 rt_interrupt_leave();
477 FREE_INT_SP();
478 }
479 #endif /* BSP_USING_TIM10 */
480
rt_hw_timer_init(void)481 static int rt_hw_timer_init(void)
482 {
483 int i = 0;
484 int result = RT_EOK;
485
486 for (i = 0; i < sizeof(ch32_hwtimer_obj) / sizeof(ch32_hwtimer_obj[0]); i++)
487 {
488 ch32_hwtimer_obj[i].device.info = &ch32_hwtimer_info;
489 ch32_hwtimer_obj[i].device.ops = &ch32_hwtimer_ops;
490 result = rt_device_hwtimer_register(&ch32_hwtimer_obj[i].device,
491 ch32_hwtimer_obj[i].name, (void *)&ch32_hwtimer_obj[i].handle);
492 RT_ASSERT(result == RT_EOK);
493 }
494
495 return result;
496 }
497 INIT_BOARD_EXPORT(rt_hw_timer_init);
498
499 #endif /* RT_USING_HWTIMER */
500 #endif /* BSP_USING_HWTIMER */
501