1 /*
2 * Copyright (c) 2015 - 2025, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <nrfx.h>
35
36 #if NRFX_CHECK(NRFX_TIMER_ENABLED)
37
38 #if !NRFX_FEATURE_PRESENT(NRFX_TIMER, _ENABLED)
39 #error "No enabled TIMER instances. Check <nrfx_config.h>."
40 #endif
41
42 #if NRFX_CHECK(NRFX_TIMER0_ENABLED) && ((1 << 0) & NRFX_TIMERS_USED)
43 #error "TIMER instance 0 is reserved for use outside of nrfx."
44 #endif
45 #if NRFX_CHECK(NRFX_TIMER1_ENABLED) && ((1 << 1) & NRFX_TIMERS_USED)
46 #error "TIMER instance 1 is reserved for use outside of nrfx."
47 #endif
48 #if NRFX_CHECK(NRFX_TIMER2_ENABLED) && ((1 << 2) & NRFX_TIMERS_USED)
49 #error "TIMER instance 2 is reserved for use outside of nrfx."
50 #endif
51 #if NRFX_CHECK(NRFX_TIMER3_ENABLED) && ((1 << 3) & NRFX_TIMERS_USED)
52 #error "TIMER instance 3 is reserved for use outside of nrfx."
53 #endif
54 #if NRFX_CHECK(NRFX_TIMER4_ENABLED) && ((1 << 4) & NRFX_TIMERS_USED)
55 #error "TIMER instance 4 is reserved for use outside of nrfx."
56 #endif
57
58 #include <nrfx_timer.h>
59
60 #define PRESCALER_INVALID UINT32_MAX
61
62 #define TIMER_FREQUENCY_VALID_CHECK(p_instance, frequency) \
63 ((NRFX_TIMER_BASE_FREQUENCY_GET(p_instance) % (frequency) == 0) && \
64 NRFX_IS_POWER_OF_TWO(NRFX_TIMER_BASE_FREQUENCY_GET(p_instance) / (frequency)) && \
65 ((NRFX_TIMER_BASE_FREQUENCY_GET(p_instance) / (frequency)) <= \
66 (1 << NRF_TIMER_PRESCALER_MAX)))
67
68 #define NRFX_LOG_MODULE TIMER
69 #include <nrfx_log.h>
70
71 /** @brief Timer control block. */
72 typedef struct
73 {
74 nrfx_timer_event_handler_t handler;
75 void * context;
76 nrfx_drv_state_t state;
77 } timer_control_block_t;
78
79 static timer_control_block_t m_cb[NRFX_TIMER_ENABLED_COUNT];
80
prescaler_calculate(nrfx_timer_t const * p_instance,uint32_t frequency)81 static uint32_t prescaler_calculate(nrfx_timer_t const * p_instance, uint32_t frequency)
82 {
83 (void)p_instance;
84 uint32_t base_frequency = NRFX_TIMER_BASE_FREQUENCY_GET(p_instance);
85
86 if (!TIMER_FREQUENCY_VALID_CHECK(p_instance, frequency))
87 {
88 return PRESCALER_INVALID;
89 }
90 return NRF_CTZ(base_frequency / frequency);
91 }
92
timer_configure(nrfx_timer_t const * p_instance,nrfx_timer_config_t const * p_config)93 static nrfx_err_t timer_configure(nrfx_timer_t const * p_instance,
94 nrfx_timer_config_t const * p_config)
95 {
96 uint32_t prescaler;
97
98 prescaler = prescaler_calculate(p_instance, p_config->frequency);
99 if (prescaler == PRESCALER_INVALID)
100 {
101 NRFX_LOG_WARNING("Specified frequency is not supported by the TIMER instance.");
102 return NRFX_ERROR_INVALID_PARAM;
103 }
104
105 nrfy_timer_config_t nrfy_config =
106 {
107 .prescaler = prescaler,
108 .mode = p_config->mode,
109 .bit_width = p_config->bit_width
110 };
111
112 nrfy_timer_periph_configure(p_instance->p_reg, &nrfy_config);
113 nrfy_timer_int_init(p_instance->p_reg,
114 NRF_TIMER_ALL_CHANNELS_INT_MASK,
115 p_config->interrupt_priority,
116 false);
117 return NRFX_SUCCESS;
118 }
119
nrfx_timer_init(nrfx_timer_t const * p_instance,nrfx_timer_config_t const * p_config,nrfx_timer_event_handler_t timer_event_handler)120 nrfx_err_t nrfx_timer_init(nrfx_timer_t const * p_instance,
121 nrfx_timer_config_t const * p_config,
122 nrfx_timer_event_handler_t timer_event_handler)
123 {
124 NRFX_ASSERT(p_config);
125
126 timer_control_block_t * p_cb = &m_cb[p_instance->instance_id];
127
128 nrfx_err_t err_code;
129
130 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
131 {
132 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
133 err_code = NRFX_ERROR_ALREADY;
134 #else
135 err_code = NRFX_ERROR_INVALID_STATE;
136 #endif
137 NRFX_LOG_WARNING("Function: %s, error code: %s.",
138 __func__,
139 NRFX_LOG_ERROR_STRING_GET(err_code));
140 return err_code;
141 }
142
143 p_cb->handler = timer_event_handler;
144
145 if (p_config)
146 {
147 p_cb->context = p_config->p_context;
148 NRFX_ASSERT(NRF_TIMER_IS_BIT_WIDTH_VALID(p_instance->p_reg, p_config->bit_width));
149
150 err_code = timer_configure(p_instance, p_config);
151 }
152 else
153 {
154 err_code = NRFX_SUCCESS;
155 }
156
157 p_cb->state = err_code == NRFX_SUCCESS ?
158 NRFX_DRV_STATE_INITIALIZED : NRFX_DRV_STATE_UNINITIALIZED;
159
160 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
161 return err_code;
162 }
163
nrfx_timer_reconfigure(nrfx_timer_t const * p_instance,nrfx_timer_config_t const * p_config)164 nrfx_err_t nrfx_timer_reconfigure(nrfx_timer_t const * p_instance,
165 nrfx_timer_config_t const * p_config)
166 {
167 NRFX_ASSERT(p_config);
168 NRFX_ASSERT(NRF_TIMER_IS_BIT_WIDTH_VALID(p_instance->p_reg, p_config->bit_width));
169
170 timer_control_block_t * p_cb = &m_cb[p_instance->instance_id];
171
172 if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
173 {
174 return NRFX_ERROR_INVALID_STATE;
175 }
176 if (p_cb->state == NRFX_DRV_STATE_POWERED_ON)
177 {
178 return NRFX_ERROR_BUSY;
179 }
180
181 p_cb->context = p_config->p_context;
182 nrfx_err_t err_code = timer_configure(p_instance, p_config);
183 return err_code;
184 }
185
nrfx_timer_uninit(nrfx_timer_t const * p_instance)186 void nrfx_timer_uninit(nrfx_timer_t const * p_instance)
187 {
188 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
189
190 nrfy_timer_int_uninit(p_instance->p_reg);
191
192 nrfy_timer_shorts_disable(p_instance->p_reg, ~0UL);
193 nrfy_timer_int_disable(p_instance->p_reg, ~0UL);
194
195 nrfx_timer_disable(p_instance);
196
197 m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_UNINITIALIZED;
198 NRFX_LOG_INFO("Uninitialized instance: %d.", p_instance->instance_id);
199 }
200
nrfx_timer_init_check(nrfx_timer_t const * p_instance)201 bool nrfx_timer_init_check(nrfx_timer_t const * p_instance)
202 {
203 timer_control_block_t * p_cb = &m_cb[p_instance->instance_id];
204
205 return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
206 }
207
nrfx_timer_enable(nrfx_timer_t const * p_instance)208 void nrfx_timer_enable(nrfx_timer_t const * p_instance)
209 {
210 NRFX_ASSERT(m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_INITIALIZED);
211
212 nrfy_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START);
213 m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_POWERED_ON;
214 NRFX_LOG_INFO("Enabled instance: %d.", p_instance->instance_id);
215 }
216
nrfx_timer_disable(nrfx_timer_t const * p_instance)217 void nrfx_timer_disable(nrfx_timer_t const * p_instance)
218 {
219 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
220
221 #if NRF_TIMER_HAS_SHUTDOWN
222 nrfy_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_SHUTDOWN);
223 #else
224 nrfy_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_STOP);
225 nrfy_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_CLEAR);
226 #endif
227 m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;
228 NRFX_LOG_INFO("Disabled instance: %d.", p_instance->instance_id);
229 }
230
nrfx_timer_is_enabled(nrfx_timer_t const * p_instance)231 bool nrfx_timer_is_enabled(nrfx_timer_t const * p_instance)
232 {
233 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
234
235 return (m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_POWERED_ON);
236 }
237
nrfx_timer_resume(nrfx_timer_t const * p_instance)238 void nrfx_timer_resume(nrfx_timer_t const * p_instance)
239 {
240 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
241
242 nrfy_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START);
243 NRFX_LOG_INFO("Resumed instance: %d.", p_instance->instance_id);
244 }
245
nrfx_timer_pause(nrfx_timer_t const * p_instance)246 void nrfx_timer_pause(nrfx_timer_t const * p_instance)
247 {
248 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
249
250 nrfy_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_STOP);
251 NRFX_LOG_INFO("Paused instance: %d.", p_instance->instance_id);
252 }
253
nrfx_timer_clear(nrfx_timer_t const * p_instance)254 void nrfx_timer_clear(nrfx_timer_t const * p_instance)
255 {
256 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
257
258 nrfy_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_CLEAR);
259 }
260
nrfx_timer_increment(nrfx_timer_t const * p_instance)261 void nrfx_timer_increment(nrfx_timer_t const * p_instance)
262 {
263 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
264 NRFX_ASSERT(nrfy_timer_mode_get(p_instance->p_reg) != NRF_TIMER_MODE_TIMER);
265
266 nrfy_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_COUNT);
267 }
268
nrfx_timer_capture(nrfx_timer_t const * p_instance,nrf_timer_cc_channel_t cc_channel)269 uint32_t nrfx_timer_capture(nrfx_timer_t const * p_instance, nrf_timer_cc_channel_t cc_channel)
270 {
271 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
272 NRFX_ASSERT(cc_channel < p_instance->cc_channel_count);
273
274 return nrfy_timer_capture_get(p_instance->p_reg, cc_channel);
275 }
276
nrfx_timer_us_to_ticks(nrfx_timer_t const * p_instance,uint32_t time_us)277 uint32_t nrfx_timer_us_to_ticks(nrfx_timer_t const * p_instance, uint32_t time_us)
278 {
279 uint32_t prescaler = nrfy_timer_prescaler_get(p_instance->p_reg);
280 uint32_t freq_base_mhz = NRFX_TIMER_BASE_FREQUENCY_GET(p_instance) / 1000000;
281 uint64_t ticks = (((uint64_t)time_us * freq_base_mhz) >> prescaler);
282 return (uint32_t)ticks;
283 }
284
nrfx_timer_ms_to_ticks(nrfx_timer_t const * p_instance,uint32_t time_ms)285 uint32_t nrfx_timer_ms_to_ticks(nrfx_timer_t const * p_instance, uint32_t time_ms)
286 {
287 uint32_t prescaler = nrfy_timer_prescaler_get(p_instance->p_reg);
288 uint32_t freq_base_khz = NRFX_TIMER_BASE_FREQUENCY_GET(p_instance) / 1000;
289 uint64_t ticks = (((uint64_t)time_ms * freq_base_khz) >> prescaler);
290 return (uint32_t)ticks;
291 }
292
nrfx_timer_compare(nrfx_timer_t const * p_instance,nrf_timer_cc_channel_t cc_channel,uint32_t cc_value,bool enable_int)293 void nrfx_timer_compare(nrfx_timer_t const * p_instance,
294 nrf_timer_cc_channel_t cc_channel,
295 uint32_t cc_value,
296 bool enable_int)
297 {
298 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
299
300 nrf_timer_int_mask_t timer_int = nrfy_timer_compare_int_get(cc_channel);
301
302 if (enable_int)
303 {
304 nrfy_timer_event_clear(p_instance->p_reg, nrfy_timer_compare_event_get(cc_channel));
305 nrfy_timer_int_enable(p_instance->p_reg, timer_int);
306 }
307 else
308 {
309 nrfy_timer_int_disable(p_instance->p_reg, timer_int);
310 }
311
312 nrfy_timer_cc_set(p_instance->p_reg, cc_channel, cc_value);
313 NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.",
314 p_instance->instance_id,
315 (unsigned long)cc_value,
316 cc_channel);
317 }
318
nrfx_timer_extended_compare(nrfx_timer_t const * p_instance,nrf_timer_cc_channel_t cc_channel,uint32_t cc_value,nrf_timer_short_mask_t timer_short_mask,bool enable_int)319 void nrfx_timer_extended_compare(nrfx_timer_t const * p_instance,
320 nrf_timer_cc_channel_t cc_channel,
321 uint32_t cc_value,
322 nrf_timer_short_mask_t timer_short_mask,
323 bool enable_int)
324 {
325 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
326
327 nrfy_timer_shorts_disable(p_instance->p_reg,
328 (uint32_t)(NRF_TIMER_SHORT_COMPARE0_STOP_MASK << cc_channel) |
329 (uint32_t)(NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK << cc_channel));
330
331 nrfy_timer_shorts_enable(p_instance->p_reg, timer_short_mask);
332
333 nrfx_timer_compare(p_instance,
334 cc_channel,
335 cc_value,
336 enable_int);
337 NRFX_LOG_INFO("Timer id: %d, capture value set: %lu, channel: %d.",
338 p_instance->instance_id,
339 (unsigned long)cc_value,
340 cc_channel);
341 }
342
nrfx_timer_compare_int_enable(nrfx_timer_t const * p_instance,uint32_t channel)343 void nrfx_timer_compare_int_enable(nrfx_timer_t const * p_instance, uint32_t channel)
344 {
345 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
346 NRFX_ASSERT(channel < p_instance->cc_channel_count);
347
348 nrfy_timer_event_clear(p_instance->p_reg, nrfy_timer_compare_event_get((uint8_t)channel));
349 nrfy_timer_int_enable(p_instance->p_reg, nrfy_timer_compare_int_get((uint8_t)channel));
350 }
351
nrfx_timer_compare_int_disable(nrfx_timer_t const * p_instance,uint32_t channel)352 void nrfx_timer_compare_int_disable(nrfx_timer_t const * p_instance, uint32_t channel)
353 {
354 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
355 NRFX_ASSERT(channel < p_instance->cc_channel_count);
356
357 nrfy_timer_int_disable(p_instance->p_reg, nrfy_timer_compare_int_get((uint8_t)channel));
358 }
359
irq_handler(NRF_TIMER_Type * p_reg,timer_control_block_t * p_cb,uint8_t channel_count)360 static void irq_handler(NRF_TIMER_Type * p_reg, timer_control_block_t * p_cb, uint8_t channel_count)
361 {
362 uint32_t event_mask = nrfy_timer_events_process(p_reg, NRF_TIMER_ALL_CHANNELS_INT_MASK);
363 nrf_timer_event_t event;
364 uint32_t active_cc_mask = nrfy_timer_int_enable_check(p_reg, NRF_TIMER_ALL_CHANNELS_INT_MASK);
365
366 for (uint8_t i = 0; i < channel_count; ++i)
367 {
368 event = nrfy_timer_compare_event_get(i);
369 if ((active_cc_mask & NRFY_EVENT_TO_INT_BITMASK(event)) &&
370 (event_mask & NRFY_EVENT_TO_INT_BITMASK(event)))
371 {
372 NRFX_LOG_DEBUG("Compare event, channel: %d.", i);
373 if (p_cb->handler)
374 {
375 p_cb->handler(event, p_cb->context);
376 }
377 }
378 }
379 }
380
381 NRFX_INSTANCE_IRQ_HANDLERS_EXT(TIMER, timer, NRF_TIMER_CC_CHANNEL_COUNT)
382
383 #endif // NRFX_CHECK(NRFX_TIMER_ENABLED)
384