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

nrf52840 RTC vs app_timer plus timestamping

hello Nordic

i am working with nrf52840, sdk16, over the peripheral app_ble_blinky example

my system will go to sleep mode for 10 minutes each time, i wonder if there is any advantage to use RTC directly instead of app_timer in meters of power consumption, is there less cpu interventions or over head when using RTC directly ?

also if i have some gpio interrupt during the 10 min sleep then i want to be able to read the current clock at resolution of 100ms. 

first thought was to use an app_timer that counts in 100ms intervals but that seems wasteful, i think i should seek for a way to have one timer interrupt every 10 minutes but ne able to get the current time stamp from the clock maybe.

1. is there a way to read a clock value while in sleep mode, that has some meaning, does it start from '0' every time we put the power on so we can try to calculate the delta each time ? 

2. is there a way to have an app_timer running on REPEATED mode that wakes up every 10 minutes ? does it really save something or it ticks every 32khz anyway? and is it better to do it directly with RTC ?

not so relevant but what's the difference between WFI and WFE beside the Event/Interrupt, does it refer to the type of sleep mode - system ON sleep(for WFE) vs system OFF sleep (for WFI)?

hope to read from you soon

best regards

Ziv

Parents
  • Hi,

    my system will go to sleep mode for 10 minutes each time, i wonder if there is any advantage to use RTC directly instead of app_timer in meters of power consumption, is there less cpu interventions or over head when using RTC directly ?

    App_timer has a few additional interrupts that trigger on at specific events (overflow, compare1 at half of max count), to handle internal flow. When using RTC directly, you can configure it for your exact needs, to avoid these interrupts. Depending on the configuration, these events should not have a very big impact on the average current consumption.

    1. is there a way to read a clock value while in sleep mode, that has some meaning, does it start from '0' every time we put the power on so we can try to calculate the delta each time ? 

    Not sure exactly how you intend to read the clock value while you are in sleep mode, but if you mean before and after sleep, you can use the app_timer_cnt_get() and app_timer_cnt_diff_compute() functions. These functions will simply get the count register from the RTC and compute the difference between them, but if you configure APP_TIMER_CONFIG_RTC_FREQUENCY to allow the RTC to not overflow more than once during the longest expected sleep cycle, this should work. If you want to translate this to actual time in your application, you need to store the counts, or use a similar approach to the nRF5 Calendar Example.

    2. is there a way to have an app_timer running on REPEATED mode that wakes up every 10 minutes ? does it really save something or it ticks every 32khz anyway? and is it better to do it directly with RTC ?

    App_timer uses compare events to wakeup when the next timer expires, it does not wake every 32 kHz to "tick". The frequency is also configurable, allowing for longer timers, as described above.

    not so relevant but what's the difference between WFI and WFE beside the Event/Interrupt, does it refer to the type of sleep mode - system ON sleep(for WFE) vs system OFF sleep (for WFI)?

    Both uses System On idle mode. The chip can only wake from System OFF from a limited set of peripheral signals (see System OFF mode), and wakeup will cause a chip reset. See this post for more details on WFE/WFI.

    Best regards,
    Jørgen

  • ziv123 said:
    1. if i use the APP_TIMER_CONFIG_RTC_FREQUENCY, to change pre scaling if i understand correct, would it affect other app_timer instances that i have in my program ? 

    Yes, this will change the PRESCALER configuration of the RTC used by app_timer, and will affect all created timers.

    ziv123 said:

    2. the APP_TIMER_CONFIG_RTC_FREQUENCY to 1024 (minimum) but, with RTC, if i get this right,

    in the "sdk_config.h": "NRFX_RTC_DEFAULT_CONFIG_FREQUENCY - Frequency  <16-32768> "

    i can get down to 16 tick per second, am i right ?

    Theoretically, you should be able to set the config lower for app_timer as well, but it may affect other uses of app_timer, and may not be testet properly. I just tested by setting it to 4095 in the ble_app_hrs application, and the only issue I saw so far was that the default detection delay for buttons used by the BSP library is too low. After increasing this 100 times, the ble_app_hrs runs as normal.

    ziv123 said:
    3. if i want to use the RTC directly, is there an example in the sdk for using the RTC directly, and if i have softdevice, timer (HFCLK), SPI(at 8MHz), TWI (not sure if the serials clock matter) and one instance of app_timer in my program, can i use only the RTC2 for this 10min sleep ?

     See the Real Time Counter Example. Softdevice uses RTC0 and app_timer uses RTC1 by default, so RTC2 should be fine to use for this purpose.

  • hi Jorgen

    i looked at the rtc example, stange thing though

    when running the rtc example (SDK 16) for nrf542840, when changing the 

     config.prescaler = 32767; //15; //8191; // 32767; //4095;

    from 4095 to 32767, i was expecting that blinking will slow down to 1 sec blink but it seems the blinking stays the same.. how come ? 

    another strange thing for me is that the compare event happens only once at start, is it not supposed to happen every 3 sec and not only after the first 3 sec, is there no zeroing of the counter after each compare event ? 

    one more thing which is critical for me is that i get the event handler to be called on each tick event, i don't want this in my program, i want the event to be called only when compare event has accurse, can you explain what changes i need to make to get that ? 

    hope to read you soon 

    p.s. in my code 

    static void timers_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        sd_clock_hfclk_request();  // this is for the audio sempling rate
    
        err_code = nrf_drv_clock_init();
        APP_ERROR_CHECK(err_code);
        nrf_drv_clock_lfclk_request(NULL);
    
        //Initialize RTC instance
        nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
        config.prescaler = 32767; //8191; // 32767; // 4095; // with 32768 it should tick every one second
        err_code = nrf_drv_rtc_init(&rtc_10_min, &config, rtc_10_min_handler);
        APP_ERROR_CHECK(err_code);
    
        //Enable tick event & interrupt
        nrf_drv_rtc_tick_enable(&rtc_10_min,true);
    
        //Set compare channel to trigger interrupt after COMPARE_COUNTERTIME seconds
        err_code = nrf_drv_rtc_cc_set(&rtc_10_min,0,COMPARE_COUNTER_10_MIN, true);
        APP_ERROR_CHECK(err_code);
    
        //Power on RTC instance
        nrf_drv_rtc_enable(&rtc_10_min);
    
        // app_timer used by other modules
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }

    where this is the handler:

    volatile uint32_t count = 0;
    
    static void rtc_10_min_handler(nrf_drv_rtc_int_type_t int_type)
    {
        if (int_type == NRF_DRV_RTC_INT_COMPARE0)
        {
            main_state = MAIN_STATE_EVERY_10_MIN_SAMPELING;
            physic_sample_done_flag = false;
            accelo_sample_done_flag = false;     
    //nrf_gpio_pin_toggle(COMPARE_EVENT_OUTPUT);
        }
        count++;
    //    else if (int_type == NRF_DRV_RTC_INT_TICK)
    //    {
    //    calculaTE delta    
    //nrf_gpio_pin_toggle(TICK_EVENT_OUTPUT);
    //    }
    }

    and this is the instance:

    const nrf_drv_rtc_t rtc_10_min = NRF_DRV_RTC_INSTANCE(2);

    it seems that if i put the count variable in the handler in a watch i see that every 1 second (which is the set refresh time in SEGGER debugging) it adds 8 to its value, even if the pre scaling is 32676, or 8191 it still the same .. why does the pre scaling does not change the tick count ?

    BEST REGARDS

    Ziv

  • Hi,

    ziv123 said:

    when running the rtc example (SDK 16) for nrf542840, when changing the 

    config.prescaler = 32767; //15; //8191; // 32767; //4095;
     config.prescaler = 32767; //15; //8191; // 32767; //4095;

    from 4095 to 32767, i was expecting that blinking will slow down to 1 sec blink but it seems the blinking stays the same.. how come ? 

     The PRESCALER register is only 12 bits, which means that 4095 is the highest value you can set.

    ziv123 said:
    another strange thing for me is that the compare event happens only once at start, is it not supposed to happen every 3 sec and not only after the first 3 sec, is there no zeroing of the counter after each compare event ? 

    The interrupt handler in the RTC driver disables the event and the interrupt for the COMPAREx event when the event is detected. You either need to comment out these two lines in the driver, or call nrf_drv_rtc_cc_set()? again in the event handler.

    ziv123 said:
    one more thing which is critical for me is that i get the event handler to be called on each tick event, i don't want this in my program, i want the event to be called only when compare event has accurse, can you explain what changes i need to make to get that ? 

    Comment out the enabling of tick event and interrupt in timers_init():

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

    Best regards,
    Jørgen

  • The interrupt handler in the RTC driver disables the event and the interrupt for the COMPAREx event when the event is detected. You either need to comment out these two lines in the driver, or call nrf_drv_rtc_cc_set()? again in the event handler.

    well i did not want to change the nrfx_rtc.c but calling the nrf_rtc_cc_set does not seem to generate another compare event, so maybe i m using it in the wrong place ?

    static void rtc_10_min_handler(nrf_drv_rtc_int_type_t int_type)
    {
        if (int_type == NRF_DRV_RTC_INT_COMPARE0)
        {
            main_state = MAIN_STATE_EVERY_10_MIN_SAMPELING;
            physic_sample_done_flag = false;
            accelo_sample_done_flag = false;   
            
            nrf_drv_rtc_cc_set(&rtc_10_min,0,COMPARE_COUNTER_10_MIN, true);
            
    //nrf_gpio_pin_toggle(COMPARE_EVENT_OUTPUT);
        }
    
        count++;
    //    else if (int_type == NRF_DRV_RTC_INT_TICK)
    //    {
    //    calculaTE delta    
    //nrf_gpio_pin_toggle(TICK_EVENT_OUTPUT);
    //    }
    }
    

    [this was edited to the response later] actually what i did that made it work is to clear the counter, i guessed that if the counter keeps on running after compare event then the value for compare event which is fixed will never meat the counter again , if there is something wrong with that logic please elaborate

    The PRESCALER register is only 12 bits, which means that 4095 is the highest value you can set.

    is there a way to change the RTC2 frequency (below code in the sdk_config.h) without changing it also for the RTC0 and RTC1 ?

    // <e> RTC_ENABLED - nrf_drv_rtc - RTC peripheral driver - legacy layer
    //==========================================================
    #ifndef RTC_ENABLED
    #define RTC_ENABLED 1
    #endif
    // <o> RTC_DEFAULT_CONFIG_FREQUENCY - Frequency  <16-32768> 
    
    
    #ifndef RTC_DEFAULT_CONFIG_FREQUENCY
    #define RTC_DEFAULT_CONFIG_FREQUENCY 32768
    #endif
    

    best regards

    Ziv

  • ziv123 said:
    [this was edited to the response later] actually what i did that made it work is to clear the counter, i guessed that if the counter keeps on running after compare event then the value for compare event which is fixed will never meat the counter again , if there is something wrong with that logic please elaborate

    Yes, that is correct. You need to clear the RTC if you want to restart it from 0. You would still hit the COMPARE event again if you let the RTC run, but this would first happen after it overflows and hit the CC point again.

    ziv123 said:
    is there a way to change the RTC2 frequency (below code in the sdk_config.h) without changing it also for the RTC0 and RTC1 ?

    RTC_DEFAULT_CONFIG_FREQUENCY is only used to set the prescaler in the default config. Since you set the prescaler in your code, there is no need to care about this config. Also, note that this config only affects RTC instances controlled by the RTC driver. Neither the softdevice, nor the app_timer library uses the RTC driver for interacting with the RTC peripheral.

Reply
  • ziv123 said:
    [this was edited to the response later] actually what i did that made it work is to clear the counter, i guessed that if the counter keeps on running after compare event then the value for compare event which is fixed will never meat the counter again , if there is something wrong with that logic please elaborate

    Yes, that is correct. You need to clear the RTC if you want to restart it from 0. You would still hit the COMPARE event again if you let the RTC run, but this would first happen after it overflows and hit the CC point again.

    ziv123 said:
    is there a way to change the RTC2 frequency (below code in the sdk_config.h) without changing it also for the RTC0 and RTC1 ?

    RTC_DEFAULT_CONFIG_FREQUENCY is only used to set the prescaler in the default config. Since you set the prescaler in your code, there is no need to care about this config. Also, note that this config only affects RTC instances controlled by the RTC driver. Neither the softdevice, nor the app_timer library uses the RTC driver for interacting with the RTC peripheral.

Children
  • RTC_DEFAULT_CONFIG_FREQUENCY is only used to set the prescaler in the default config. Since you set the prescaler in your code, there is no need to care about this config. Also, note that this config only affects RTC instances controlled by the RTC driver. Neither the softdevice, nor the app_timer library uses the RTC driver for interacting with the RTC peripheral.

    in the sdk_config comments it is written - Frequency  <16-32768> , so is it possible to set the frequency here for something like 8191 (more then 12 bits) ? and then to set prescaler to zero ?

  • No, like you see in my link, RTC_DEFAULT_CONFIG_FREQUENCY is passed to RTC_FREQ_TO_PRESCALER, which will calculate the prescaler for the given frequency. If you set the frequency to 8191 in your sdk_config.h file, the calculated prescaler will be (32768/8191)-1=3. 

    And again, since you set the prescaler in the code, this will be overwritten and have no effect:

    nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
    config.prescaler = 32767; //8191; // 32767; // 4095; // with 32768 it should tick every one second

Related