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

Replacing nrf_delay_ms with app_timer doesn't work

Hi I managed to successfully implement a busy-wait using nrf_delay_ms(). However, I read that nrf_delay_ms() uses more power than app_timer's RTC. So I am trying to use app_timer to do a busy_wait for 10 seconds before calling the rest of the code after peer_manager_init() is called in main(). 

My busy_wait code works by checking whether m_custom_value is >= 10 before calling services_init() and the other functions.

The issue with my busy-wait code is services_init() and the other functions are never called (so no BLE advertising on the NRF). I have also tried using a while loop instead of the if conditional, but that did not work either. m_custom_value is incremented every second by a repeated app_timer which is initialized and starts before the busy-wait code. 

Is this an issue with app_timer when main is called or am I just not creating the busy-wait correctly? Thanks!

int main(void)
{
    bool erase_bonds;

    // Initialize.
    log_init();
    timers_init();
    
    application_timers_start();
    
    buttons_leds_init(&erase_bonds);
    power_management_init();
    ble_stack_init();
    gap_params_init();
    gatt_init();
    peer_manager_init();
    
    //nrf_delay_ms(10000);
    
    if (m_custom_value >= 10){
        services_init();
        advertising_init();
        conn_params_init();

        NRF_LOG_INFO("Template example started.");
        advertising_start(erase_bonds);
     }

    /*
    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }*/
    
    
}

main.c.zip

Parents
  • Hi.

    I'm not quite sure what you're trying to do here:

    If you want to create a 10 second delay you should use the single shot mode for the app timer.

    You can see how it's implemented in this tutorial.

    Just scroll down to "Create a single shot timer".

    If you create a while loop that sleeps while waiting for 10 seconds to pass, and then exit the while loop it will be very power friendly. Perhaps something like this could be an idea:

    #define NOTIFICATION_INTERVAL           APP_TIMER_TICKS(10000)  // 10 seconds interval
    static uint8_t wait_flag = 0;
    
    static void timers_init(void)
    {
        // Initialize timer module.
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
        // Create timers.
        err_code = app_timer_create(&m_notification_timer_id, APP_TIMER_MODE_SINGLE_SHOT, single_shot_timer_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for starting timers.
     */
    static void application_timers_start(void)
    {
           ret_code_t err_code;
           err_code = app_timer_start(m_notification_timer_id, NOTIFICATION_INTERVAL, NULL);
           APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Timeout handler for the single shot timer.
     */
    static void single_shot_timer_handler(void * p_context)
    {
        wait_flag = 1;
    }
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        bool erase_bonds;
    
        // Initialize.
        log_init();
        timers_init();
        application_timers_start();
        buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        peer_manager_init();
        
        // Sleep for 10 seconds
        while(wait_flag == 0)
        {
            idle_state_handle();
        }
        
        services_init();
        advertising_init();
        conn_params_init();
      
        NRF_LOG_INFO("Template example started.");
        advertising_start(erase_bonds);
        
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
        }
    }

    I hope this is helpful.

    Best regards,

    Andreas

  • Hi Andreas,

    Thank you for your help, the code you provided worked! But I still do not know why I cannot use the counter variable 'm_custom_value' to create a 10 second delay? If 'm_custom_value' is incremented every second by the notification_timeout_handler() called when the repeated 'm_notification_timer_id' timer expires, then 'm_custom_value' should increase to 10 after 10 seconds. 

    Shouldn't I be able to use conditional while or if statement  to only call services_init() and the other functions in main() after 'm_custom_value' > 10?  

    #define NOTIFICATION_INTERVAL           APP_TIMER_TICKS(1000)     
    
    APP_TIMER_DEF(m_notification_timer_id);
    
    static uint8_t m_custom_value = 0;
    
    static void notification_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        ret_code_t err_code;
        
        // Increment the value of m_custom_value before nortifing it.
        m_custom_value++;
    }
    
    
    static void timers_init(void)
    {
        err_code = app_timer_create(&m_notification_timer_id, APP_TIMER_MODE_REPEATED, notification_timeout_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    
    static void application_timers_start(void)
    {
           ret_code_t err_code;
           err_code = app_timer_start(m_notification_timer_id, NOTIFICATION_INTERVAL, NULL);
           APP_ERROR_CHECK(err_code);
    }
    
    int main(void)
    {
        bool erase_bonds;
    
        // Initialize.
        log_init();
        timers_init();
        application_timers_start();
        buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        peer_manager_init();
        
        //nrf_delay_ms(10000);
        if(m_custom_value >= 5){
            services_init();
            advertising_init();
            conn_params_init();
      
            NRF_LOG_INFO("Template example started.");
            advertising_start(erase_bonds);
          }
    
        
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
        }
        
    }

  • Hi.

    I think the issue is that you have to remember that your main-thread is not a loop.

    So when you run this code, log and timers are initialized, the timer starts and so on. This procedure of the code is executed rapidly and then you run into your if-statement.

    By this point, since the code so far has been executed rapidly the notification_timeout_handler() is yet to be called even once, and m_custom_value is 0. So the if-statement is not entered and you continue passed the if-statement into the for-loop.

    The key point is, you will never go back and check the if-statement.

    I'm guessing it will work if you put the if-statement in the for-loop, it will however look kind of messy. 

    Best regards,

    Andreas

Reply
  • Hi.

    I think the issue is that you have to remember that your main-thread is not a loop.

    So when you run this code, log and timers are initialized, the timer starts and so on. This procedure of the code is executed rapidly and then you run into your if-statement.

    By this point, since the code so far has been executed rapidly the notification_timeout_handler() is yet to be called even once, and m_custom_value is 0. So the if-statement is not entered and you continue passed the if-statement into the for-loop.

    The key point is, you will never go back and check the if-statement.

    I'm guessing it will work if you put the if-statement in the for-loop, it will however look kind of messy. 

    Best regards,

    Andreas

Children
No Data
Related