1 /*
2 * Copyright (c) 2014 - 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_RTC_ENABLED)
37
38 #if !NRFX_FEATURE_PRESENT(NRFX_RTC, _ENABLED)
39 #error "No enabled RTC instances. Check <nrfx_config.h>."
40 #endif
41
42 #include <nrfx_rtc.h>
43
44 #define NRFX_LOG_MODULE RTC
45 #include <nrfx_log.h>
46
47 #define EVT_TO_STR(event) \
48 (event == NRF_RTC_EVENT_TICK ? "NRF_RTC_EVENT_TICK" : \
49 (event == NRF_RTC_EVENT_OVERFLOW ? "NRF_RTC_EVENT_OVERFLOW" : \
50 (event == NRF_RTC_EVENT_COMPARE_0 ? "NRF_RTC_EVENT_COMPARE_0" : \
51 (event == NRF_RTC_EVENT_COMPARE_1 ? "NRF_RTC_EVENT_COMPARE_1" : \
52 (event == NRF_RTC_EVENT_COMPARE_2 ? "NRF_RTC_EVENT_COMPARE_2" : \
53 (event == NRF_RTC_EVENT_COMPARE_3 ? "NRF_RTC_EVENT_COMPARE_3" : \
54 "UNKNOWN EVENT"))))))
55
56 /** @brief RTC driver instance control block structure. */
57 typedef struct
58 {
59 nrfx_rtc_handler_t handler; /**< Instance event handler. */
60 nrfx_drv_state_t state; /**< Instance state. */
61 bool reliable; /**< Reliable mode flag. */
62 uint8_t tick_latency; /**< Maximum length of interrupt handler in ticks (max 7.7 ms). */
63 } nrfx_rtc_cb_t;
64
65 // User callbacks local storage.
66 static nrfx_rtc_cb_t m_cb[NRFX_RTC_ENABLED_COUNT];
67
nrfx_rtc_init(nrfx_rtc_t const * p_instance,nrfx_rtc_config_t const * p_config,nrfx_rtc_handler_t handler)68 nrfx_err_t nrfx_rtc_init(nrfx_rtc_t const * p_instance,
69 nrfx_rtc_config_t const * p_config,
70 nrfx_rtc_handler_t handler)
71 {
72 NRFX_ASSERT(p_config);
73 NRFX_ASSERT(handler);
74 nrfx_err_t err_code;
75
76 m_cb[p_instance->instance_id].handler = handler;
77
78 if (m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED)
79 {
80 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
81 err_code = NRFX_ERROR_ALREADY;
82 #else
83 err_code = NRFX_ERROR_INVALID_STATE;
84 #endif
85 NRFX_LOG_WARNING("Function: %s, error code: %s.",
86 __func__,
87 NRFX_LOG_ERROR_STRING_GET(err_code));
88 return err_code;
89 }
90
91 nrfy_rtc_int_init(p_instance->p_reg, 0, p_config->interrupt_priority, false);
92
93 nrfy_rtc_config_t config =
94 {
95 .prescaler = p_config->prescaler
96 };
97
98 nrfy_rtc_periph_configure(p_instance->p_reg, &config);
99 m_cb[p_instance->instance_id].reliable = p_config->reliable;
100 m_cb[p_instance->instance_id].tick_latency = p_config->tick_latency;
101 m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;
102
103 err_code = NRFX_SUCCESS;
104 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
105 return err_code;
106 }
107
nrfx_rtc_uninit(nrfx_rtc_t const * p_instance)108 void nrfx_rtc_uninit(nrfx_rtc_t const * p_instance)
109 {
110 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
111
112 uint32_t mask = NRF_RTC_INT_TICK_MASK |
113 NRF_RTC_INT_OVERFLOW_MASK |
114 NRF_RTC_ALL_CHANNELS_INT_MASK;
115
116 nrfy_rtc_int_uninit(p_instance->p_reg);
117 nrfy_rtc_stop(p_instance->p_reg, mask);
118
119 m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_UNINITIALIZED;
120 NRFX_LOG_INFO("Uninitialized.");
121 }
122
nrfx_rtc_init_check(nrfx_rtc_t const * p_instance)123 bool nrfx_rtc_init_check(nrfx_rtc_t const * p_instance)
124 {
125 return (m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
126 }
127
nrfx_rtc_enable(nrfx_rtc_t const * p_instance)128 void nrfx_rtc_enable(nrfx_rtc_t const * p_instance)
129 {
130 NRFX_ASSERT(m_cb[p_instance->instance_id].state == NRFX_DRV_STATE_INITIALIZED);
131
132 nrfy_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_START);
133 m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_POWERED_ON;
134 NRFX_LOG_INFO("Enabled.");
135 }
136
nrfx_rtc_disable(nrfx_rtc_t const * p_instance)137 void nrfx_rtc_disable(nrfx_rtc_t const * p_instance)
138 {
139 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
140
141 nrfy_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_STOP);
142 m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;
143 NRFX_LOG_INFO("Disabled.");
144 }
145
nrfx_rtc_cc_disable(nrfx_rtc_t const * p_instance,uint32_t channel)146 nrfx_err_t nrfx_rtc_cc_disable(nrfx_rtc_t const * p_instance, uint32_t channel)
147 {
148 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
149 NRFX_ASSERT(channel < p_instance->cc_channel_count);
150
151 nrfx_err_t err_code;
152 uint32_t int_mask = NRF_RTC_CHANNEL_INT_MASK(channel);
153 nrf_rtc_event_t event = NRF_RTC_CHANNEL_EVENT_ADDR(channel);
154
155 nrfy_rtc_event_disable(p_instance->p_reg, int_mask);
156 if (nrfy_rtc_int_enable_check(p_instance->p_reg, int_mask))
157 {
158 nrfy_rtc_int_disable(p_instance->p_reg, int_mask);
159 if (nrfy_rtc_event_check(p_instance->p_reg, event))
160 {
161 nrfy_rtc_event_clear(p_instance->p_reg, event);
162 err_code = NRFX_ERROR_TIMEOUT;
163 NRFX_LOG_WARNING("Function: %s, error code: %s.",
164 __func__,
165 NRFX_LOG_ERROR_STRING_GET(err_code));
166 return err_code;
167 }
168 }
169 NRFX_LOG_INFO("RTC id: %d, channel disabled: %lu.",
170 p_instance->instance_id,
171 (unsigned long)channel);
172 err_code = NRFX_SUCCESS;
173 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
174 return err_code;
175 }
176
nrfx_rtc_cc_set(nrfx_rtc_t const * p_instance,uint32_t channel,uint32_t val,bool enable_irq)177 nrfx_err_t nrfx_rtc_cc_set(nrfx_rtc_t const * p_instance,
178 uint32_t channel,
179 uint32_t val,
180 bool enable_irq)
181 {
182 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
183 NRFX_ASSERT(channel < p_instance->cc_channel_count);
184
185 nrfx_err_t err_code;
186 uint32_t int_mask = NRF_RTC_CHANNEL_INT_MASK(channel);
187 nrf_rtc_event_t event = NRF_RTC_CHANNEL_EVENT_ADDR(channel);
188
189 nrfy_rtc_event_int_disable(p_instance->p_reg, int_mask);
190
191 val = NRF_RTC_WRAP(val);
192 if (m_cb[p_instance->instance_id].reliable)
193 {
194 nrfy_rtc_cc_set(p_instance->p_reg, channel, val);
195 uint32_t cnt = nrfy_rtc_counter_get(p_instance->p_reg);
196 int32_t diff = (int32_t)(cnt - val);
197 if (cnt < val)
198 {
199 diff += (int32_t)NRF_RTC_COUNTER_MAX;
200 }
201 if (diff < m_cb[p_instance->instance_id].tick_latency)
202 {
203 err_code = NRFX_ERROR_TIMEOUT;
204 NRFX_LOG_WARNING("Function: %s, error code: %s.",
205 __func__,
206 NRFX_LOG_ERROR_STRING_GET(err_code));
207 return err_code;
208 }
209 }
210 else
211 {
212 nrfy_rtc_cc_set(p_instance->p_reg, channel, val);
213 }
214
215 nrfy_rtc_event_int_clear_enable(p_instance->p_reg, event, enable_irq);
216
217 NRFX_LOG_INFO("RTC id: %d, channel enabled: %lu, compare value: %lu.",
218 p_instance->instance_id,
219 (unsigned long)channel,
220 (unsigned long)val);
221 err_code = NRFX_SUCCESS;
222 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
223 return err_code;
224 }
225
nrfx_rtc_tick_enable(nrfx_rtc_t const * p_instance,bool enable_irq)226 void nrfx_rtc_tick_enable(nrfx_rtc_t const * p_instance, bool enable_irq)
227 {
228 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
229
230 nrfy_rtc_event_int_clear_enable(p_instance->p_reg,
231 NRF_RTC_EVENT_TICK,
232 enable_irq);
233 NRFX_LOG_INFO("Tick events enabled.");
234 }
235
nrfx_rtc_tick_disable(nrfx_rtc_t const * p_instance)236 void nrfx_rtc_tick_disable(nrfx_rtc_t const * p_instance)
237 {
238 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
239
240 nrfy_rtc_event_int_disable(p_instance->p_reg,
241 NRF_RTC_INT_TICK_MASK);
242 NRFX_LOG_INFO("Tick events disabled.");
243 }
244
nrfx_rtc_overflow_enable(nrfx_rtc_t const * p_instance,bool enable_irq)245 void nrfx_rtc_overflow_enable(nrfx_rtc_t const * p_instance, bool enable_irq)
246 {
247 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
248
249 nrfy_rtc_event_int_clear_enable(p_instance->p_reg,
250 NRF_RTC_EVENT_OVERFLOW,
251 enable_irq);
252 }
253
nrfx_rtc_overflow_disable(nrfx_rtc_t const * p_instance)254 void nrfx_rtc_overflow_disable(nrfx_rtc_t const * p_instance)
255 {
256 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
257
258 nrfy_rtc_event_int_disable(p_instance->p_reg,
259 NRF_RTC_INT_OVERFLOW_MASK);
260 }
261
nrfx_rtc_max_ticks_get(nrfx_rtc_t const * p_instance)262 uint32_t nrfx_rtc_max_ticks_get(nrfx_rtc_t const * p_instance)
263 {
264 NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
265
266 uint32_t ticks;
267 if (m_cb[p_instance->instance_id].reliable)
268 {
269 ticks = NRF_RTC_COUNTER_MAX - m_cb[p_instance->instance_id].tick_latency;
270 }
271 else
272 {
273 ticks = NRF_RTC_COUNTER_MAX;
274 }
275 return ticks;
276 }
277
irq_handler(NRF_RTC_Type * p_reg,nrfx_rtc_cb_t * p_cb,uint32_t channel_count)278 static void irq_handler(NRF_RTC_Type * p_reg,
279 nrfx_rtc_cb_t * p_cb,
280 uint32_t channel_count)
281 {
282 uint32_t evt_to_process = NRFY_EVENT_TO_INT_BITMASK(NRF_RTC_EVENT_TICK) |
283 NRFY_EVENT_TO_INT_BITMASK(NRF_RTC_EVENT_OVERFLOW) |
284 NRF_RTC_ALL_CHANNELS_INT_MASK;
285
286 uint32_t event_mask = nrfy_rtc_events_process(p_reg, evt_to_process);
287
288 uint32_t active_cc_mask = nrfy_rtc_int_enable_check(p_reg, NRF_RTC_ALL_CHANNELS_INT_MASK);
289
290 for (uint8_t i = 0; i < channel_count; i++)
291 {
292 nrf_rtc_event_t event = nrf_rtc_compare_event_get(i);
293 if ((active_cc_mask & NRFY_EVENT_TO_INT_BITMASK(event)) &&
294 (event_mask & NRFY_EVENT_TO_INT_BITMASK(event)))
295 {
296 nrfy_rtc_event_disable(p_reg, NRFY_EVENT_TO_INT_BITMASK(event));
297 NRFX_LOG_DEBUG("Event: %s, reg: %p.", EVT_TO_STR(event), p_reg);
298 p_cb->handler((nrfx_rtc_int_type_t)i);
299 }
300 }
301
302 if (event_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_RTC_EVENT_TICK))
303 {
304 NRFX_LOG_DEBUG("Event: %s, reg: %p.", EVT_TO_STR(NRF_RTC_EVENT_TICK), p_reg);
305 p_cb->handler(NRFX_RTC_INT_TICK);
306 }
307
308 if (event_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_RTC_EVENT_OVERFLOW))
309 {
310 NRFX_LOG_DEBUG("Event: %s, reg: %p.", EVT_TO_STR(NRF_RTC_EVENT_OVERFLOW), p_reg);
311 p_cb->handler(NRFX_RTC_INT_OVERFLOW);
312 }
313 }
314
315 NRFX_INSTANCE_IRQ_HANDLERS_EXT(RTC, rtc, NRF_RTC_CC_CHANNEL_COUNT)
316
317 #endif // NRFX_CHECK(NRFX_RTC_ENABLED)
318