RTC drift ?

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!

  • Hi,

    Can you check if the drift is more/less when using the LFRC as the clock source?

    On my end, I found a contact point for the RTC in the nRF91 and have just now sent an internal ticket to them.

    Do you have a SiP version for referencing?

  • Hi MaLu,

    I got feedback from our engineers a few days ago but was too occupied and could only relay the information today. My apologies.

    The tolerance listed for LFXO in the nRF9160 Product Specification is only the tolerance of the crystal component. Meanwhile, the tolerance of LFXO is also dependent on the tolerance of the capacitors in the crystal oscillator circuit.

    Considering that, the drift that you observed is not impossible. We have made a note to make improvement regarding this part of the Product Specification.

    Regarding real time tracking, the amount of RTC drift that each device has is going to be stable given the same environment conditions. Therefore, we suggest perhaps you could have the algorithm adapt to the drift. For example, instead of hard-coded one second to advance after 32768 RTC ticks, you could calculate a more accurate number of ticks and update the algorithm to use that instead.

    However, if the strategy you currently use is good enough for you, then that is also totally fine.

    My apology for the long wait and the inconveniences.

    Hieu

Related