Safely initialize RTC on kinetis devices

When initializing the RTC on Kinetis devices, handle the case where
the time overflow interrupt is pending and the case where the time
alarm flag is pending. These flags persist across reset and if not
handled will cause a crash when powering up the low power ticker.

This problem manifested as a lp_ticker test failure on the K22F and
K64F on CI only when running a nightly. This problem has been present
but was made obvious by PR #4094 which configures all tickers to
interrupt at least every MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA
(~31 minutes). This caused the RTC alarm to fire 31 minutes after the lp_ticker
or lp_timeout test and caused the next run of the lp_ticker test to
crash on boot.
pull/4453/head
Russ Butler 2017-06-05 15:49:23 -05:00
parent 8d6bc1d47d
commit f749a2990b
1 changed files with 20 additions and 9 deletions

View File

@ -33,16 +33,26 @@ static int lptmr_schedule = 0;
static void rtc_isr(void) static void rtc_isr(void)
{ {
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable); uint32_t sr = RTC->SR;
RTC->TAR = 0; /* Write clears the IRQ flag */ if (sr & RTC_SR_TOF_MASK) {
// Reset RTC to 0 so it keeps counting
RTC_StopTimer(RTC);
RTC->TSR = 0;
RTC_StartTimer(RTC);
} else if (sr & RTC_SR_TAF_MASK) {
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable);
RTC->TAR = 0; /* Write clears the IRQ flag */
/* Wait subsecond remainder if any */ /* Wait subsecond remainder if any */
if (lptmr_schedule) { if (lptmr_schedule) {
LPTMR_SetTimerPeriod(LPTMR0, lptmr_schedule); LPTMR_SetTimerPeriod(LPTMR0, lptmr_schedule);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable); LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0); LPTMR_StartTimer(LPTMR0);
} else { } else {
lp_ticker_irq_handler(); lp_ticker_irq_handler();
}
} else if (sr & RTC_SR_TIF_MASK) {
RTC_DisableInterrupts(RTC, kRTC_TimeOverflowInterruptEnable);
} }
} }
@ -73,6 +83,7 @@ void lp_ticker_init(void)
RTC_StartTimer(RTC); RTC_StartTimer(RTC);
} }
RTC->TAR = 0; /* Write clears the IRQ flag */
NVIC_ClearPendingIRQ(RTC_IRQn); NVIC_ClearPendingIRQ(RTC_IRQn);
NVIC_SetVector(RTC_IRQn, (uint32_t)rtc_isr); NVIC_SetVector(RTC_IRQn, (uint32_t)rtc_isr);
NVIC_EnableIRQ(RTC_IRQn); NVIC_EnableIRQ(RTC_IRQn);