Hello!
I have been working on a project recently and I am in need of millisecond precise time stamps.
I have a GPS providing time codes, but they are so infrequent that I would like to rely on something more regular.
The internal RTC for the Teensy 4.0 seems to be the solution.
I am looking at how to get millisecond precise reading by reading the raw data registers for the RTC and interpreting it manually. I was wondering how possible this approach is.
I have done some digging and found a couple things:
A Thread on Millisecond precision for the Teensy 3
This post with comments about handling register update issues
The RTC get and set functions in the Teensy 4 core
And various other less-useful information...
My questions are....
Overall, it seems like the registers store the RTC crystals cycles, where the 16th bit should be the actual second (32,768 cycles per second).
This doesnt really line up with my tests2:
It seems that the 24th bit (from the right) is very consistent in cycling every second, The 25th bit seems to count the seconds, but skips a second irregulary. (See lines 4 & 5)
So, That leaves me curious about how it works and what extra precision I can squeeze.
THANKS FOR YOUR INPUT IN ADVANCE!!
───────────────────────────────────────────────────────────────────
1: Source code for SNVS_HPRTCMR and SNVS_HPRTCLR values in Teensy 4 core:
2: Source code used to read RTC registers:
I have been working on a project recently and I am in need of millisecond precise time stamps.
I have a GPS providing time codes, but they are so infrequent that I would like to rely on something more regular.
The internal RTC for the Teensy 4.0 seems to be the solution.
I am looking at how to get millisecond precise reading by reading the raw data registers for the RTC and interpreting it manually. I was wondering how possible this approach is.
I have done some digging and found a couple things:
A Thread on Millisecond precision for the Teensy 3
This post with comments about handling register update issues
The RTC get and set functions in the Teensy 4 core
And various other less-useful information...
My questions are....
- What exactly do the SNVS_HPRTCMR and SNVS_HPRTCLR registers store? (Source code below1)
- How are the registers updated (So any potential issues can be handled)
- Is there a better way to do this that I dont know of (carry-over with power loss, poor GPS signal, no network, Millisecond precision)
Overall, it seems like the registers store the RTC crystals cycles, where the 16th bit should be the actual second (32,768 cycles per second).
This doesnt really line up with my tests2:
Code:
// RTC register reading taken 1000 ms apart using delay(1000);
// |───────── SNVS_HPRTCMR ─────────| |────────── SNVS_HPRTCLR ─────────|
1: 00000000 00000000 00000000 00000000 01110001 10010110 00011001 00001001
2: 00000000 00000000 00000000 00000000 01110010 00010110 00011010 00001001
3: 00000000 00000000 00000000 00000000 01110011 10010110 00011010 00001001
4: 00000000 00000000 00000000 00000000 01110100 00010110 00011011 00001001
5: 00000000 00000000 00000000 00000000 01110110 10010110 00011011 00001001
6: 00000000 00000000 00000000 00000000 01110111 00010110 00011100 00001001
7: 00000000 00000000 00000000 00000000 01111000 10010110 00011100 00001001
8: 00000000 00000000 00000000 00000000 01111001 00010110 00011101 00001001
9: 00000000 00000000 00000000 00000000 01111011 10010110 00011101 00001001
10:00000000 00000000 00000000 00000000 01111100 00010110 00011110 00001001
11:00000000 00000000 00000000 00000000 01111101 10010110 00011110 00001001
It seems that the 24th bit (from the right) is very consistent in cycling every second, The 25th bit seems to count the seconds, but skips a second irregulary. (See lines 4 & 5)
So, That leaves me curious about how it works and what extra precision I can squeeze.
THANKS FOR YOUR INPUT IN ADVANCE!!
───────────────────────────────────────────────────────────────────
1: Source code for SNVS_HPRTCMR and SNVS_HPRTCLR values in Teensy 4 core:
Code:
#include "imxrt.h"
#include "debug/printf.h"
unsigned long rtc_get(void)
{
uint32_t hi1 = SNVS_HPRTCMR;
uint32_t lo1 = SNVS_HPRTCLR;
while (1) {
uint32_t hi2 = SNVS_HPRTCMR;
uint32_t lo2 = SNVS_HPRTCLR;
if (lo1 == lo2 && hi1 == hi2) {
return (hi2 << 17) | (lo2 >> 15);
}
hi1 = hi2;
lo1 = lo2;
}
}
void rtc_set(unsigned long t)
{
// stop the RTC
SNVS_HPCR &= ~(SNVS_HPCR_RTC_EN | SNVS_HPCR_HP_TS);
while (SNVS_HPCR & SNVS_HPCR_RTC_EN); // wait
// stop the SRTC
SNVS_LPCR &= ~SNVS_LPCR_SRTC_ENV;
while (SNVS_LPCR & SNVS_LPCR_SRTC_ENV); // wait
// set the SRTC
SNVS_LPSRTCLR = t << 15;
SNVS_LPSRTCMR = t >> 17;
// start the SRTC
SNVS_LPCR |= SNVS_LPCR_SRTC_ENV;
while (!(SNVS_LPCR & SNVS_LPCR_SRTC_ENV)); // wait
// start the RTC and sync it to the SRTC
SNVS_HPCR |= SNVS_HPCR_RTC_EN | SNVS_HPCR_HP_TS;
}
void rtc_compensate(int adjust)
{
}
2: Source code used to read RTC registers:
Code:
#include "Arduino.h"
//#include "TimeLib.h"
void BinaryStrZeroPad(int Number,char ZeroPadding);
void setup(){
Serial.begin(9600);
rtc_set(0);
}
void loop(){
delay (1000);
for (int i = 3; i > -1; i--){
BinaryStrZeroPad((SNVS_HPRTCMR >> (8*i)) & 0xFF, 7);
Serial .print(" ");
}
for (int i = 0; i < 4; i++){
BinaryStrZeroPad((SNVS_HPRTCLR >> (8*i)) & 0xFF, 7);
Serial .print(" ");
}
Serial.println();
}
/** Binary Value Padding Function
* Credit: https://forum.arduino.cc/index.php?topic=475435.0
*
* Pads output with 0's
*/
void BinaryStrZeroPad(int Number,char ZeroPadding){
//ZeroPadding = nth bit, e.g for a 16 bit number nth bit = 15
signed char i=ZeroPadding;
while(i>=0){
if((Number & (1<<i)) > 0) Serial.write('1');
else Serial.write('0');
--i;
}
}
Last edited: