1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author           Notes
8  * 2015-09-02     heyuanjie87      the first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "lpc_timer.h"
14 #include "lpc_clkpwr.h"
15 #include "drv_hwtimer.h"
16 
17 #ifdef RT_USING_HWTIMER
18 
NVIC_Configuration(void)19 static void NVIC_Configuration(void)
20 {
21     NVIC_EnableIRQ(TIMER0_IRQn);
22 }
23 
timer_init(rt_hwtimer_t * timer,rt_uint32_t state)24 static void timer_init(rt_hwtimer_t *timer, rt_uint32_t state)
25 {
26     LPC_TIM_TypeDef *tim;
27     TIM_TIMERCFG_Type cfg;
28 
29     tim = (LPC_TIM_TypeDef *)timer->parent.user_data;
30 
31     TIM_DeInit(tim);
32 
33     if (state == 1)
34     {
35         NVIC_Configuration();
36 
37         cfg.PrescaleOption = TIM_PRESCALE_TICKVAL;
38         cfg.PrescaleValue = 0xFFFF;
39         TIM_Init(tim, TIM_TIMER_MODE, &cfg);
40     }
41 }
42 
timer_start(rt_hwtimer_t * timer,rt_uint32_t t,rt_hwtimer_mode_t opmode)43 static rt_err_t timer_start(rt_hwtimer_t *timer, rt_uint32_t t, rt_hwtimer_mode_t opmode)
44 {
45     LPC_TIM_TypeDef *tim;
46     TIM_MATCHCFG_Type match;
47 
48     tim = (LPC_TIM_TypeDef *)timer->parent.user_data;
49 
50     match.MatchChannel = 0;
51     match.IntOnMatch = ENABLE;
52     match.ResetOnMatch = ENABLE;
53     match.StopOnMatch = (opmode == HWTIMER_MODE_ONESHOT) ? ENABLE : DISABLE;
54     match.ExtMatchOutputType = 0;
55     match.MatchValue = t;
56 
57     TIM_ConfigMatch(tim, &match);
58     TIM_Cmd(tim, ENABLE);
59 
60     return RT_EOK;
61 }
62 
timer_stop(rt_hwtimer_t * timer)63 static void timer_stop(rt_hwtimer_t *timer)
64 {
65     LPC_TIM_TypeDef *tim;
66 
67     tim = (LPC_TIM_TypeDef *)timer->parent.user_data;
68 
69     TIM_Cmd(tim, DISABLE);
70 }
71 
timer_ctrl(rt_hwtimer_t * timer,rt_uint32_t cmd,void * arg)72 static rt_err_t timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg)
73 {
74     LPC_TIM_TypeDef *tim;
75     rt_err_t err = RT_EOK;
76 
77     tim = (LPC_TIM_TypeDef *)timer->parent.user_data;
78 
79     switch (cmd)
80     {
81     case HWTIMER_CTRL_FREQ_SET:
82     {
83         uint32_t clk;
84         uint32_t pre;
85 
86         clk = CLKPWR_GetCLK(CLKPWR_CLKTYPE_PER);
87         pre = clk / *((uint32_t *)arg) - 1;
88         tim->PR = pre;
89     }
90     break;
91     default:
92     {
93         err = -RT_ENOSYS;
94     }
95     break;
96     }
97 
98     return err;
99 }
100 
timer_counter_get(rt_hwtimer_t * timer)101 static rt_uint32_t timer_counter_get(rt_hwtimer_t *timer)
102 {
103     LPC_TIM_TypeDef *tim;
104 
105     tim = (LPC_TIM_TypeDef *)timer->parent.user_data;
106 
107     return tim->TC;
108 }
109 
110 static const struct rt_hwtimer_info _info =
111 {
112     1000000,           /* the maximum count frequency can be set */
113     2000,              /* the minimum count frequency can be set */
114     0xFFFFFF,          /* the maximum counter value */
115     HWTIMER_CNTMODE_UP,/* Increment or Decreasing count mode */
116 };
117 
118 static const struct rt_hwtimer_ops _ops =
119 {
120     timer_init,
121     timer_start,
122     timer_stop,
123     timer_counter_get,
124     timer_ctrl,
125 };
126 
127 static rt_hwtimer_t _timer0;
128 
rt_hw_hwtimer_init(void)129 int rt_hw_hwtimer_init(void)
130 {
131     _timer0.info = &_info;
132     _timer0.ops  = &_ops;
133 
134     rt_device_hwtimer_register(&_timer0, "timer0", LPC_TIM0);
135 
136     return 0;
137 }
138 
TIMER0_IRQHandler(void)139 void TIMER0_IRQHandler(void)
140 {
141     if (TIM_GetIntStatus(LPC_TIM0, TIM_MR0_INT) != RESET)
142     {
143         TIM_ClearIntPending(LPC_TIM0, TIM_MR0_INT);
144         rt_device_hwtimer_isr(&_timer0);
145     }
146 }
147 
148 INIT_BOARD_EXPORT(rt_hw_hwtimer_init);
149 
150 #endif  /* RT_USING_HWTIMER */
151