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





Parents
  • 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

  • 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().

  • Thanks for your reply Jørgen.

    So I have cleaned up the code but I am getting some bizarre behaviour. Well bizarre to me, but as my University Professor said to me many, many years ago. "That computer is doing exactly, what you told it to do." :)

    So a few questions. Initially I removed nrf_drv_gpiote_in_uninit() on SWITCH_PIN as the whole system seems to hang and pause at "In the idle loop"  if I had that line in there, but now I think it was maybe reaching shutdown, just not printing any of the comments in the in_pin_handler(). 

    Is there a delay on JLinkRTTViewer being able to print debug comments? 

    I have resorted to JLinkRTTViewer as I never get any comments in debug mode in Segger. The window is always blank. Should I move to Keil or is there a trick to getting the debug screen in Segger to work?

    So, when I had nrf_drv_gpiote_in_uninit() on SWITCH_PIN as a line of code in in_pin_handler() sometimes I was seeing LED_1 go solid when I physically disconnected the wire grounding PIN 16.  Hence I thought it was never shutting down

    So I have taken your advice and I have changed the code in in_pin_handler() to do the following

    /**
     * @brief Interrupt handler for wakeup pins
     */
     
    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
    		//NRF_LOG_INFO("PIN: %d", pin);
                    NRF_LOG_INFO("action: %d", nrf_gpio_pin_read(SWITCH_PIN));
                    NRF_LOG_INFO("PIN: %d",pin);
    
                    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); 
    			
    				//Configure wake-up button
                    NRF_LOG_INFO("Configure switch to wake-up");
    		nrf_gpio_cfg_sense_input(SWITCH_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
                    NRF_LOG_INFO("Enter System-off");
    		sd_power_system_off();
    
    		}
    }

    using the GPIO HAL function.

    So here is the bizarre part. I flash the board with PIN 16 tied to the ground and I get the gpio_init() to run and it leaves my comments on jlinkRTTViewer. But depending on the speed with which I unground the PIN I get two different error logs

    Error log one

    It prints Switch Monitor started indicating it has rebooted and LED_1 goes solid greed

    however if I unground the pin with a  sharp movement I get the following

    error log 2

    indicating it has fired the in_pin_handler() but it does not even print to the JlinkRTTViewer "PIN: 16" which is the next line of code. So it has hit shutdown and JlinkRTTViewer can't keep up??

    So a few questions in summary I guess:

    1. Is there a delay on JLinkRTTViewer being able to print debug comments and the board has shutdown before it gets to print them? 

    If this is so

    2. It is quite possible that my original code using nrf_drv_gpiote_in_uninit() on SWITCH_PIN and reprogramming PIN 16 as sense HItoLo, worked but it looked like it was hanging as JlinkRTTViewer could never print the comments before shutdown occurred. Explains why it rebooted properly if I reconnected the ground to pin 16.

    3. Is there some sort of instability on the speed of withdrawal of the wire tying PIN 16 to ground line that is making the board start to reboot and then hang? resulting in the "Switch Monitor started" message and a solid greed LED_1

    4. Is there a solution to getting Segger debug screen to print anything, or should I install Keil and move to that?

    Thanks for your help. This has been a real loop in my mind and testing back and forth...

    My theory could also be nuts.

    Here is my entire code...resulting in two different JLinkRTTViewer logs above, depending on the speed of ground withdrawal on pin 16

    /**
     * @brief Interrupt handler for wakeup pins
     */
     
    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
    		//NRF_LOG_INFO("PIN: %d", pin);
                    NRF_LOG_INFO("action: %d", nrf_gpio_pin_read(SWITCH_PIN));
                    NRF_LOG_INFO("PIN: %d",pin);
    
                    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); 
    			
    				//Configure wake-up button
                    NRF_LOG_INFO("Configure switch to wake-up");
    		nrf_gpio_cfg_sense_input(SWITCH_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
                    NRF_LOG_INFO("Enter System-off");
    		sd_power_system_off();
    
    		}
    }
    
    
    /**
     * @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 to detect switch opening: Error code on gpiote_in_init 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);
        }
    }
    
    
    /**
     * @}
     */
    

    Thanks for sticking with me on this....

    Best,

    DW

  • DW said:
    1. Is there a delay on JLinkRTTViewer being able to print debug comments and the board has shutdown before it gets to print them? 

    You should call NRF_LOG_FINAL_FLUSH() if you want to make sure that you get all logs before shutting down.

    DW said:
    2. It is quite possible that my original code using nrf_drv_gpiote_in_uninit() on SWITCH_PIN and reprogramming PIN 16 as sense HItoLo, worked but it looked like it was hanging as JlinkRTTViewer could never print the comments before shutdown occurred. Explains why it rebooted properly if I reconnected the ground to pin 16.

    Yes, that sounds very likely.

    DW said:
    3. Is there some sort of instability on the speed of withdrawal of the wire tying PIN 16 to ground line that is making the board start to reboot and then hang? resulting in the "Switch Monitor started" message and a solid greed LED_1

    Could it be that you created noise on the pin when you pulled it? Since you use the same pin for entering the pin handler and wakeup from system OFF, noise could cause both these to happen. Note that you will enter emulated system OFF mode, if the chip is in debug mode. You should add a while(1) after entering system OFF to avoid that code is run unintentionally.

    DW said:
    4. Is there a solution to getting Segger debug screen to print anything, or should I install Keil and move to that?

    Check out this post.

     

     

     

  • NRF_LOG_FINAL_FLUSH() worked a treat!

    So now some further testing to reproduce the LED_1 going solid green. If I intermittently get it I think some I'll need to work out how to place some debounce code on the SWITCH_PIN.

    Thank you so much for your help. Feels great to make the progress...

    Best

    DW

Reply Children
No Data
Related