1 /*
2 * Copyright (c) 2006-2025, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-11-21 chenyingchun first version
9 */
10 #include <rtthread.h>
11 #include <rtdevice.h>
12 #include <board.h>
13 #include <nrfx_timer.h>
14
15 #ifdef SOFTDEVICE_PRESENT
16 #ifdef BSP_USING_TIM0
17 #error "TIMER0 cannot be used when SOFTDEVICE has been used."
18 #endif
19 #endif
20
21 #ifdef BSP_USING_TIM
22
23 #define LOG_TAG "drv.hwtimer"
24 #define DBG_LVL DBG_INFO
25 #include <rtdbg.h>
26
27 #ifdef RT_USING_HWTIMER
28
29 #ifndef TIM_DEV_INFO_CONFIG
30 /* maxfreq and minfreq unit is HZ */
31 #define TIM_DEV_INFO_CONFIG \
32 { \
33 .maxfreq = 16000000, \
34 .minfreq = 31250, \
35 .maxcnt = 0xFFFFFFFF, \
36 .cntmode = HWTIMER_CNTMODE_UP, \
37 }
38 #endif
39
40 typedef struct
41 {
42 nrfx_timer_t timer_inst;
43 nrfx_timer_config_t timer_cfg;
44 nrf_timer_cc_channel_t cc_channel;
45 }nrf5x_timer_info_t;
46
47 struct nrf5x_hwtimer
48 {
49 rt_hwtimer_t timer_device;
50 nrf5x_timer_info_t timer_info;
51 char *name;
52 };
53
54 static struct nrf5x_hwtimer nrf5x_hwtimer_obj[] =
55 {
56 #ifdef BSP_USING_TIM0
57 {
58 .timer_info.timer_inst = NRFX_TIMER_INSTANCE(0),
59 .timer_info.timer_cfg = NRFX_TIMER_DEFAULT_CONFIG,
60 .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL0,
61 .name = "timer0",
62 },
63 #endif
64
65 #ifdef BSP_USING_TIM1
66 {
67 .timer_info.timer_inst = NRFX_TIMER_INSTANCE(1),
68 .timer_info.timer_cfg = NRFX_TIMER_DEFAULT_CONFIG,
69 .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL1,
70 .name = "timer1",
71 },
72 #endif
73
74 #ifdef BSP_USING_TIM2
75 {
76 .timer_info.timer_inst = NRFX_TIMER_INSTANCE(2),
77 .timer_info.timer_cfg = NRFX_TIMER_DEFAULT_CONFIG,
78 .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL2,
79 .name = "timer2",
80 },
81 #endif
82
83 #ifdef BSP_USING_TIM3
84 {
85 .timer_info.timer_inst = NRFX_TIMER_INSTANCE(3),
86 .timer_info.timer_cfg = NRFX_TIMER_DEFAULT_CONFIG,
87 .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL3,
88 .name = "timer3",
89 },
90 #endif
91
92 #ifdef BSP_USING_TIM4
93 {
94 .timer_info.timer_inst = NRFX_TIMER_INSTANCE(4),
95 .timer_info.timer_cfg = NRFX_TIMER_DEFAULT_CONFIG,
96 .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL4,
97 .name = "timer4",
98 }
99 #endif
100 };
101
timer_callback(nrf_timer_event_t event_type,void * p_context)102 static void timer_callback(nrf_timer_event_t event_type, void* p_context)
103 {
104 rt_hwtimer_t *timer_device = (struct rt_hwtimer_device *)p_context;
105
106 /* no matter what event_type is(NRF_TIMER_EVENT_COMPARE0 or others), call same function "rt_device_hwtimer_isr" */
107 LOG_D("timer_callback event_type = %d, inst_id = %d, cc conunt = %d\r\n",
108 event_type, timer_info->timer_inst.instance_id, timer_info->timer_inst.cc_channel_count);
109 rt_device_hwtimer_isr(timer_device);
110 }
111
timer_init(struct rt_hwtimer_device * timer,rt_uint32_t state)112 static void timer_init(struct rt_hwtimer_device *timer, rt_uint32_t state)
113 {
114 nrf5x_timer_info_t *timer_info = RT_NULL;
115 nrfx_timer_config_t *timer_cfg = RT_NULL;
116
117 RT_ASSERT(timer != RT_NULL);
118 if (state)
119 {
120 timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
121 timer_cfg = &(timer_info->timer_cfg);
122 timer_cfg->bit_width = NRF_TIMER_BIT_WIDTH_32;
123 timer_cfg->p_context = timer;
124
125 nrfx_timer_init(&(timer_info->timer_inst), timer_cfg, timer_callback);
126 }
127 }
128
timer_start(rt_hwtimer_t * timer,rt_uint32_t t,rt_hwtimer_mode_t opmode)129 static rt_err_t timer_start(rt_hwtimer_t *timer, rt_uint32_t t, rt_hwtimer_mode_t opmode)
130 {
131 nrf5x_timer_info_t *timer_info = RT_NULL;
132 nrf_timer_short_mask_t mask = NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK;
133
134 RT_ASSERT(timer != RT_NULL);
135
136 timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
137
138 if (opmode == HWTIMER_MODE_ONESHOT)
139 {
140 /* means TIMER_SHORTS_COMPARE0_STOP_Msk or TIMER_SHORTS_COMPARE1_STOP_Msk ..., according to cc_channel. */
141 mask = (nrf_timer_short_mask_t)(1 << (timer_info->cc_channel + 8));
142 }
143 else
144 {
145 /* means TIMER_SHORTS_COMPARE0_CLEAR_Msk or TIMER_SHORTS_COMPARE1_CLEAR_Msk ..., according to cc_channel. */
146 mask = (nrf_timer_short_mask_t)(1 << timer_info->cc_channel);
147 }
148
149 nrfx_timer_extended_compare(&(timer_info->timer_inst), timer_info->cc_channel, t, mask, true);
150 nrfx_timer_enable(&(timer_info->timer_inst));
151 return RT_EOK;
152 }
153
timer_stop(rt_hwtimer_t * timer)154 static void timer_stop(rt_hwtimer_t *timer)
155 {
156 nrf5x_timer_info_t *timer_info = RT_NULL;
157
158 RT_ASSERT(timer != RT_NULL);
159
160 timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
161
162 nrfx_timer_disable(&(timer_info->timer_inst));
163
164 /* set time count register to zero*/
165 nrfx_timer_clear(&(timer_info->timer_inst));
166 }
167
frequency_convert(rt_uint32_t freq)168 static nrf_timer_frequency_t frequency_convert(rt_uint32_t freq)
169 {
170 nrf_timer_frequency_t frequency = NRF_TIMER_FREQ_1MHz;
171 switch (freq)
172 {
173 case 16000000:
174 {
175 frequency = NRF_TIMER_FREQ_16MHz;
176 break;
177 }
178
179 case 8000000:
180 {
181 frequency = NRF_TIMER_FREQ_8MHz;
182 break;
183 }
184
185 case 2000000:
186 {
187 frequency = NRF_TIMER_FREQ_2MHz;
188 break;
189 }
190
191 case 1000000:
192 {
193 frequency = NRF_TIMER_FREQ_1MHz;
194 break;
195 }
196
197 case 500000:
198 {
199 frequency = NRF_TIMER_FREQ_500kHz;
200 break;
201 }
202
203 case 250000:
204 {
205 frequency = NRF_TIMER_FREQ_250kHz;
206 break;
207 }
208
209 case 125000:
210 {
211 frequency = NRF_TIMER_FREQ_125kHz;
212 break;
213 }
214
215 case 62500:
216 {
217 frequency = NRF_TIMER_FREQ_62500Hz;
218 break;
219 }
220
221 case 31250:
222 {
223 frequency = NRF_TIMER_FREQ_31250Hz;
224 break;
225 }
226
227 default:
228 {
229 break;
230 }
231 }
232
233 return frequency;
234 }
235
timer_ctrl(rt_hwtimer_t * timer,rt_uint32_t cmd,void * arg)236 static rt_err_t timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg)
237 {
238 rt_err_t result = RT_EOK;
239 nrf5x_timer_info_t *timer_info = RT_NULL;
240 nrfx_timer_t *timer_inst = RT_NULL;
241
242 RT_ASSERT(timer != RT_NULL);
243 RT_ASSERT(arg != RT_NULL);
244
245 timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
246 timer_inst = &(timer_info->timer_inst);
247
248 switch (cmd)
249 {
250 case HWTIMER_CTRL_FREQ_SET:
251 {
252 rt_uint32_t freq;
253 /* set timer frequence */
254 freq = *((rt_uint32_t *)arg);
255
256 nrf_timer_frequency_set(timer_inst->p_reg, frequency_convert(freq));
257 break;
258 }
259 default:
260 {
261 result = -RT_ENOSYS;
262 break;
263 }
264
265 }
266
267 return result;
268 }
269
timer_counter_get(rt_hwtimer_t * timer)270 static rt_uint32_t timer_counter_get(rt_hwtimer_t *timer)
271 {
272 rt_uint32_t count = 0;
273 nrf5x_timer_info_t *timer_info = RT_NULL;
274
275 RT_ASSERT(timer != RT_NULL);
276
277 timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
278
279 /* capture method will copy the current counter register to the specified cc channel (here is NRF_TIMER_CC_CHANNEL5). */
280 /* the specified cc channel cannot be same with the already used cc channels */
281 count = nrfx_timer_capture(&(timer_info->timer_inst), NRF_TIMER_CC_CHANNEL5);
282 return count;
283 }
284
285 static const struct rt_hwtimer_info _info = TIM_DEV_INFO_CONFIG;
286 static const struct rt_hwtimer_ops _ops =
287 {
288 .init = timer_init,
289 .start = timer_start,
290 .stop = timer_stop,
291 .count_get = timer_counter_get,
292 .control = timer_ctrl,
293 };
294
nrf5x_hwtimer_init(void)295 static int nrf5x_hwtimer_init(void)
296 {
297 int i = 0;
298 int result = RT_EOK;
299
300 for (i = 0; i < sizeof(nrf5x_hwtimer_obj) / sizeof(nrf5x_hwtimer_obj[0]); i++)
301 {
302 nrf5x_hwtimer_obj[i].timer_device.info = &_info;
303 nrf5x_hwtimer_obj[i].timer_device.ops = &_ops;
304 if (rt_device_hwtimer_register(&nrf5x_hwtimer_obj[i].timer_device, nrf5x_hwtimer_obj[i].name, &nrf5x_hwtimer_obj[i].timer_info) == RT_EOK)
305 {
306 LOG_D("%s register success", nrf5x_hwtimer_obj[i].name);
307 }
308 else
309 {
310 LOG_E("%s register failed", nrf5x_hwtimer_obj[i].name);
311 result = -RT_ERROR;
312 }
313 }
314
315 return result;
316 }
317 INIT_BOARD_EXPORT(nrf5x_hwtimer_init);
318
319 #endif /* RT_USING_HWTIMER */
320 #endif /* BSP_USING_TIM */
321
322