This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

nRF51822 and Zephyr: GPIO interrupt on multiple GPIOs

Hello, guys!

I am using nRF51822 SoC with Zephyr. There is a need to configure multiple GPIOs as inputs, with the possibility to fire an interrupt on rising/falling/both edges.
The following piece of code is used to configure one single GPIO:

#define GPIO_PORT DT_LABEL(DT_NODELABEL(gpio0))
const struct device *gpio0;
struct gpio_callback callback;
void Touch1IrqCallback(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins);
    
gpio0 = device_get_binding(GPIO_PORT);

gpio_pin_configure(gpio0, Pin1, GPIO_INPUT | GPIO_PULL_UP);
gpio_pin_interrupt_configure(gpio0, Pin1, GPIO_INT_EDGE_BOTH);
gpio_init_callback(&callback, Touch1IrqCallback, BIT(Pin1));    
gpio_add_callback(gpio0, &callback);



Everything works well until the point when I want to configure 3rd GPIO the same way. At that moment, gpio_pin_interrupt_configure() function returns -19 which is the code for ENODEV.

Is there anything I am missing or I am not aware of? Can we configure multiple nRF51822 GPIOs to fire an interrupt?

Parents Reply Children
  • Hi Bojan,

     

    I just quickly added more inputs to the zephyr/samples/basic/button sample in ncs v1.8.0 (zephyr v2.7.0):

    /*
     * Copyright (c) 2016 Open-RnD Sp. z o.o.
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr.h>
    #include <device.h>
    #include <drivers/gpio.h>
    #include <sys/util.h>
    #include <sys/printk.h>
    #include <inttypes.h>
    
    #define SLEEP_TIME_MS	1
    
    /*
     * Get button configuration from the devicetree sw0 alias. This is mandatory.
     */
    #define SW0_NODE	DT_ALIAS(sw0)
    #if !DT_NODE_HAS_STATUS(SW0_NODE, okay)
    #error "Unsupported board: sw0 devicetree alias is not defined"
    #endif
    static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios,
    							      {0});
    static struct gpio_callback button0_cb_data;
    static struct gpio_callback button1_cb_data;
    static struct gpio_callback button2_cb_data;
    static struct gpio_callback button3_cb_data;
    
    #define PIN1 18
    #define PIN2 19
    #define PIN3 20
    
    /*
     * The led0 devicetree alias is optional. If present, we'll use it
     * to turn on the LED whenever the button is pressed.
     */
    static struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios,
    						     {0});
    
    void button_pressed(const struct device *dev, struct gpio_callback *cb,
    		    uint32_t pins)
    {
    	uint32_t bit_to_pin = 0;
    	for (int i = 0; i < 32; i++) {
    		if ((pins >> i) == 1) {
    			bit_to_pin = i;
    			break;
    		}
    	}
    
    	printk("Button %d pressed at %" PRIu32 "\n", bit_to_pin, k_cycle_get_32());
    	static bool val;
    	val = !val;
    	gpio_pin_set_dt(&led, val);	
    }
    
    void main(void)
    {
    	int ret;
    
    	if (!device_is_ready(button.port)) {
    		printk("Error: button device %s is not ready\n",
    		       button.port->name);
    		return;
    	}
    
    	ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
    	if (ret != 0) {
    		printk("Error %d: failed to configure %s pin %d\n",
    		       ret, button.port->name, button.pin);
    		return;
    	}
    
    	ret = gpio_pin_interrupt_configure_dt(&button,
    					      GPIO_INT_EDGE_TO_ACTIVE);
    	if (ret != 0) {
    		printk("Error %d: failed to configure interrupt on %s pin %d\n",
    			ret, button.port->name, button.pin);
    		return;
    	}
    
    	ret = gpio_pin_configure(button.port, PIN1, GPIO_INPUT | GPIO_PULL_UP);
    	printk("ret %d\n", ret);
    	ret = gpio_pin_configure(button.port, PIN2, GPIO_INPUT | GPIO_PULL_UP);
    	printk("ret %d\n", ret);
    	ret = gpio_pin_configure(button.port, PIN3, GPIO_INPUT | GPIO_PULL_UP);
    	printk("ret %d\n", ret);
    	ret = gpio_pin_interrupt_configure(button.port, PIN1, GPIO_INT_EDGE_BOTH);
    	printk("ret %d\n", ret);
    	ret = gpio_pin_interrupt_configure(button.port, PIN2, GPIO_INT_EDGE_BOTH);
    	printk("ret %d\n", ret);
    	ret = gpio_pin_interrupt_configure(button.port, PIN3, GPIO_INT_EDGE_BOTH);
    	printk("ret %d\n", ret);
    	gpio_init_callback(&button1_cb_data, button_pressed, BIT(PIN1));
    	ret = gpio_add_callback(button.port, &button1_cb_data);
    	printk("ret %d\n", ret);
    	gpio_init_callback(&button2_cb_data, button_pressed, BIT(PIN2));	
    	ret = gpio_add_callback(button.port, &button2_cb_data);
    	printk("ret %d\n", ret);
    	gpio_init_callback(&button3_cb_data, button_pressed, BIT(PIN3));	
    	ret = gpio_add_callback(button.port, &button3_cb_data);		
    	printk("ret %d\n", ret);
    	
    
    	gpio_init_callback(&button0_cb_data, button_pressed, BIT(button.pin));
    	gpio_add_callback(button.port, &button0_cb_data);
    	printk("Set up button at %s pin %d\n", button.port->name, button.pin);
    
    	if (led.port && !device_is_ready(led.port)) {
    		printk("Error %d: LED device %s is not ready; ignoring it\n",
    		       ret, led.port->name);
    		led.port = NULL;
    	}
    	if (led.port) {
    		ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT);
    		if (ret != 0) {
    			printk("Error %d: failed to configure LED device %s pin %d\n",
    			       ret, led.port->name, led.pin);
    			led.port = NULL;
    		} else {
    			printk("Set up LED at %s pin %d\n", led.port->name, led.pin);
    		}
    	}
    
    	printk("Press the button\n");
    }
    

     

    And it works as expected on my end (on my nrf51dk):

    *** Booting Zephyr OS build v2.7.0-ncs1  ***
    ...
    Set up button at GPIO_0 pin 17
    Set up LED at GPIO_0 pin 21
    Press the button
    Button 17 pressed at 234164
    Button 18 pressed at 253241
    Button 18 pressed at 256734
    Button 18 pressed at 256835
    Button 19 pressed at 272220
    Button 19 pressed at 276119
    Button 20 pressed at 288819
    Button 20 pressed at 292737
    

     

    Kind regards,

    Håkon

  • Thanks, Hakon. Let me dive deeper and figure out what I am missing.

    Thanks for the great support!

  • Hello, Hakon.

    Here is how I tried to initialize GPIOs used to catch external interrupts:

    /* Touch Pads */
    #if DT_NODE_HAS_STATUS(DT_NODELABEL(touchpadsgpio), okay)
    	tp1GpioDevice = device_get_binding(DT_LABEL(DT_PHANDLE(DT_NODELABEL(touchpadsgpio), tp1_gpio)));
    	tp1Pin = DT_PROP(DT_NODELABEL(touchpadsgpio), tp1_pin);            
    	gpio_pin_configure(tp1GpioDevice, tp1Pin, GPIO_INPUT | GPIO_PULL_UP);
    	gpio_pin_interrupt_configure(tp1GpioDevice, tp1Pin, GPIO_INT_EDGE_BOTH);
    	gpio_init_callback(&callback, Touch1IrqCallback, BIT(tp1Pin));    
    	gpio_add_callback(tp1GpioDevice, &callback);
    
    	tp2GpioDevice = device_get_binding(DT_LABEL(DT_PHANDLE(DT_NODELABEL(touchpadsgpio), tp2_gpio)));
    	tp2Pin = DT_PROP(DT_NODELABEL(touchpadsgpio), tp2_pin);
    	gpio_pin_configure(tp2GpioDevice, tp2Pin, GPIO_INPUT | GPIO_PULL_UP);
    	gpio_pin_interrupt_configure(tp2GpioDevice, tp2Pin, GPIO_INT_EDGE_BOTH);
    	gpio_init_callback(&callback, Touch2IrqCallback, BIT(tp2Pin));    
    	gpio_add_callback(tp2GpioDevice, &callback);
    #else 
    #error "Can't find TouchPads GPIO node!"
    #endif 
    
    /* Accelerometer */
    #if DT_NODE_HAS_STATUS(DT_NODELABEL(da217gpio), okay)	
    	int1GpioDevice = device_get_binding(DT_LABEL(DT_PHANDLE(DT_NODELABEL(da217gpio), int1_gpio)));            
    	int1Pin = DT_PROP(DT_NODELABEL(da217gpio), int1_pin);
    	gpio_pin_configure(int1GpioDevice, int1Pin, GPIO_INPUT | GPIO_PULL_DOWN);
    	gpio_pin_interrupt_configure(int1GpioDevice, int1Pin, GPIO_INT_EDGE_RISING);	                        
    	gpio_init_callback(&accCallback, AccInt1IrqCallback, BIT(int1Pin));    
    	ret = gpio_add_callback(int1GpioDevice, &accCallback);
    
    	int2GpioDevice = device_get_binding(DT_LABEL(DT_PHANDLE(DT_NODELABEL(da217gpio), int2_gpio)));
    	int2Pin = DT_PROP(DT_NODELABEL(da217gpio), int2_pin);                      
    	gpio_pin_configure(int2GpioDevice, int2Pin, GPIO_INPUT | GPIO_PULL_DOWN);
    	gpio_pin_interrupt_configure(int2GpioDevice, int2Pin, GPIO_INT_EDGE_RISING);
    	gpio_init_callback(&accCallback, AccInt2IrqCallback, BIT(int2Pin));    
    	gpio_add_callback(int2GpioDevice, &accCallback);
    #else 
    #error "Can't find DA217 GPIO node!"
    #endif 

    touchpadgpio and da217gpio are defined in .overlay file:

        da217gpio: da217gpio {
            status = "okay";
            compatible = "da217-gpio";
            int1-gpio = <&gpio0>;
            int1-pin = <15>;
            int2-gpio = <&gpio0>;
            int2-pin = <16>;
        };        
    
        touchpadsgpio: touchpadsgpio {
            status = "okay";
            compatible = "touchpads-gpio";
            tp1-gpio = <&gpio0>;
            tp1-pin = <5>;
            tp2-gpio = <&gpio0>;
            tp2-pin = <2>;
        };

    Do you have any idea why with that approach I can properly initialize only 2 GPIOs and the 3rd one is returning -19 at gpio_pin_interrupt_configure() point?

    Regards,

    Bojan

  • Hi Bojan,

     

    Try to give each pin-interrupt each own "callback" variable. It looks like you are overwriting "callback" with Touch2IrqCallback now.

    Same goes both interrupt pins on the da271gpio device, where accCallback is used on both pins.

     

    Kind regards,

    Håkon

  • It did not help, Hakon.

    I now have 4 different callback variables but am still unable to properly configure more than two GPIOs.

Related