RTC and Sub second Time

cancel
Showing results for 
Search instead for 
Did you mean: 

RTC and Sub second Time

Jump to solution
1,149 Views
Contributor IV

I would like to keep track of time to the millisecond. How can I do this on a K20? I would like the time to be accurate through low power modes down to VLLS2?

Any ideas ?

Leif

Labels (1)
1 Solution
56 Views
Senior Contributor III

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:

RTC seconds not updated properly

View solution in original post

5 Replies
57 Views
Senior Contributor III

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:

RTC seconds not updated properly

View solution in original post

56 Views
Contributor IV

Very good, thanks. I didn't understand the TPR register i guess, now i do.

Question why the double read? Is that documented by Freescale?

0 Kudos
56 Views
Senior Contributor III

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:

RTC counters behavior (seconds and prescaler registers)

0 Kudos
56 Views
Senior Contributor III

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!

0 Kudos
56 Views
Contributor IV

Okay, sounds good. Thanks for the knowledge.

I will implement it with the double read.

0 Kudos