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