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

Programming DK board button to go to system on low power mode and then wake & advertise on consecutive button presses

Hi I am trying to program the bsp buttons on the NRF52 DK, so pushing button 1 will toggle start advertising and going to sleep by calling sd_app_evt_wait().

I have successfully got the button to go to sleep when pressed, but in my current code below after it goes to sleep it cannot be woken up if I press button 1 again or any other button on the DK. I use an integer variable 'bsp_adv_bool' to keep track of whether the NRF should go to sleep or wake up & advertise when button 1 is pressed. Should I be using another method to wake up button 1 and then set it call sd_app_evt_wait() on the next press?

static uint8_t bsp_adv_bool = 0;

static void sleep_mode_enter(void)
{
    ret_code_t err_code;

    err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    APP_ERROR_CHECK(err_code);

    // Prepare wakeup buttons.
    err_code = bsp_btn_ble_sleep_mode_prepare();
    APP_ERROR_CHECK(err_code);

    err_code = sd_app_evt_wait();
    APP_ERROR_CHECK(err_code);
   
}

static void bsp_event_handler(bsp_event_t event)
{
    ret_code_t err_code;

    switch (event)
    {
        case BSP_EVENT_SLEEP:
                if(bsp_adv_bool == 0) 
                {
                  bsp_adv_bool = 1; 
                  sleep_mode_enter();
                }
                else if (bsp_adv_bool == 1)
                {
                   bsp_adv_bool = 0;
                   bool erase_bonds;
                   advertising_start(erase_bonds);
                }
            
            break; // BSP_EVENT_SLEEP

        case BSP_EVENT_DISCONNECT:
            err_code = sd_ble_gap_disconnect(m_conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            if (err_code != NRF_ERROR_INVALID_STATE)
            {
                APP_ERROR_CHECK(err_code);
            }
            break; // BSP_EVENT_DISCONNECT

        case BSP_EVENT_WHITELIST_OFF:
            if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
            {
                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
            }
            break; // BSP_EVENT_KEY_0

        default:
            break;
    }
}

static void buttons_leds_init(bool * p_erase_bonds)
{
    ret_code_t err_code;
    bsp_event_t startup_event;

    err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
    APP_ERROR_CHECK(err_code);

    err_code = bsp_btn_ble_init(NULL, &startup_event);
    APP_ERROR_CHECK(err_code);

    *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
}

static void idle_state_handle(void)
{
    if (NRF_LOG_PROCESS() == false)
    {
        sd_app_evt_wait();
    }
}

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();
    
    services_init();
    advertising_init();
    conn_params_init();
  
    NRF_LOG_INFO("Template example started.");
    advertising_start(erase_bonds);
    
    // Enter main loop.
  for (;;)
    {
        idle_state_handle();
    } 
    
}

In slightly different code below I attempt to program the DK to only start advertising when button 1 is pressed, but the code still relies on logic structure similar to the code above. So the code below doesn't work either until the above code is fixed. But should calling advertising_start() only in bsp_event_handler() work or is there issues with doing this? 

static uint8_t bsp_adv_bool = 1;

static void sleep_mode_enter(void)
{
    ret_code_t err_code;

    err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    APP_ERROR_CHECK(err_code);

    // Prepare wakeup buttons.
    err_code = bsp_btn_ble_sleep_mode_prepare();
    APP_ERROR_CHECK(err_code);

    err_code = sd_app_evt_wait();
    APP_ERROR_CHECK(err_code);
   
}

static void bsp_event_handler(bsp_event_t event)
{
    ret_code_t err_code;

    switch (event)
    {
        case BSP_EVENT_SLEEP:
                if(bsp_adv_bool == 0) 
                {
                  bsp_adv_bool = 1; 
                  sleep_mode_enter();
                }
                else if (bsp_adv_bool == 1)
                {
                   bsp_adv_bool = 0;
                   bool erase_bonds;
                   
                   NRF_LOG_INFO("Template example started.");
                   advertising_start(erase_bonds);
                }
            
            break; // BSP_EVENT_SLEEP

        case BSP_EVENT_DISCONNECT:
            err_code = sd_ble_gap_disconnect(m_conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            if (err_code != NRF_ERROR_INVALID_STATE)
            {
                APP_ERROR_CHECK(err_code);
            }
            break; // BSP_EVENT_DISCONNECT

        case BSP_EVENT_WHITELIST_OFF:
            if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
            {
                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
            }
            break; // BSP_EVENT_KEY_0

        default:
            break;
    }
}



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();
    services_init();
    conn_params_init();
    advertising_init();
    
    // Enter main loop.
  for (;;)
    {
        idle_state_handle();
    } 
    
}

Parents
  • Is there a reason why you're not only using the initial solution? With idle_state_handle() inside the for loop.
    Could you try to comment out err_code = bsp_btn_ble_sleep_mode_prepare(); in sleep_mode_enter()  and see if the problem still persist?

    Best regards,

    Simon

  • Hi, for my application the NRF should not power off as I need the RTC to be active, so the RTC should stay on until the NRF runs out of battery. My application also requires that BLE advertising only start when the user presses a button. 

    I commented out bsp_btn_ble_sleep_mode_prepare() and the problem still persisted. I made some more modifications and it turns out that if I press the button twice while BLE advertising is still active from the first advertising_start() call in main() then there is another call to advertising_start(). It seems like one or more calls to advertising_start() while BLE advertising is already on will generate errors. I will investigate some more. 

Reply
  • Hi, for my application the NRF should not power off as I need the RTC to be active, so the RTC should stay on until the NRF runs out of battery. My application also requires that BLE advertising only start when the user presses a button. 

    I commented out bsp_btn_ble_sleep_mode_prepare() and the problem still persisted. I made some more modifications and it turns out that if I press the button twice while BLE advertising is still active from the first advertising_start() call in main() then there is another call to advertising_start(). It seems like one or more calls to advertising_start() while BLE advertising is already on will generate errors. I will investigate some more. 

Children
  • The function sd_app_evt_wait() will not block the RTC. I think you are mixing system OFF mode and system ON mode.

    • System OFF mode will put the device into the deepest power saving and disable all peripherals (including RTC)
    • System ON mode will put the system in a lighter sleep mode where all the peripherals can be used (including RTC). To put the device into system ON, you call sd_app_evt_wait().

    Read this Devzone ticket for more information about this.

    I would recommend you to remove the call to sd_app_evt_wait() in the bsp_event_handler(). In your code, the chip is already set up to go to sleep. It is done through idle_state_handle()-->nrf_pwr_mgmt_run()-->sd_app_evt_wait(). The program flow works in this manner:

    The call to advertising_start() can still remain in bsp_event_handler(), but you should create a boolean variable that checks if advertising is ongoing or not. Set variable to true when advertising is started, and set it to false when advertising is stopped.

    Best regards,

    Simon

Related