[NRF52840]: fix:

- rtc overflow-while-set-timestamp issue
- timer has a race condition
pull/4174/head
Andrzej Puzdrowski 2017-04-12 11:10:48 +02:00
parent 7d65b0f644
commit 560bd7403d
1 changed files with 46 additions and 16 deletions

View File

@ -55,32 +55,36 @@
bool m_common_rtc_enabled = false; bool m_common_rtc_enabled = false;
uint32_t volatile m_common_rtc_overflows = 0; uint32_t volatile m_common_rtc_overflows = 0;
__STATIC_INLINE void rtc_ovf_event_check(void)
{
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW)) {
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
// Don't disable this event. It shall occur periodically.
++m_common_rtc_overflows;
}
}
#if defined(TARGET_MCU_NRF51822) #if defined(TARGET_MCU_NRF51822)
void common_rtc_irq_handler(void) void common_rtc_irq_handler(void)
#else #else
void COMMON_RTC_IRQ_HANDLER(void) void COMMON_RTC_IRQ_HANDLER(void)
#endif #endif
{ {
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, US_TICKER_EVENT))
{ rtc_ovf_event_check();
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, US_TICKER_EVENT)) {
us_ticker_irq_handler(); us_ticker_irq_handler();
} }
#if DEVICE_LOWPOWERTIMER #if DEVICE_LOWPOWERTIMER
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, LP_TICKER_EVENT)) if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, LP_TICKER_EVENT)) {
{
lp_ticker_irq_handler(); lp_ticker_irq_handler();
} }
#endif #endif
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW))
{
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
// Don't disable this event. It shall occur periodically.
++m_common_rtc_overflows;
}
} }
// Function for fix errata 20: RTC Register values are invalid // Function for fix errata 20: RTC Register values are invalid
@ -168,13 +172,37 @@ void common_rtc_init(void)
m_common_rtc_enabled = true; m_common_rtc_enabled = true;
} }
__STATIC_INLINE void rtc_ovf_event_safe_check(void)
{
core_util_critical_section_enter();
rtc_ovf_event_check();
core_util_critical_section_exit();
}
uint32_t common_rtc_32bit_ticks_get(void) uint32_t common_rtc_32bit_ticks_get(void)
{ {
uint32_t ticks = nrf_rtc_counter_get(COMMON_RTC_INSTANCE); uint32_t ticks;
// The counter used for time measurements is less than 32 bit wide, uint32_t prev_overflows;
// so its value is complemented with the number of registered overflows
// of the counter. do {
ticks += (m_common_rtc_overflows << RTC_COUNTER_BITS); prev_overflows = m_common_rtc_overflows;
ticks = nrf_rtc_counter_get(COMMON_RTC_INSTANCE);
// The counter used for time measurements is less than 32 bit wide,
// so its value is complemented with the number of registered overflows
// of the counter.
ticks += (m_common_rtc_overflows << RTC_COUNTER_BITS);
// Check in case that OVF occurred during execution of a RTC handler (apply if call was from RTC handler)
// m_common_rtc_overflows might been updated in this call.
rtc_ovf_event_safe_check();
// If call was made from a low priority level m_common_rtc_overflows might have been updated in RTC handler.
} while (m_common_rtc_overflows != prev_overflows);
return ticks; return ticks;
} }
@ -213,6 +241,7 @@ void common_rtc_set_interrupt(uint32_t us_timestamp, uint32_t cc_channel,
uint32_t compare_value = uint32_t compare_value =
(uint32_t)CEIL_DIV((timestamp64) * RTC_INPUT_FREQ, 1000000); (uint32_t)CEIL_DIV((timestamp64) * RTC_INPUT_FREQ, 1000000);
core_util_critical_section_enter();
// The COMPARE event occurs when the value in compare register is N and // The COMPARE event occurs when the value in compare register is N and
// the counter value changes from N-1 to N. Therefore, the minimal safe // the counter value changes from N-1 to N. Therefore, the minimal safe
// difference between the compare value to be set and the current counter // difference between the compare value to be set and the current counter
@ -226,6 +255,7 @@ void common_rtc_set_interrupt(uint32_t us_timestamp, uint32_t cc_channel,
nrf_rtc_cc_set(COMMON_RTC_INSTANCE, cc_channel, RTC_WRAP(compare_value)); nrf_rtc_cc_set(COMMON_RTC_INSTANCE, cc_channel, RTC_WRAP(compare_value));
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, int_mask); nrf_rtc_event_enable(COMMON_RTC_INSTANCE, int_mask);
core_util_critical_section_exit();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------