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

Use 1 button to exit/enter system off mode

Hi, I'm learning the nrf51-powerdown-example <system_off_wakeup_on_gpiote> from github. 

My understanding of the code is: 

1) When button 0 (Power down) button is pressed (high to low), in_pin_handler() starts

2) We firstly turn off LED, uninitialize and disable button 0 (Power down)

3) Then, enable button 1 (wakeup button).

4) lastly, Enter the system off. 

My question is: 

1) When button 1 (wakeup button) is pressed (high to low), why the event handler is NULL? How could the system wake up? Which code makes the system wake up (exist system off mode)?

2) Above example uses 2 buttons to enter/exit the system off mode. I have also tried the pin_change_int and pwr_mgmt example code in SDK. Does Nordic have any "1-button to exit/enter system off mode" example? If no, what's the idea/process to achieve it? 

Thanks!  

  • Hi,

    1. Wakeup from System OFF is a pure HW feature. The GPIO is configured to sense the state of the pin. If the pin state changes, this will generate a HW signal inside the chip to start the wakeup procedure. Note that wakeup from System OFF will always cause a chip reset, it will not continue executing code from where you put it to sleep. You can use the RESETREAS register to check if the startup was from a System OFF event or a reset.
    2. Yes, there should be no issues with using the same pin for power-down/power-up. Once you have entered the in_pin_handler to power down, you can reconfigure the same pin as wakeup source from System OFF before entering this state.

    Best regards,
    Jørgen

  • Thanks for your reply, Jorgen. I modified the code. I want to: 

    1) When I press the button, turn on the system. 

    2) Press the same button again, enter the system off state. 

    3) Press again, wake up from the system off state. 

    Here is my code. Because I used HITOLO for both gpio_init() and in_pin_handler(), so the system always restarts at main(). How to modify the code (i.e. what's the the logic), please? Does the nRF52805 have an internal debouncing hardware circuit? If no, is there any button debouncing software example code from Nordic? Thank you very much! 

    #include <stdbool.h>
    #include "nrf.h"
    #include "nrf_drv_gpiote.h"
    #include "app_error.h"
    #include "boards.h"
    
    
    
    
    #define SWITCH_PIN          BSP_BUTTON_0
    #define LED_PIN_OUT         BSP_LED_0
    
    
    /**
     * @brief Interrupt handler for wakeup pins
     */
    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        ret_code_t err_code;
        printf("in_pin_handler() entered\r\n");
        if (pin == SWITCH_PIN)
        {
            //Turn off LED to indicate the nRF5x is in System-off mode
            //NRF_LOG_INFO("Turn off LED to indicate the nRF5x is in System-off mode");
            nrf_drv_gpiote_out_set(LED_PIN_OUT);
            
            //Disable power-down button to prevent System-off wakeup
            //NRF_LOG_INFO("Disable power-down button to prevent System-off wakeup");
            nrf_drv_gpiote_in_uninit(SWITCH_PIN);           
            nrf_drv_gpiote_in_event_disable(SWITCH_PIN);
            
            //Configure wake-up button
            nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false);     //Configure to generate interrupt and wakeup on pin signal low. "false" means that gpiote will use the PORT event, which is low power, i.e. does not add any noticable current consumption (<<1uA). Setting this to "true" will make the gpiote module use GPIOTE->IN events which add ~8uA for nRF52 and ~1mA for nRF51.
            in_config.pull = NRF_GPIO_PIN_PULLUP;                                            //Configure pullup for input pin to prevent it from floting. Pin is pulled down when button is pressed on nRF5x-DK boards, see figure two in http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52/dita/nrf52/development/dev_kit_v1.1.0/hw_btns_leds.html?cp=2_0_0_1_4
            err_code = nrf_drv_gpiote_in_init(SWITCH_PIN, &in_config, NULL);             //Initialize the wake-up pin
            APP_ERROR_CHECK(err_code);                                                       //Check error code returned
            nrf_drv_gpiote_in_event_enable(SWITCH_PIN, true);                            //Enable event and interrupt for the wakeup pin
            printf("Configured switch to wake-up\r\n");
    
            //Enter System-off
            printf("Enter System-off\r\n\r\n");
            NRF_POWER->SYSTEMOFF = 1;
            
        }
    }
    
    
    
    
    /**
     * @brief Function for configuring: SWITCH_PIN (BUTTON_1) to enter System-off, 
     * SWITCH_PIN pin (BUTTON_2) to wake up from System-off, and LED_PIN_OUT pin for LED_1 output
     */
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
        //Initialize gpiote module
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
        
        //Initialize output pin, and Turn on LED 4
        nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);        	//Configure output button
        err_code = nrf_drv_gpiote_out_init(LED_PIN_OUT, &out_config);                        	//Initialize output button
        APP_ERROR_CHECK(err_code);                                                     	//Check potential error
        nrf_drv_gpiote_out_clear(LED_PIN_OUT);                                               	//Turn on LED to indicate that nRF5x is not in System-off mode
    
        //Configure sense input pin to enable wakeup and interrupt on button press.
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(false);        //Configure to generate interrupt and go to system_off on pin signal high. "false" means that gpiote will use the PORT event, which is low power, i.e. does not add any noticable current consumption (<<1uA). Setting this to "true" will make the gpiote module use GPIOTE->IN events which add ~8uA for nRF52 and ~1mA for nRF51.
        in_config.pull = NRF_GPIO_PIN_PULLUP;                                             	//Configure pullup for input pin to prevent it from floting. Pin is pulled down when button is pressed on nRF5x-DK boards, see figure two in http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52/dita/nrf52/development/dev_kit_v1.1.0/hw_btns_leds.html?cp=2_0_0_1_4		
        err_code = nrf_drv_gpiote_in_init(SWITCH_PIN, &in_config, in_pin_handler);   //Initialize the pin with interrupt handler in_pin_handler
        APP_ERROR_CHECK(err_code);                                                          //Check potential error
        nrf_drv_gpiote_in_event_enable(SWITCH_PIN, true);
        
        printf("gpio_init() completed\r\n");
    }
    
    
    
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        printf("Enter main()\r\n");
        gpio_init();
    
        while (true)
        {
            //Enter System-on idle mode
            __WFE();
            __SEV();
            __WFE();	
        }
    }

  • Hi,

    There is no HW debounce functionality in the chip. You can use the Button handling library, which implements timers for button detection delay.

    Wakeup from system OFF will always cause a reset, and hence execution from main(). If you want to perform a different task when waking from System OFF than from Power-On-Reset, you can check the RESETREAS register to decide what to do in start of main().

    Best regards,
    Jørgen

  • Problem solved. Here is my code of "using 1 button to turn on/off the system". Happy to share/use the code if you're interested.

    You may connect your nRF52 DK with PuTTY. Press button 0 to see that the system has been turned on/off. 

    #include <stdbool.h>
    #include <stdint.h>
    #include "boards.h"
    #include "bsp.h"
    #include "bsp_nfc.h"
    #include "app_timer.h"
    #include "nordic_common.h"
    #include "app_error.h"
    #include "nrf_drv_clock.h"
    #include "nrf_pwr_mgmt.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #if NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
    #include "app_scheduler.h"
    #define APP_SCHED_MAX_EVENT_SIZE    0   /**< Maximum size of scheduler events. */
    #define APP_SCHED_QUEUE_SIZE        4   /**< Maximum number of events in the scheduler queue. */
    #endif // NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
    
    #define BTN_ID                0
    
    
    /**@brief Handler for shutdown preparation.
     */
    bool shutdown_handler(nrf_pwr_mgmt_evt_t event)
    {
    
        uint32_t err_code;
    
        switch (event)
        {
            case NRF_PWR_MGMT_EVT_PREPARE_WAKEUP:
                NRF_LOG_INFO("NRF_PWR_MGMT_EVT_PREPARE_WAKEUP");
                err_code = bsp_buttons_disable();
                // Suppress NRF_ERROR_NOT_SUPPORTED return code.
                UNUSED_VARIABLE(err_code);
    
                err_code = bsp_wakeup_button_enable(BTN_ID);
                // Suppress NRF_ERROR_NOT_SUPPORTED return code.
                UNUSED_VARIABLE(err_code);
    
                break;
        }
    
        err_code = app_timer_stop_all();
        APP_ERROR_CHECK(err_code);
    
        return true;
    }
    
    
    
    
    
    /**@brief Register application shutdown handler with priority 0. */
    NRF_PWR_MGMT_HANDLER_REGISTER(shutdown_handler, 0);
    
    
    
    
    
    
    /**@brief Function for handling BSP events.
     */
    static void bsp_evt_handler(bsp_event_t evt)
    {
    #if NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_ENABLED
        nrf_pwr_mgmt_feed();
        NRF_LOG_INFO("Power management fed");
    #endif // NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_ENABLED
    
        switch (evt)
        {
            
            case BSP_EVENT_DEFAULT:
    
                break;
    
            case BSP_EVENT_SYSOFF:
    
                    // Application will prepare the wakeup mechanism: NRF_PWR_MGMT_EVT_PREPARE_WAKEUP
                    /**@brief Function for shutting down the system.
                     * @param[in] shutdown_type     Type of operation.
                     * @details All callbacks will be executed prior to shutdown.
                     */
                    nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
                    // NRF_LOG_INFO("2) System OFF is entered\r\n");
                    // NRF_POWER->SYSTEMOFF = 1;
                
                break;
    
    
            default:
                return; // no implementation needed
        }
    }
    
    
    
    
    
    
    
    
    /**@brief Function for initializing low-frequency clock.
     */
    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 for initializing the BSP module.
     */
    static void bsp_configuration()
    {
        uint32_t err_code;
    
        err_code = bsp_init(BSP_INIT_BUTTONS, bsp_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_event_to_button_action_assign(BTN_ID,
                                                     BSP_BUTTON_ACTION_LONG_PUSH,
                                                     BSP_EVENT_DEFAULT);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_event_to_button_action_assign(BTN_ID,
                                                     BSP_BUTTON_ACTION_RELEASE,
                                                     BSP_EVENT_SYSOFF);
        APP_ERROR_CHECK(err_code);
    
    }
    
    
    
    
    
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO("Power Management example");
    
        lfclk_config();
    
        uint32_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
    #if NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
        APP_SCHED_INIT(APP_SCHED_MAX_EVENT_SIZE, APP_SCHED_QUEUE_SIZE);
    #endif // NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
        bsp_configuration();
    
        ret_code_t ret_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(ret_code);
    
        while (true)
        {
    #if NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
            app_sched_execute();
    #endif // NRF_PWR_MGMT_CONFIG_USE_SCHEDULER
    
            if (NRF_LOG_PROCESS() == false)
            {
                nrf_pwr_mgmt_run();
            }
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    

  • Hi StevenW807,

    the solution you made for system ON/OFF using single button is working fine. but I integrated this code with BLE peripheral code and started working with device. turn ON/OFF functions are working only if BLE IS not pairing with other device but if i perform device turn OFF after it is connected with BLE device it is not turning OFF. if I reset the device then only the device is working.

    kindly help me on this issue

    thank&regards

    Srinivasa m

Related