k_uptime_get() drift way too much using LFXO.

Hi

This project is using nRF52840 and NCS 2.5.2, using LFXO as LFCLK source.

I added a code snippet which will be called once a button is pressed

#include <zephyr/drivers/clock_control.h>
void check_clock_calibration(void)
{
    static uint8_t first_enter = 1;
    if (first_enter) {
        first_enter = 0;
        if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION)) {
            LOG_ERR("LFRC calibration is enabled.");
        } else {
            LOG_ERR("LFRC calibration is disabled.");
        }
    }

    uint32_t lfclk_src = NRF_CLOCK->LFCLKSTAT & CLOCK_LFCLKSTAT_SRC_Msk;
    if (lfclk_src == CLOCK_LFCLKSTAT_SRC_RC) {
        LOG_ERR("LFCLK is using LFRC.");
    } else if (lfclk_src == CLOCK_LFCLKSTAT_SRC_Xtal) {
        LOG_ERR("LFCLK is using external XTAL (LFXO).");
    } else if (lfclk_src == CLOCK_LFCLKSTAT_SRC_Synth) {
        LOG_ERR("LFCLK is using synthesized clock.");
    } else {
        LOG_ERR("LFCLK source is unknown or not set.");
    }

    LOG_ERR("NRF_CLOCK->LFCLKSTAT %d ", NRF_CLOCK->LFCLKSTAT);
    int64_t timestamp_ms = (int64_t)k_uptime_get();
    LOG_ERR("%s timestamp_ms %llu", __func__, timestamp_ms);
}

You can see that the delta between k_uptime_get() and RTT Viewer's timestamp increase to 738 ms within 30 seconds.

I double check the RTT Viewer's timestamp using a stop watch and it seems pretty accurate.

I continue this test for over 1 hour and the delta increase to over 90 seconds. Which is way too much.

00> [00:00:09.706,237] <err> sleekapp: LFRC calibration is disabled.
00> [00:00:09.706,268] <err> sleekapp: LFCLK is using external XTAL (LFXO).
00> [00:00:09.706,298] <err> sleekapp: NRF_CLOCK->LFCLKSTAT 65537 
00> [00:00:09.706,329] <err> sleekapp: check_clock_calibration timestamp_ms 9939 //delta:233
00> [00:00:11.357,482] <err> pal_run_loop: HAPPlatformRunLoopRun
00> [00:00:17.055,908] <err> sleekapp: LFCLK is using external XTAL (LFXO).
00> [00:00:17.055,938] <err> sleekapp: NRF_CLOCK->LFCLKSTAT 65537 
00> [00:00:17.055,969] <err> sleekapp: check_clock_calibration timestamp_ms 17465 //delta:409
00> [00:00:20.708,190] <err> sleekapp: LFCLK is using external XTAL (LFXO).
00> [00:00:20.708,221] <err> sleekapp: NRF_CLOCK->LFCLKSTAT 65537 
00> [00:00:20.708,251] <err> sleekapp: check_clock_calibration timestamp_ms 21205 //delta:497
00> [00:00:23.088,928] <err> pal_run_loop: HAPPlatformRunLoopRun
00> [00:00:23.586,120] <err> sleekapp: LFCLK is using external XTAL (LFXO).
00> [00:00:23.586,151] <err> sleekapp: NRF_CLOCK->LFCLKSTAT 65537 
00> [00:00:23.586,181] <err> sleekapp: check_clock_calibration timestamp_ms 24152 //delta:566
00> [00:00:25.461,120] <err> sleekapp: LFCLK is using external XTAL (LFXO).
00> [00:00:25.461,151] <err> sleekapp: NRF_CLOCK->LFCLKSTAT 65537 
00> [00:00:25.461,181] <err> sleekapp: check_clock_calibration timestamp_ms 26072 //delta:611
00> [00:00:27.160,339] <err> sleekapp: LFCLK is using external XTAL (LFXO).
00> [00:00:27.160,369] <err> sleekapp: NRF_CLOCK->LFCLKSTAT 65537 
00> [00:00:27.160,400] <err> sleekapp: check_clock_calibration timestamp_ms 27812 //delta:652
00> [00:00:30.735,534] <err> sleekapp: LFCLK is using external XTAL (LFXO).
00> [00:00:30.735,565] <err> sleekapp: NRF_CLOCK->LFCLKSTAT 65537 
00> [00:00:30.735,595] <err> sleekapp: check_clock_calibration timestamp_ms 31473 //delta:738

I use the same test scenario to add the same print on another project (different hardware, nRF52840 IC, different firmware using NCS 2.3.0).

The delta between k_uptime_get() and RTT Viewer's timestamp is less than 1 second after 1 hour test.

Could you kindly help me locate this issue to see is it hardware related?

Regards,

Anthony Yuan

Parents
  • Hi,

     

    Now you are introducing uncertainty in the RTT process itself, so this is not a very reliable way of checking the accuracy.

    What I would recommend is to check the timestamp against a known stable high speed timer on the nRF itself, as this is sourced from the HFCLK.

    What is important then is to first start the HFXO, either via clock_control API, or by just running this:

    NRF_CLOCK->TASKS_HFCLKSTART=1;
    while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;

     

    Kind regards,

    Håkon 

  • Hi Håkon,

    Just tested with CONFIG_SYS_CLOCK_TICKS_PER_SEC=1024 in .conf file

    And now the k_uptime_get() matching with RTT log and matching with my stop watch.

    I am not quite familiar with zephyr/kernel, I have 2 questions about CONFIG_SYS_CLOCK_TICKS_PER_SEC:

    1. I can't find out why NCS 2.3.0 and NCS 2.5.2 use the same CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 but have different result.

    2. I change CONFIG_SYS_CLOCK_TICKS_PER_SEC=2048 and the k_uptime_get() works properly too, as my understanding that it will make zephyr kernel more accurate if I set CONFIG_SYS_CLOCK_TICKS_PER_SEC=32768, but is there any side effects?

    Regards,

    Anthony Yuan

  • Hi,

     

    You are changing the prescaler for the NRF_RTC instance that is used by the kernel for timekeeping by changing that specific kconfig.

    Could you try to run the sample in zephyr/samples/boards/nordic/clock_skew ?

     

    Then add the 32k RC config:

    CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
     
    And add this to the startup sequence to use HFXO:

    https://github.com/nrfconnect/sdk-nrf/blob/v2.8.0/samples/cellular/at_client/src/main.c#L18-L23


     
    My output running on RC32k:

    Ty  Latest           Base             Span             Err
    HF  00:03:40.572049  00:00:00.017209  00:03:40.554840
    LF  00:03:40.577789  00:00:00.033599  00:03:40.544189 -00:00:00.010651
    RHF 00:03:40.572019                                   -00:00:00.000030
    Skew 1.000048 ; err -48279 ppb
    
    Ty  Latest           Base             Span             Err
    HF  00:03:50.597951  00:00:00.017209  00:03:50.580741
    LF  00:03:50.603271  00:00:00.033599  00:03:50.569671 -00:00:00.011070
    RHF 00:03:50.597928                                   -00:00:00.000022
    Skew 1.000048 ; err -48041 ppb
    
    Ty  Latest           Base             Span             Err
    HF  00:04:00.623685  00:00:00.017209  00:04:00.606475
    LF  00:04:00.628753  00:00:00.033599  00:04:00.595153 -00:00:00.011322
    RHF 00:04:00.623685                                    00:00:00.000000
    Skew 1.000047 ; err -47087 ppb

     

    < 50 ppm drift.

     

    Changing to LFXO gives <2 ppm initial drift:

    Ty  Latest           Base             Span             Err
    HF  00:00:10.026283  00:00:00.017210  00:00:10.009073
    LF  00:00:10.523406  00:00:00.514312  00:00:10.009094  00:00:00.000021
    RHF 00:00:10.026273                                   -00:00:00.000009
    Skew 0.999998 ; err 2086 ppb

      

    Kind regards,

    Håkon

  • Hi Håkon,

    Thanks for the update.

    1. I use clock_skew to test RC32k Skew and it < 50 ppm

    2. I put sometime read the zephyr kernel code and figure it out what cause my issue:

    My project in NCS 2.3.0, no time drift

    //generated autoconf.h
    #define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 32768
    #define CONFIG_SYS_CLOCK_TICKS_PER_SEC 32768

    My project in NCS 2.5.2, have time drift

    //generated autoconf.h
    #define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 32768
    #define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000

    cycles per tick = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC = 32768 / 1000 = 32.768 cycles

    Since the hardware cannot generate fractional cycles, this value is typically rounded up or down to the nearest integer, such as 32 cycles or 33 cycles. And Tick period of kernel is 1 ms.

    There may be cumulative timing errors due to rounding, as 32.768 is not an exact match for the hardware clock cycles.

    After change the CONFIG_SYS_CLOCK_TICKS_PER_SEC to 1024, Tick period change to 0.97656ms and cycles per tick is 32 and there is no need to rounding, and that eliminate the time drift.

    Regards,

    Anthony Yuan

Reply
  • Hi Håkon,

    Thanks for the update.

    1. I use clock_skew to test RC32k Skew and it < 50 ppm

    2. I put sometime read the zephyr kernel code and figure it out what cause my issue:

    My project in NCS 2.3.0, no time drift

    //generated autoconf.h
    #define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 32768
    #define CONFIG_SYS_CLOCK_TICKS_PER_SEC 32768

    My project in NCS 2.5.2, have time drift

    //generated autoconf.h
    #define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 32768
    #define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000

    cycles per tick = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC = 32768 / 1000 = 32.768 cycles

    Since the hardware cannot generate fractional cycles, this value is typically rounded up or down to the nearest integer, such as 32 cycles or 33 cycles. And Tick period of kernel is 1 ms.

    There may be cumulative timing errors due to rounding, as 32.768 is not an exact match for the hardware clock cycles.

    After change the CONFIG_SYS_CLOCK_TICKS_PER_SEC to 1024, Tick period change to 0.97656ms and cycles per tick is 32 and there is no need to rounding, and that eliminate the time drift.

    Regards,

    Anthony Yuan

Children
No Data
Related