This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Unix time with RTC

Hi,

I have a Unix time stamp value stored on the Nordic board that comes from a GATT connection.

I am using SDK 15 s140 pca10056 NRF52840-dk.

I need to update this value once per second so that I have an accurate timestamp for my data which, I store to an SD card. I tried combining a calendar example however, this did not work with the Bluetooth initialised just crashed. Therefore, how can I go about creating something that can increment the counter by 1 each second. I am thinking of using RTC but, am struggling to set this up. 

Looking at the RTC example within the SDK it allows a LED 1. To blink rapidly. The LED 2 turns on after 3 second. Would it be possible to change LED 1 to increment the counter by one and run this once per second.

/** @brief Function configuring gpio for pin toggling.
 */
static void leds_config(void)
{
    bsp_board_init(BSP_INIT_LEDS);
}

/** @brief Function starting the internal LFCLK XTAL oscillator.
 */
static void lfclk_config(void)
{
    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_clock_lfclk_request(NULL);
}

/** @brief Function initialization and configuration of RTC driver instance.
 */
static void rtc_config(void)
{
    uint32_t err_code;

    //Initialize RTC instance
    nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
    config.prescaler = 4095;
    err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler);
    APP_ERROR_CHECK(err_code);

    //Enable tick event & interrupt
    nrf_drv_rtc_tick_enable(&rtc,true);

    //Set compare channel to trigger interrupt after COMPARE_COUNTERTIME seconds
    err_code = nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME * 8,true);
    APP_ERROR_CHECK(err_code);

    //Power on RTC instance
    nrf_drv_rtc_enable(&rtc);
}

Thanks,

  • Hi,

    I tried combining a calendar example however, this did not work with the Bluetooth initialised just crashed.

    The nrf-calendar-example uses RTC0, which is not available when you use the SoftDevice. You should be able to make it work by using a different RTC instance (I suggest 2, since 1 is used by the ap timer, and 0 is used by the SoftDevice).

    Therefore, how can I go about creating something that can increment the counter by 1 each second. I am thinking of using RTC but, am struggling to set this up. 

    That makes a lot of sense. If you are using other SDK libraries, then you probably have the app timer library active already. So the most sensible approach is to use a repeated app timer that times out ever 1 second. This used RTC1 under the hood.

    Looking at the RTC example within the SDK it allows a LED 1. To blink rapidly. The LED 2 turns on after 3 second. Would it be possible to change LED 1 to increment the counter by one and run this once per second.

    Yes. But I don't see any good reason for using an RTC directly instead of the app timer. You can refer to the app timer tutorial to see how it is used. That demonstrates how you can use a repeated app timer to blink a LED at a fixed interval.

  • Hi Einar,

    Thanks for your detailed response. I've changed the RTC instance to 2 and now it works. However, I have changed the pre-scaler and the compare counter time and multiplied by a compare_calibration value. This is because I want a good resolution on the timer itself. Can you confirm that this is setup to run once per second. I have it blinking an led and storing data. The led looks to be around once per second but if you could confirm my maths that would be good.

    nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME * COMPARE_CALIBRATION,true);

    COMPARE_COUNTERTIME = 1UL.

    COMPARE_CALIBRATION = 32768.

    and my Config.prescaler is set to 0.

    I have set it to 0 as this is the greatest resolution. I've posted my code below. Thanks.

    const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(2); /**< Declaring an instance of nrf_drv_rtc for RTC0. */
    
    //RTC code functions
    /** @brief: Function for handling the RTC0 interrupts.
     * Triggered on TICK and COMPARE0 match.
     */
    static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
    {
        if (int_type == NRF_DRV_RTC_INT_COMPARE0)
        {
            nrf_gpio_pin_toggle(COMPARE_EVENT_OUTPUT);
            nrf_drv_rtc_counter_clear(&rtc);//Will this re run?
            nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME *COMPARE_CALIBRATION,true);//Reset
            Unix_Time = Unix_Time + 1;
        }
        else if (int_type == NRF_DRV_RTC_INT_TICK)
        {
            nrf_gpio_pin_toggle(TICK_EVENT_OUTPUT);
        }
    }
    
    /** @brief Function configuring gpio for pin toggling.
     */
    static void leds_config(void)
    {
        bsp_board_init(BSP_INIT_LEDS);
    }
    
    /** @brief Function starting the internal LFCLK XTAL oscillator.
     */
    static void lfclk_config(void)
    {
        ret_code_t err_code = nrf_drv_clock_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_clock_lfclk_request(NULL);
    }
    
    /** @brief Function initialization and configuration of RTC driver instance.
     */
    static void rtc_config(void)
    {
        uint32_t err_code;
    
        //Initialize RTC instance
        nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
        config.prescaler = 0;//Counter resolution was 4095
        err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler);
        APP_ERROR_CHECK(err_code);
    
        //Enable tick event & interrupt
        nrf_drv_rtc_tick_enable(&rtc,true);
    
        //Set compare channel to trigger interrupt after COMPARE_COUNTERTIME seconds
        err_code = nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME * COMPARE_CALIBRATION,true);
        APP_ERROR_CHECK(err_code);
    
        //Power on RTC instance
        nrf_drv_rtc_enable(&rtc);
    }

  • Hi,

    This looks about right, but clearing the counter will take some clock cycles, so you will have an offset. The way this is implemented,  you will use some additional clock cycles to clear the RTC, and this may depend on compiler optimization and if there are other high priorities interrupts blocking this code. I suggest you replace the low-level RTC stuff with a repeated app timer instead to avoid making any mistakes here. We have allready ensured that the app timer is correct, so you will get the same average accuracy as the clock source.

  • What do you mean with a repeated app timer?

    Do you mean something like set a boolean inside of the RTC handler. Then another piece of code. Say the main loop perform the specified action given this boolean is enabled. Then set it to false?

  • Hi,

    Thomas said:
    What do you mean with a repeated app timer?

    I mean using the app timer library repeated timer feature. It has two timer types: repeated and single shot. If you need a tick at a regular interval, which is on average as accurate as your clock source, then a repeated timer is the best approach in my opinion. This has a very simple API, we have tested it and know it is correct, and it does not use any additional HW resources and does not conflict with any BLE examples.

    Thomas said:
    Do you mean something like set a boolean inside of the RTC handler. Then another piece of code. Say the main loop perform the specified action given this boolean is enabled. Then set it to false?

    No. I suggest you use the app timer library instead of using the RTC directly. The app timer is an SW that is based on the RTC.

Related