Hi,
We have a custom board with an nRF9160. We are using NCS 2.0.2 and we are using the RTC to keep track of local time. For this we are using the "counter" from Zephyr.
In the overlay file we have configured the RTC to count in 1/256 second steps. (We need to have 1/256s accuracy)
&rtc0 { /* f_rtc = f_lfclk/(prs+1) * zephyr driver automatically subtracts -1 * -> prs of 128 needed in device tree for 256Hz */ prescaler = <128>; };
We always get the time of our Server for reference when we do a sync over LTE and when the times are off by >=5s, we log this and resync the local timestamp. We have noticed, that over the course of a bit more than a day, we need to resync the timestamps, meaning the RTC was 5s off. This offset was observed to grow gradually over time.
Here is a code snippet, of how we use the RTC to get the time and handle RTC Overflow. Maybe something here is wrong as well, but I fail to see it.
/** time stamp structure */ typedef struct { u32 u32SysTime; // [1 seconds - starting from 31.12.1999 00:00:00] u8 u8SysTime; // [1/256 seconds] } TRtc_Stamp; static const struct device* psRtc_Dev = DEVICE_DT_GET(DT_NODELABEL(rtc0)); static TRtc_Stamp sRtc_StoredStamp __attribute__((section(".noinit"))); static uint32_t u32Rtc_TicksLastRead; static u32 u32Rtc_Flags; /* This function is called at least once a minute, to ensure RTC cannot overflow twice. */ void Rtc_Read(TRtc_Stamp* psStamp) { uint32_t u32CurrTicks = 0; u32 u32DeltaTicks; u32 u32OverflowTicks; counter_get_value(psRtc_Dev, &u32CurrTicks); /* handle counter overflow */ if(u32CurrTicks >= u32Rtc_TicksLastRead) u32OverflowTicks = 0; else u32OverflowTicks = counter_get_top_value(psRtc_Dev) + 1; u32DeltaTicks = u32CurrTicks + u32OverflowTicks - u32Rtc_TicksLastRead; sRtc_StoredStamp.u32SysTime += u32DeltaTicks / counter_get_frequency(psRtc_Dev); /* handle 1/256s overflow */ u32DeltaTicks = u32DeltaTicks & 0xFF; if(u32DeltaTicks + sRtc_StoredStamp.u8SysTime > 0xFF) sRtc_StoredStamp.u32SysTime++; sRtc_StoredStamp.u8SysTime += u32DeltaTicks; if(psStamp) { psStamp->u32SysTime = sRtc_StoredStamp.u32SysTime; psStamp->u8SysTime = sRtc_StoredStamp.u8SysTime; } u32Rtc_TicksLastRead = u32CurrTicks; } /* @param psInit initial timestamp, for example from external RTC */ void Rtc_Init(TRtc_Stamp* psInit) { /* Prescaler should be set in device tree to ensure 256Hz */ counter_start(psRtc_Dev); counter_get_value(psRtc_Dev, &u32Rtc_TicksLastRead); if(psInit) { sRtc_StoredStamp.u32SysTime = psInit->u32SysTime; sRtc_StoredStamp.u8SysTime = psInit->u8SysTime; } else if(!Rtc_IsStoredStampValid()) { sRtc_StoredStamp.u32SysTime = 0; sRtc_StoredStamp.u8SysTime = 0; } u32Rtc_Flags |= RTC_FLAG_INIT_DONE; }
Are there maybe additional configs that need to be set to get the RTC to drift less? I have looked in the debugger and the registers say, that LFXO is active instead of LFRCO.
Thank you in advance!