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

ble_proximity app and gpiote interrupt code to wake from and send microcontroller to system_off, not working harmoniously

Hi,

I am trying to merge working code that places the microcontroller in system_off when a switch connected to pin 16 is opened. It then wakes up the micro controller when switch is closed. The same pin is used to achieve this using GPIOTE. The challenge occurs when I merge this with the  ble_proximity app.  I can never get the chip to go to sleep when I remove the physical ground connector on PIN 16 and open the switch. However it worked perfectly when not merged with ble_proximity 

I am effectively using method two neatly described here

https://devzone.nordicsemi.com/f/nordic-q-a/19536/how-to-read-status-of-gpio-pin-12-whether-it-is-high-or-low

I have found some useful information in the discussion below.

https://devzone.nordicsemi.com/f/nordic-q-a/37328/gpio-interrupt-with-ble-peripheral-code

It reveals that the conflict in the 

buttons_leds_init(&erase_bonds);


function needs to be dealt with which I believe I have done.

So changes I have made are to file pca10040.h
//#define BUTTONS_NUMBER 4 - change to 3 
#define BUTTONS_NUMBER 3

so only the first three buttons are initialised effectively liberating pin 16

My code is as per below and there must be something incorrect with the configuration of pin 16 as the in_pin_handler is never called.

#define SWITCH_PIN   BUTTON_4
#define PIN_OUT      LED_4
/**
 * @brief Interrupt handler for wakeup pin
 */
 
void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
		ret_code_t err_code;
              NRF_LOG_INFO("ON WAKEUP SWITCH PIN state is: %d..", nrf_gpio_pin_read(pin));

		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(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_LOG_INFO("Configure switch to wake-up");
		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
			
				//Enter System-off
                NRF_LOG_INFO("Enter System-off");
		NRF_POWER->SYSTEMOFF = 1;
                      while(1){
								//This has been put in here to  prevent spurious calls whilst in debug mode
                               }
		}
}


/**
 * @brief Function for configuring: PIN_IN_POWER_DOWN pin (BUTTON_1) to enter System-off, 
 * PIN_IN_WAKE_UP pin (BUTTON_2) to wake up from System-off, and PIN_OUT pin for LED_1 output
 */

static void gpio_init(void)
{
    ret_code_t err_code;

	//Initialize gpiote module
    NRF_LOG_INFO("Initialize gpiote module");
    if(!nrf_drv_gpiote_is_init())
        {
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
        }
    NRF_LOG_INFO("Error is: %d..", err_code);
    
	//Initialize output pin
    NRF_LOG_INFO("Turn on LED 4");
    nrf_drv_gpiote_out_clear(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 buckle closure 1-> 0 as high to ground
    nrf_drv_gpiote_in_uninit(SWITCH_PIN);           
    nrf_drv_gpiote_in_event_disable(SWITCH_PIN);  
    NRF_LOG_INFO("Configure sense input pin to commence shutdown procedure  on opening of the switch");
    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(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 floating. 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
    NRF_LOG_INFO("Error is: %d..", err_code);
    APP_ERROR_CHECK(err_code);                                                          			//Check potential error
    nrf_drv_gpiote_in_event_enable(SWITCH_PIN, true);                            				//Enable event and interrupt for the wakeup pin
    NRF_LOG_INFO("Got to here");
    NRF_LOG_INFO("SWITCH PIN state is: %d..", nrf_gpio_pin_read(SWITCH_PIN));
}


/**@brief Function for application main entry.
 */
int main(void)
{
    bool erase_bonds;
    // Initialize.
    log_init();
    timers_init();
    buttons_leds_init(&erase_bonds);
    power_management_init();
    ble_stack_init();
    adc_configure();
    gap_params_init();
    gatt_init();
    advertising_init();
    db_discovery_init();
    services_init();
    conn_params_init();
    peer_manager_init();

    // Start execution.
    NRF_LOG_INFO("Proximity example started.");
    advertising_start(erase_bonds);
    tx_power_set();
    gpio_init();

    // Enter main loop.
    for (;;)
    {
       // idle_state_handle();
        NRF_LOG_INFO("Got to here in main loop");
        NRF_LOG_INFO("SWITCH PIN state is: %d..", nrf_gpio_pin_read(SWITCH_PIN));
        nrf_delay_ms(5000);

    }
}


Any help greatly appreciated as to where I am getting this wrong.

Best,
DW





  • Hi,

    It looks like this should be sufficient to prevent BSP from initializing the pin. Have you verified through debugging that in_pin_handler is in fact not called, or do the chip just not enter system off mode? Unless you disable the softdevice first, you should not access the NRF_POWER peripheral registers directly. Access to these registers are restricted by softdevice, and can only be accessed through the softdevice API. Try using sd_power_system_off() instead.

    Best regards,
    Jørgen

  • You're correct. The chip is simply not entering system off mode as LED 4 is turned on in gpio_init() and then never turns off. This makes me think that when I un-ground PIN 16 the event handler is not being fired. I have changed the code to now include sd_power_system_off() though although we are not getting to this point in the code.

    The sequence of events that I see are:

    • Flash the device with 16 physically tied to GND
    • LED 1 flashes once to indicate fast advertising (not sure why it only flashes once and stops)
    • LED 4 then turns on indicating that gpis_init() is running.
    • I then unplug ground which should allow pin 16 to rise up to high and trigger the in_pin handler, but and LED 4 stays on indicating that the code below in in_pin_handler() is not run.

    		//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(PIN_OUT);

    I have changed the code in in_pin_handler() to now run the sd_power_system_off() code as suggested.

    				//Enter System-off
                    NRF_LOG_INFO("Enter System-off");
    		            sd_power_system_off();
                          while(1){
    								//This has been put in here to  prevent spurious calls whilst in debug mode
                                   }

    Thanks for your support on this Jørgen

  • Do you see advertising from the device with a phone or a PC running nRF Connect? If not, something most likely returned an error and put the application in the error handler. Could you try debugging the application, to see if you catch any error codes?

  • Hi,

    I've made lots of progress and have it effectively running GPIO_init() and going to the in_pin_handler()  which I did by removing in gpio_init() the following code

        //err_code = nrf_drv_gpiote_in_uninit(SWITCH_PIN);
        //NRF_LOG_INFO("Error is: %d..", err_code);
        //APP_ERROR_CHECK(err_code);  
     

    and in in_pin_handler() the following code

    				//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);           
                  

    My log now looks like this 

    So gpio_init is being called and the in_pin_handler() is being called but the error is in the in_pin_handler() at this line

    err_code = nrf_drv_gpiote_in_init(SWITCH_PIN, &in_config, NULL);            	 //Initialize the wake-up pin

    Error code 8 usually means that something has been declared before?

    Oops.. thought I better add my development stack

    I'm using

    • An nRF52832 DK
    • SDK 15.3.0
    • Segger IDE
    • The soft device is S112 
    • JLinkRTTViewer for debug

    Any help on this fatal error 8 gratefully received.

    My code now looks like this..

    /**
     * @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;
    		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(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_LOG_INFO("Configure switch to wake-up");
    		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
    		NRF_LOG_INFO("Error is: %d..", err_code);
                    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
    			
    				//Enter System-off
                    NRF_LOG_INFO("Enter System-off");
    		sd_power_system_off();
                          while(1){
                                             //This has been put in here to  prevent spurious calls whilst in debug mode
                                   }
    		}
    }
    
    
    /**
     * @brief Function for configuring: PIN_IN_POWER_DOWN pin (BUTTON_1) to enter System-off, 
     * PIN_IN_WAKE_UP pin (BUTTON_2) to wake up from System-off, and PIN_OUT pin for LED_4 output
     */
    
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
    	//Initialize gpiote module
        NRF_LOG_INFO("Initialize gpiote module");
        if(!nrf_drv_gpiote_is_init())
            {
            err_code = nrf_drv_gpiote_init();
            APP_ERROR_CHECK(err_code);  
            }
        APP_ERROR_CHECK(err_code);
        
    		//Initialize output pin
        NRF_LOG_INFO("Turn on LED 4");
        nrf_drv_gpiote_out_clear(PIN_OUT);                                               	//Turn on LED to indicate that nRF5x is not in System-off mode
    
        //Configure sense input pin
        NRF_LOG_INFO("Configure sense input pin to commence shutdown procedure  on opening of the switch");
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(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 floating. 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
        NRF_LOG_INFO("intiate the PIN Error is: %d..", err_code);
        APP_ERROR_CHECK(err_code);                                                          			//Check potential error
        nrf_drv_gpiote_in_event_enable(SWITCH_PIN, true);                                                           //Enable event and interrupt for the wakeup pin
    
    }
    
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        bool erase_bonds;
    
        // Initialize.
        log_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        adc_configure();
        gap_params_init();
        gatt_init();
        advertising_init();
        db_discovery_init();
        services_init();
        conn_params_init();
        peer_manager_init();
    
        // Start execution.
        NRF_LOG_INFO("Switch monitor started.");
        advertising_start(erase_bonds);
        tx_power_set();
        gpio_init();
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
            NRF_LOG_INFO("In the idle loop... ");
            nrf_delay_ms(500);
        }
    }

  • Yes, error 8 (INVALID_STATE) means that either the driver is not initialized, or the pin is in use. I see that you removed nrf_drv_gpiote_in_uninit() on SWITCH_PIN in in_pin_handler, so the pin will be in use when you try to init it again below. Note that you can also configure the sense functionality of a GPIO for wakeup directly using the GPIO HAL function nrf_gpio_cfg_sense_input().

Related