Add rollover protection to the STM32 RTC sampling logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3963 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
417ae9969a
commit
cb518b3a04
@ -83,7 +83,6 @@
|
||||
|
||||
#define RTC_TIMEMSB_REG STM32_BKP_DR1
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
* Private Data
|
||||
************************************************************************************/
|
||||
@ -93,8 +92,8 @@
|
||||
* - on start-up
|
||||
* - during operation, reported by LSE interrupt
|
||||
*/
|
||||
volatile bool g_rtc_enabled = false;
|
||||
|
||||
volatile bool g_rtc_enabled = false;
|
||||
|
||||
/************************************************************************************
|
||||
* Private Functions
|
||||
@ -109,13 +108,11 @@ static inline void stm32_rtc_beginwr(void)
|
||||
modifyreg16(STM32_RTC_CRL, 0, RTC_CRL_CNF);
|
||||
}
|
||||
|
||||
|
||||
static inline void stm32_rtc_endwr(void)
|
||||
{
|
||||
modifyreg16(STM32_RTC_CRL, RTC_CRL_CNF, 0);
|
||||
}
|
||||
|
||||
|
||||
/** Wait for registerred to synchronise with RTC module, call after power-up only */
|
||||
static inline void stm32_rtc_wait4rsf(void)
|
||||
{
|
||||
@ -123,8 +120,6 @@ static inline void stm32_rtc_wait4rsf(void)
|
||||
while( !(getreg16(STM32_RTC_CRL) & RTC_CRL_RSF) ) up_waste();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
* Interrupt Service Routines
|
||||
************************************************************************************/
|
||||
@ -147,7 +142,6 @@ static int stm32_rtc_overflow_isr(int irq, void *context)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
* Public Function - Initialization
|
||||
************************************************************************************/
|
||||
@ -175,13 +169,13 @@ int up_rtcinitialize(void)
|
||||
|
||||
// \todo Get state from this function, if everything is
|
||||
// okay and whether it is already enabled (if it was disabled
|
||||
// reset upper time register
|
||||
// reset upper time register)
|
||||
g_rtc_enabled = true;
|
||||
|
||||
// \todo Possible stall? should we set the timeout period? and return with -1
|
||||
stm32_rtc_wait4rsf();
|
||||
|
||||
/* Configure prescaler, note that this are write-only registers */
|
||||
/* Configure prescaler, note that these are write-only registers */
|
||||
|
||||
stm32_rtc_beginwr();
|
||||
putreg16(prescaler >> 16, STM32_RTC_PRLH);
|
||||
@ -206,17 +200,53 @@ int up_rtcinitialize(void)
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/** Get time (counter) value
|
||||
*
|
||||
* \return time, where the unit depends on the prescaler value
|
||||
**/
|
||||
|
||||
clock_t up_rtc_getclock(void)
|
||||
{
|
||||
return ( (uint32_t)getreg16(STM32_RTC_CNTH) << 16) |
|
||||
(uint32_t)getreg16(STM32_RTC_CNTL);
|
||||
}
|
||||
irqstate_t flags;
|
||||
uint16_t cnth;
|
||||
uint16_t cntl;
|
||||
uint16_t tmp;
|
||||
|
||||
/* The RTC counter is read from two 16-bit registers to form one 32-bit
|
||||
* value. Because these are non-atomic operations, many things can happen
|
||||
* between the two reads: This thread could get suspended or interrrupted
|
||||
* or the lower 16-bit counter could rollover between reads. Disabling
|
||||
* interrupts will prevent suspensions and interruptions:
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
|
||||
/* And the following loop will handle any clock rollover events that may
|
||||
* happen between samples. Most of the time (like 99.9%), the following
|
||||
* loop will execute only once. In the rare rollover case, it should
|
||||
* execute no more than 2 times.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
tmp = getreg16(STM32_RTC_CNTL);
|
||||
cnth = getreg16(STM32_RTC_CNTH);
|
||||
cntl = getreg16(STM32_RTC_CNTL);
|
||||
}
|
||||
|
||||
/* The second sample of CNTL could be less than the first sample of CNTL
|
||||
* only if rollover occurred. In that case, CNTH may or may not be out
|
||||
* of sync. The best thing to do is try again until we know that no
|
||||
* rollover occurred.
|
||||
*/
|
||||
|
||||
while (cntl < tmp);
|
||||
irqrestore(flags);
|
||||
|
||||
/* Then return the full 32-bit counter value */
|
||||
|
||||
return ((uint32_t)cnth << 16) | (uint32_t)cntl;
|
||||
}
|
||||
|
||||
/** Set time (counter) value
|
||||
*
|
||||
@ -231,7 +261,6 @@ void up_rtc_setclock(clock_t newclock)
|
||||
stm32_rtc_endwr();
|
||||
}
|
||||
|
||||
|
||||
time_t up_rtc_gettime(void)
|
||||
{
|
||||
/* Fetch time from LSB (hardware counter) and MSB (backup domain)
|
||||
@ -263,7 +292,6 @@ time_t up_rtc_gettime(void)
|
||||
return time_msb | time_lsb;
|
||||
}
|
||||
|
||||
|
||||
void up_rtc_settime(time_t newtime)
|
||||
{
|
||||
/* Do reverse compared to gettime above */
|
||||
@ -281,7 +309,6 @@ void up_rtc_settime(time_t newtime)
|
||||
irqrestore( irqs );
|
||||
}
|
||||
|
||||
|
||||
/** Set ALARM at which time ALARM callback is going to be generated
|
||||
*
|
||||
* The function sets the alarm and return present time at the time
|
||||
@ -304,12 +331,10 @@ clock_t up_rtc_setalarm(clock_t atclock)
|
||||
return up_rtc_getclock();
|
||||
}
|
||||
|
||||
|
||||
/** Set alarm output pin */
|
||||
void stm32_rtc_settalarmpin(bool activate)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#endif // defined(CONFIG_STM32_BKP)
|
||||
/** \} */
|
||||
|
Loading…
Reference in New Issue
Block a user