Skip to content

Commit 4f99aa5

Browse files
committed
[NRF5] us_ticker:
- extarct for check rtc overflow - make common_rtc_32bit_ticks_get safe against preemption.
1 parent c6ef2f3 commit 4f99aa5

File tree

1 file changed

+45
-40
lines changed

1 file changed

+45
-40
lines changed

targets/TARGET_NORDIC/TARGET_NRF5/us_ticker.c

Lines changed: 45 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "nrf_drv_common.h"
4343
#include "nrf_drv_config.h"
4444
#include "lp_ticker_api.h"
45+
#include "mbed_critical.h"
4546

4647

4748
//------------------------------------------------------------------------------
@@ -52,19 +53,24 @@
5253
bool m_common_rtc_enabled = false;
5354
uint32_t volatile m_common_rtc_overflows = 0;
5455

55-
#if defined(TARGET_MCU_NRF51822)
56-
void common_rtc_irq_handler(void)
57-
#else
58-
void COMMON_RTC_IRQ_HANDLER(void)
59-
#endif
56+
__STATIC_INLINE void rtc_ovf_event_check(void)
6057
{
61-
6258
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW)) {
6359
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
6460
// Don't disable this event. It shall occur periodically.
6561

6662
++m_common_rtc_overflows;
6763
}
64+
}
65+
66+
#if defined(TARGET_MCU_NRF51822)
67+
void common_rtc_irq_handler(void)
68+
#else
69+
void COMMON_RTC_IRQ_HANDLER(void)
70+
#endif
71+
{
72+
73+
rtc_ovf_event_check();
6874

6975
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, US_TICKER_EVENT)) {
7076
us_ticker_irq_handler();
@@ -144,13 +150,37 @@ void common_rtc_init(void)
144150
m_common_rtc_enabled = true;
145151
}
146152

153+
__STATIC_INLINE void rtc_ovf_event_safe_check(void)
154+
{
155+
core_util_critical_section_enter();
156+
157+
rtc_ovf_event_check();
158+
159+
core_util_critical_section_exit();
160+
}
161+
162+
147163
uint32_t common_rtc_32bit_ticks_get(void)
148164
{
149-
uint32_t ticks = nrf_rtc_counter_get(COMMON_RTC_INSTANCE);
150-
// The counter used for time measurements is less than 32 bit wide,
151-
// so its value is complemented with the number of registered overflows
152-
// of the counter.
153-
ticks += (m_common_rtc_overflows << RTC_COUNTER_BITS);
165+
uint32_t ticks;
166+
uint32_t prev_overflows;
167+
168+
do {
169+
prev_overflows = m_common_rtc_overflows;
170+
171+
ticks = nrf_rtc_counter_get(COMMON_RTC_INSTANCE);
172+
// The counter used for time measurements is less than 32 bit wide,
173+
// so its value is complemented with the number of registered overflows
174+
// of the counter.
175+
ticks += (m_common_rtc_overflows << RTC_COUNTER_BITS);
176+
177+
// Check in case that OVF occurred during execution of a RTC handler (apply if call was from RTC handler)
178+
// m_common_rtc_overflows might been updated in this call.
179+
rtc_ovf_event_safe_check();
180+
181+
// If call was made from a low priority level m_common_rtc_overflows might have been updated in RTC handler.
182+
} while (m_common_rtc_overflows != prev_overflows);
183+
154184
return ticks;
155185
}
156186

@@ -161,7 +191,7 @@ uint64_t common_rtc_64bit_us_get(void)
161191
return ROUNDED_DIV(((uint64_t)ticks) * 1000000, RTC_INPUT_FREQ);
162192
}
163193

164-
__STATIC_INLINE void internal_common_rtc_set_interrupt(uint32_t us_timestamp, uint32_t cc_channel,
194+
void common_rtc_set_interrupt(uint32_t us_timestamp, uint32_t cc_channel,
165195
uint32_t int_mask)
166196
{
167197
// The internal counter is clocked with a frequency that cannot be easily
@@ -187,6 +217,8 @@ __STATIC_INLINE void internal_common_rtc_set_interrupt(uint32_t us_timestamp, ui
187217
uint32_t compare_value =
188218
(uint32_t)CEIL_DIV((timestamp64) * RTC_INPUT_FREQ, 1000000);
189219

220+
221+
core_util_critical_section_enter();
190222
// The COMPARE event occurs when the value in compare register is N and
191223
// the counter value changes from N-1 to N. Therefore, the minimal safe
192224
// difference between the compare value to be set and the current counter
@@ -199,35 +231,8 @@ __STATIC_INLINE void internal_common_rtc_set_interrupt(uint32_t us_timestamp, ui
199231

200232
nrf_rtc_cc_set(COMMON_RTC_INSTANCE, cc_channel, RTC_WRAP(compare_value));
201233
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, int_mask);
202-
}
203234

204-
void common_rtc_set_interrupt(uint32_t us_timestamp, uint32_t cc_channel,
205-
uint32_t int_mask)
206-
{
207-
uint32_t prev_overflows;
208-
209-
while (1)
210-
{
211-
prev_overflows = m_common_rtc_overflows;
212-
213-
internal_common_rtc_set_interrupt(us_timestamp, cc_channel, int_mask);
214-
215-
// check in case of preemption by RTC OVF event (apply if call was from a low priority level)
216-
if (prev_overflows != m_common_rtc_overflows)
217-
{
218-
continue;
219-
} // check in case that OVF occurred during execution of a RTC handler (apply if call was from RTC handler)
220-
else if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW))
221-
{
222-
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
223-
// Don't disable this event. It shall occur periodically.
224-
225-
++m_common_rtc_overflows;
226-
continue;
227-
}
228-
229-
break;
230-
}
235+
core_util_critical_section_exit();
231236
}
232237
//------------------------------------------------------------------------------
233238

0 commit comments

Comments
 (0)