For a project I'm making, I'm timestamping logs that are written to an SD card. To make debugging easier, I wanted to include the subsecond (millisecond) value in the log entry. I started out using millis() for this, but found that the millis() and RTC second rollover aren't synced, which makes sense. Thus, I looked into getting subsecond precision from the RTC by directly reading the count register and masking away the higher parts.
Now, I am able to get this value, but it seems like the subsecond value of the RTC isn't synced up with the seconds. I don't understand how it could be 'unsynced', since it comes from the same 2 registers, but i get the following output:
20260217 20:52:31.896
20260217 20:52:32.897
So the digit counting seconds rollsover, while the fractional part is not 0.
The datetime comes from calling now(), and using the breakTime function. Fractional calculation is done as follows:
So, my next step would have been to loop inside setup() until the seconds rolled over, and then save the subsecond offset, and apply this offset when printing my logs. However, it seems as if this offset isn't constant. I checked the reference manual of the imxrt1062 and I found a calibration function. I printed this register and the calibration was not enabled, so I think my assumption of 32768 cycles/second should be correct.
When running the bare minimum example code below, this is printed in my instance. Each line is printed when the now() function returns a different number. That also prints the current 'offset' which is ~11660 in the example below. The -1,-1,0,-1,0 sequence seems to repeat itself indefinitely. I don't understand how this is possible.
1771360827 20:40:27 10101101 10001111 11663 -1<\r><\n>
1771360828 20:40:28 00101101 10001111 11663 0<\r><\n>
1771360829 20:40:29 10101101 10001110 11662 -1<\r><\n>
1771360830 20:40:30 00101101 10001110 11662 0<\r><\n>
1771360831 20:40:31 10101101 10001101 11661 -1<\r><\n>
1771360832 20:40:32 00101101 10001100 11660 -1<\r><\n>
1771360833 20:40:33 10101101 10001100 11660 0<\r><\n>
1771360834 20:40:34 00101101 10001011 11659 -1<\r><\n>
1771360835 20:40:35 10101101 10001011 11659 0<\r><\n>
1771360836 20:40:36 00101101 10001010 11658 -1<\r><\n>
1771360837 20:40:37 10101101 10001001 11657 -1<\r><\n>
1771360838 20:40:38 00101101 10001001 11657 0<\r><\n>
Wrapping up, I would like to know why this happens and how I can fix it. I'm probably making a dumb mistake somewhere, but I can't find it.
Now, I am able to get this value, but it seems like the subsecond value of the RTC isn't synced up with the seconds. I don't understand how it could be 'unsynced', since it comes from the same 2 registers, but i get the following output:
20260217 20:52:31.896
20260217 20:52:32.897
So the digit counting seconds rollsover, while the fractional part is not 0.
The datetime comes from calling now(), and using the breakTime function. Fractional calculation is done as follows:
C++:
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) {
break;
}
hi1 = hi2;
lo1 = lo2;
}
uint16_t fraction = lo1 & 0x007FFF;
Serial.println(1000.0f * fraction / 32768.0f);
So, my next step would have been to loop inside setup() until the seconds rolled over, and then save the subsecond offset, and apply this offset when printing my logs. However, it seems as if this offset isn't constant. I checked the reference manual of the imxrt1062 and I found a calibration function. I printed this register and the calibration was not enabled, so I think my assumption of 32768 cycles/second should be correct.
When running the bare minimum example code below, this is printed in my instance. Each line is printed when the now() function returns a different number. That also prints the current 'offset' which is ~11660 in the example below. The -1,-1,0,-1,0 sequence seems to repeat itself indefinitely. I don't understand how this is possible.
1771360827 20:40:27 10101101 10001111 11663 -1<\r><\n>
1771360828 20:40:28 00101101 10001111 11663 0<\r><\n>
1771360829 20:40:29 10101101 10001110 11662 -1<\r><\n>
1771360830 20:40:30 00101101 10001110 11662 0<\r><\n>
1771360831 20:40:31 10101101 10001101 11661 -1<\r><\n>
1771360832 20:40:32 00101101 10001100 11660 -1<\r><\n>
1771360833 20:40:33 10101101 10001100 11660 0<\r><\n>
1771360834 20:40:34 00101101 10001011 11659 -1<\r><\n>
1771360835 20:40:35 10101101 10001011 11659 0<\r><\n>
1771360836 20:40:36 00101101 10001010 11658 -1<\r><\n>
1771360837 20:40:37 10101101 10001001 11657 -1<\r><\n>
1771360838 20:40:38 00101101 10001001 11657 0<\r><\n>
C++:
#include <TimeLib.h>
#include <Arduino.h>
time_t getTeensy3Time() {
return Teensy3Clock.get();
}
void setup() {
Serial.begin(0);
setSyncProvider(getTeensy3Time);
if (timeStatus() != timeSet) {
Serial.println("RTC time not set");
}
time_t seconds_prev = 0;
uint16_t reg_samp_prev = 0;
//HPCALB_EN in SNVS_HPCR is 0, so it should take 32768 counts per second (on average with some jitter ofc). but it doesn't
while (1) {
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) {
break;
}
hi1 = hi2;
lo1 = lo2;
}
time_t seconds = now();
if (seconds != seconds_prev) {
//Seconds
Serial.print(seconds);
Serial.print(" ");
//Hour-Minute-Second
TimeElements tm;
breakTime(seconds, tm);
Serial.print(tm.Hour); Serial.print(":"); Serial.print(tm.Minute); Serial.print(":"); Serial.print(tm.Second);
Serial.print(" ");
//Binary
uint16_t mask = 1 << ((sizeof(uint16_t) * 8) - 1);
int nr = 1;
while (mask) {
Serial.print(((lo1 & 0x0000FFFF) & mask) ? '1' : '0');
mask >>= 1;
if (nr++ % 8 == 0) {
Serial.print(" ");
}
}
//As decimal
Serial.print(" ");
uint16_t subsecond = lo1 & 0x0000FFFF;
if (subsecond > 32768) {
subsecond -= 32768;
}
Serial.print(subsecond);
//Difference
Serial.print(" ");
Serial.println(subsecond - reg_samp_prev);
reg_samp_prev = subsecond;
}
seconds_prev = seconds;
delayMicroseconds(1);
}
}
void loop() { }
Wrapping up, I would like to know why this happens and how I can fix it. I'm probably making a dumb mistake somewhere, but I can't find it.