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