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

getting an interrupt when any of multiple GPIO pins change

I am trying to setup an interrupt to fire whenever any of 6 GPIO pins change value using an nRF51822 with soft device. I found the example that uses GPIOTE to get an interrupt call when a single pin changes and that works fine (the pin change int example). I'm having a hard time extending that example so that my interrupt handler gets called whenever any of multiple pins (6 to be precise) change values. Are there any other examples out there that would show this? Any pointers here would be greatly appreciated. I'm using v12 of the SDK.

  • Hello David

    The pin_change_int example uses high accuracy sensing to sense change in the pin. When using high accuracy you can detect high-speed changes in several pins simultaneously, but in nRF51822 there are only 4 GPIOTE channels which means you can only detect changes in up to 4 pins. It also requires the use of a high frequency clock which increases power consumption.

    If low accuracy (Port event) is used you can detect changes in up to 32 pins, but you cannot detect high-speed changes as it uses a low frequency timer. In addition to this it can only detect change in one pin at a time. If changes in two pins happen simultaneously only one change will be sensed. A combination between high and low accuracy can be used by changing the value of

    in_config.hi_accuracy
    

    from true to false between gpiote_in_inits.

    Remember to change the "GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS" in sdk_config.h to the correct number of events you need. If you try to create more low power events than is defined here you will get a NO_MEM error.

    The following code is a modification of the pin_change_int example, and uses high accuracy for 4 inputs, and low accuracy for additional two inputs. GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS in sdk_config.h is here set to 2.

    #ifdef BSP_BUTTON_0
        #define PIN_IN BSP_BUTTON_0
    #endif
    #ifdef BSP_BUTTON_1
        #define PIN_IN2 BSP_BUTTON_1
    #endif
    #ifdef BSP_BUTTON_2
        #define PIN_IN3 BSP_BUTTON_2
    #endif
    #ifdef BSP_BUTTON_3
        #define PIN_IN4 BSP_BUTTON_3
    #endif
    
    #define PIN_IN5 16 //pin P0.16
    #define PIN_IN6 15 //pin P0.15
    
    #ifndef PIN_IN
        #error "Please indicate input pin"
    #endif
    
    #ifdef BSP_LED_0
        #define PIN_OUT BSP_LED_0
    #endif
    #ifdef BSP_LED_1
        #define PIN_OUT2 BSP_LED_1
    #endif
    #ifdef BSP_LED_2
        #define PIN_OUT3 BSP_LED_2
    #endif
    #ifdef BSP_LED_3
        #define PIN_OUT4 BSP_LED_3
    #endif
    #ifndef PIN_OUT
        #error "Please indicate output pin"
    #endif
    
    void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
    	switch(pin)
    	{
    		case PIN_IN:
    			nrf_drv_gpiote_out_toggle(PIN_OUT);
    			break;
    		case PIN_IN2:
    			nrf_drv_gpiote_out_toggle(PIN_OUT2);
    			break;
    		case PIN_IN3:
    			nrf_drv_gpiote_out_toggle(PIN_OUT3);
    			break;
    		case PIN_IN4:
    			nrf_drv_gpiote_out_toggle(PIN_OUT4);
    			break;
    		case PIN_IN5:
    			nrf_drv_gpiote_out_toggle(PIN_OUT);
    			nrf_drv_gpiote_out_toggle(PIN_OUT3);
    			break;
    		case PIN_IN6:
    			nrf_drv_gpiote_out_toggle(PIN_OUT2);
    			nrf_drv_gpiote_out_toggle(PIN_OUT4);
    			break;
    		default:
    
    			break;
    	}
    }
    
    /**
     * @brief Function for configuring: PIN_IN pin for input, PIN_OUT pin for output,
     * and configures GPIOTE to give an interrupt on pin change.
     */
    static void gpio_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);
    
        err_code = nrf_drv_gpiote_out_init(PIN_OUT, &out_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_out_init(PIN_OUT2, &out_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_out_init(PIN_OUT3, &out_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_out_init(PIN_OUT4, &out_config);
        APP_ERROR_CHECK(err_code);
    		
    		//configure pins for high accuracy
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true); 
        in_config.pull = NRF_GPIO_PIN_PULLUP;
    		
        err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_IN2, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_IN3, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_IN4, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
    		
    	//Configure low accuracy for the remaining 2 pins
    	in_config.hi_accuracy=false; 
    		
        err_code = nrf_drv_gpiote_in_init(PIN_IN5, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_IN6, &in_config, in_pin_handler);
        APP_ERROR_CHECK(err_code);
    
    	//Enable pin events, interrupt is specifically enabled for high accuracy pins to function.
    	//For low accuracy interrupt is always enabled.
        nrf_drv_gpiote_in_event_enable(PIN_IN, true);
        nrf_drv_gpiote_in_event_enable(PIN_IN2, true);
        nrf_drv_gpiote_in_event_enable(PIN_IN3, true);
        nrf_drv_gpiote_in_event_enable(PIN_IN4, true);
    	nrf_drv_gpiote_in_event_enable(PIN_IN5, true);
    	nrf_drv_gpiote_in_event_enable(PIN_IN6, true);
    }
    
    
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        gpio_init();
    
        while (true)
        {
            // Do nothing.
        }
    }
    

    Best regards

    Jørn Frøysa

  • Thank you very much Jørn for the thorough answer. Very helpful!

Related