IF you don't use the 'adjustment' features of the RTC divider chains, so that you can ALWAYS assume 32768 counts per second, then the time-prescale-register (TPR) can get you what you want. Here is my low-level-driver: This code may not be 'perfect', in that I might not be allowing enough time between my dual-reads to account for how SLOW these ripple-counters update themselves...
void _rtc_get_time
(
/* [OUT] this parameter gets actual RTC time */
TIME_STRUCT_PTR time
)
{
uint32_t read1, read2;
do{
read1 = RTC_TSR;
read2 = RTC_TSR;
}while( read1 != read2); //insure the same read twice to avoid 'glitches'
time->SECONDS = read1;
do{
read1 = RTC_TPR;
read2 = RTC_TPR;
}while( read1 != read2); //insure the same read twice to avoid 'glitches'
//Scale 32.768KHz to microseconds, but do the math within 32bits by leaving out 2^6
// 30.51758us per TPR count
time->MICROSECONDS = (read1*(1000000UL/64)+16384/64)/(32768/64); //Round crystal counts to microseconds
if( time->MICROSECONDS < 100 ) //if prescaler just rolled over from zero, might have just incremented seconds -- refetch
{
do{
read1 = RTC_TSR;
read2 = RTC_TSR;
}while( read1 != read2); //insure the same read twice to avoid 'glitches'
time->SECONDS = read1;
}
}
See also:
IF you don't use the 'adjustment' features of the RTC divider chains, so that you can ALWAYS assume 32768 counts per second, then the time-prescale-register (TPR) can get you what you want. Here is my low-level-driver: This code may not be 'perfect', in that I might not be allowing enough time between my dual-reads to account for how SLOW these ripple-counters update themselves...
void _rtc_get_time
(
/* [OUT] this parameter gets actual RTC time */
TIME_STRUCT_PTR time
)
{
uint32_t read1, read2;
do{
read1 = RTC_TSR;
read2 = RTC_TSR;
}while( read1 != read2); //insure the same read twice to avoid 'glitches'
time->SECONDS = read1;
do{
read1 = RTC_TPR;
read2 = RTC_TPR;
}while( read1 != read2); //insure the same read twice to avoid 'glitches'
//Scale 32.768KHz to microseconds, but do the math within 32bits by leaving out 2^6
// 30.51758us per TPR count
time->MICROSECONDS = (read1*(1000000UL/64)+16384/64)/(32768/64); //Round crystal counts to microseconds
if( time->MICROSECONDS < 100 ) //if prescaler just rolled over from zero, might have just incremented seconds -- refetch
{
do{
read1 = RTC_TSR;
read2 = RTC_TSR;
}while( read1 != read2); //insure the same read twice to avoid 'glitches'
time->SECONDS = read1;
}
}
See also:
Certainly if you look down that link to another thread you will see where one user certainly discovered that 'TPR rollover' did NOT 'instantly' increment the seconds. On a more general note, such a 'very low power subsystem' is intentionally made with 'slow' logic, so the asynchronous count events COULD get 'caught' mid-rollover. Now in my particular case 'always being right' was not important enough to look further into the details, and to whether these dual-reads (and near-rollover-test) are sufficient to guarantee monotonic time-values, as I only use them as console/log timestamps and a 'minor error' on one in a million is of NO consequence.
See also:
This discussion has piqued my curiosity regarding time-read reliability and the desire for time to always 'move forward'. I added this check:
_rtc_get_time( &rtc_time ); | |
if( (rtc_time.SECONDS < rtc_time_last.SECONDS) | |
|| ((rtc_time.SECONDS == rtc_time_last.SECONDS) && (rtc_time.MICROSECONDS < rtc_time_last.MICROSECONDS)) ) | |
{ | |
Os_LogDebug(OS_LOG_DEBUG_ERROR, "Time slip. Old:%X.%X, New:%X.%X\n", | |
rtc_time_last.SECONDS,rtc_time_last.MICROSECONDS,rtc_time.SECONDS,rtc_time.MICROSECONDS); | |
} | |
rtc_time_last.MICROSECONDS = rtc_time.MICROSECONDS; | |
rtc_time_last.SECONDS = rtc_time.SECONDS; |
in my 'idle' loop [most of the time], so about 175,000 checks per second. WITHOUT the protections of the above _rtc_get_time dual-reads and rollover-check, I got about 5 per second of these timestamped [HH:MM:SS.ms] prints showing TPR reads of 'inconsistent' contents due to increment-ripple-in-progress:
[09:12:33.653] ERR: Time slip. Old:56309181.9F9D2, New:56309181.9F808
[09:12:33.736] ERR: Time slip. Old:56309181.B3D1E, New:56309181.B3C48
Turning back 'on' the dual-reads-check knocked them out, but left a few of these at 'TPR rollover' from 999,969us to zero:
[09:15:24.000] ERR: Time slip. Old:5630922B.F4221, New:5630922B.0
[09:15:26.000] ERR: Time slip. Old:5630922D.F4221, New:5630922D.0
When I re-enabled that rollover protection but at '<50us', I got one in 15minutes:
[09:33:27.000] ERR: Time slip. Old:56309666.F4221, New:56309666.3D
This indicates that one(or more) 'interrupt(s)' between the TSR reads and the TPR reads took LONG ENOUGH to make the <50us check 'fail' to protect from seconds rollover: In this case TPR went from '-31us' to '+61us' AFTER we had already read TSR. At the original '<100us' (as above) for the 'rollover time check' I don't expect I would have ever seen a fault, but THAT depends entirely on one's worst interrupt processing interval! Mine is 70us.
I suggest that the entire _rtc_get_time routine should be run with interrupts disabled! The routine only takes 1 to 1.5us at 100MHz. Adding DisableInterrupts and EnableInterrupts around it, I've gotten NO fault in 6 hours!