App timer in repeated mode always runs with the same delay

Hello,

I am starting a new ticket as per the suggestion from a previous ticket.

I have RTC configured to trigger every 1 ms and that keeps track on milliseconds since startup. I use that variable to log(using RTT) when the timer is triggered.

There is only one app timer which refreshes watchdog. The timer does various tasks. I log the ticks since startup at various points in the timer and it takes about 2 ms to complete.

Here is some source code that show rtc and app timer. using RTT logger for some debug messages. The source is based is based on the nrf ble uart example and the soft device is running and advertising. The timer is configurted to run every 1000 ms but it is always triggered at 1024 ms. This means that every 40 triggers, the tasks in timer would have run one less time which is not acceptable.

/** @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)
{    
    (void) int_type;
    
    //increment 1m tick ctr
    g_ticks_since_startup++;    
}

/**
 * @brief Handler for timer events.
 * 
 * @param p_context 
 */
static void timer_handler(void * p_context)
{
    (void) p_context;
    NRF_LOG_RAW_INFO("Timer %d\n", g_ticks_since_startup);
    
    //feed the watchdog
    nrf_drv_wdt_channel_feed(m_channel_id);    
    
    
    //do more stuff
    
    //get uart sensor data 
    sensor_poll(&m_nus);
    NRF_LOG_RAW_INFO("Timer end %d,", g_ticks_since_startup);
   
    
    //set flush logs flag
    flush_pending_logs = true;
}


/**@brief Function for initializing the timer module.
 */
static void timers_init(void)
{
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

    err_code = app_timer_create(&m_timer, APP_TIMER_MODE_REPEATED, timer_handler);
    APP_ERROR_CHECK(err_code);

    err_code = app_timer_start(m_timer, APP_TIMER_TICKS(1000), NULL);
    APP_ERROR_CHECK(err_code);
}


/**
 * @brief WDT events handler.
 */
void wdt_event_handler(void)
{
    NRF_LOG_RAW_INFO("WDT trig\r\n");
    //NOTE: The max amount of time we can spend in WDT interrupt is two cycles of 32768[Hz] clock - after that, reset occurs
}

int main(void)
{
    /* Init systick driver */
    nrf_drv_systick_init();

    
    log_init();
    
    
    timers_init();
    power_management_init();
    ble_stack_init();
    gap_params_init();
    gatt_init();
    services_init();
    advertising_init();
    conn_params_init();   

    //RTC Init
    lfclk_config();
    rtc_config();
    
    //feed the watchdog
    nrf_drv_wdt_channel_feed(m_channel_id);
      
    gpio_init();      
    
    //uart sensor init
    sensor_init();

    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
    
    //set the ble tx power
    sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_SCAN_INIT, BLE_CONN_HANDLE_INVALID, BLE_TX_POWER); 
    APP_ERROR_CHECK(err_code);
    
    // Start advertising.        
    advertising_start();

    //initalise the local adc for battery voltage monitoring   
    saadc_init();
    
    //init the temperature sensor
    g_mc_termperature = 0;
        
    // Enter main loop.
    for (;;)
    {
        // Clear the event register.
        __SEV();
        __WFE();
        // Wait for an event.
        __WFE();
        
        if(flush_pending_logs)
        {
            //flush logs
            flush_pending_logs = false;
        }

        idle_state_handle();    
    }
}

How can I figure out what is causing this and ensure the timer runs every 1000 ms.

Regards

Parents
  • Hi,

    How do you measure the 1024 ms? Are you using toggling GPIOs and measure the timing externally using a logic analyzer, or do you use the 1ms RTC counter to measure the time? The RTC runs off the 32.768 kHz LFCLK, which makes it not possible to trigger in interrupt at exactly 1 ms. If you run at maximum frequency RTC Prescaler = 0, the closest would be ~976 us (32 / 32768Hz), or ~1007 us (33 / 32768Hz). The app_timer should be able to trigger at 1000ms intervals, but note that the interrupts/event handling might be delayed by other higher priority interrupts in the system.

    • What is the output from the APP_TIMER_TICKS() macro?
    • Are you using app_timer2 in your application?
    • Which SDK version are you using?

    Best regards,
    Jørgen

  • Hello Jorgen,

    I use the rtc counter to measure the 1ms ticks.

    Yes I am using app_timer2 and the SDK version is nRF5_SDK_17.0.2.

    The APP_TIMER_TICKS(1000) outputs 16384.

    Here is the rtc_config function

    #define LF_CLK_FREQ_HZ                  32768U
    #define RTC_CTR_FREQ_HZ                 1000U
    #define COMPARE_COUNTERTIME             (1UL)  
    
    /** @brief Function initialization and configuration of RTC driver instance.
     */
    static void rtc_config(void)
    {
        uint32_t err_code;
    
        //Initialize RTC instance, every 10 ms
        nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
        config.prescaler = (uint16_t)((LF_CLK_FREQ_HZ / RTC_CTR_FREQ_HZ) - 1U); //e.g PRESCALER = round(32.768 kHz / 100 Hz) - 1 = 327
        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, 2U, (COMPARE_COUNTERTIME * RTC_CTR_FREQ_HZ), true);
        APP_ERROR_CHECK(err_code);
    
        //Power on RTC instance
        nrf_drv_rtc_enable(&rtc);
    }

    Based on your comment I am measuring the 1ms ticks incorrectly. My final aim is to ensure that the the timer runs every 1000ms and if that requires modifying the rtc counter then what changes do I need to make?

    Regards

    Ankit

Reply
  • Hello Jorgen,

    I use the rtc counter to measure the 1ms ticks.

    Yes I am using app_timer2 and the SDK version is nRF5_SDK_17.0.2.

    The APP_TIMER_TICKS(1000) outputs 16384.

    Here is the rtc_config function

    #define LF_CLK_FREQ_HZ                  32768U
    #define RTC_CTR_FREQ_HZ                 1000U
    #define COMPARE_COUNTERTIME             (1UL)  
    
    /** @brief Function initialization and configuration of RTC driver instance.
     */
    static void rtc_config(void)
    {
        uint32_t err_code;
    
        //Initialize RTC instance, every 10 ms
        nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
        config.prescaler = (uint16_t)((LF_CLK_FREQ_HZ / RTC_CTR_FREQ_HZ) - 1U); //e.g PRESCALER = round(32.768 kHz / 100 Hz) - 1 = 327
        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, 2U, (COMPARE_COUNTERTIME * RTC_CTR_FREQ_HZ), true);
        APP_ERROR_CHECK(err_code);
    
        //Power on RTC instance
        nrf_drv_rtc_enable(&rtc);
    }

    Based on your comment I am measuring the 1ms ticks incorrectly. My final aim is to ensure that the the timer runs every 1000ms and if that requires modifying the rtc counter then what changes do I need to make?

    Regards

    Ankit

Children
Related