Need help with nRF5340 IRQ conflict errors when adding GPIOTE drivers to Nordic Bluetooth Peripheral UART project

We are using the Nordic Bluetooth "Peripheral UART" project as a base for our project and I am attempting to add the GPIOTE drivers to the project but getting the following error:

gen_isr_tables.py: error: multiple registrations at table_index 47 for irq 47 (0x2f)
Existing handler 0x39aa5, new handler 0x39aa5
Has IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?

It looks like there is an IRQ conflict with adding the GPIOTE drivers and the DK drivers.

The reason I need the GPIOTE driver is in order to add multiple QDEC rotary encoders (which is not supported by the current QDEC driver).  I have attached a sample app that demonstrates the error.  We are using NCS v2.3.0 targeting nrf5340dk_nrf5340_cpuapp_ns.  We need to deconflict the IRQ but also keep the as much of the DK drivers as possible to expedite this project.

See attached application below:
peripheral_uart_GPIOTE.zip

Thanks for the help!

Parents
  • I understand.

    You cannot use nrfx_gpiote driver separately when you are using gpio_nrfx.c.

    You need to do what nrf\lib\dk_buttons_and_leds\dk_buttons_and_leds.c did. You need to get the device pointer of gpiote zephyr driver like below

    const struct device *const gpiote = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(gpiote));

    And use this instead of direct nrfx API for GPIOTE. 

    You can register another callback for your application just like nrf\lib\dk_buttons_and_leds\dk_buttons_and_leds.c did.

  • The file dk_buttons_and_leds.c is using loads of macros to abstract away the code to support multiple DKs so referencing the DK code doesn't help me much because I am very unfamiliar with Zephyr and Nordic.

    When you say one CANNOT use GPIO and GPIOTE I assume you mean that it is forbidden to have the following in the prj.conf:
    CONFIG_GPIO=y
    CONFIG_NRFX_GPIOTE=y

    Can you modify my posted application to trigger an event on the rising edge of GPIO pin 37?  I understand you may not be able to test but I would like to see what the code would look like to do this.

    As a side note I have been able to get the generic nrfx GPIOTE sample application working on the nRF5340 even though the 5340 is not listed as supported by the sample application.  However, this application is using no GPIO.

     

Reply
  • The file dk_buttons_and_leds.c is using loads of macros to abstract away the code to support multiple DKs so referencing the DK code doesn't help me much because I am very unfamiliar with Zephyr and Nordic.

    When you say one CANNOT use GPIO and GPIOTE I assume you mean that it is forbidden to have the following in the prj.conf:
    CONFIG_GPIO=y
    CONFIG_NRFX_GPIOTE=y

    Can you modify my posted application to trigger an event on the rising edge of GPIO pin 37?  I understand you may not be able to test but I would like to see what the code would look like to do this.

    As a side note I have been able to get the generic nrfx GPIOTE sample application working on the nRF5340 even though the 5340 is not listed as supported by the sample application.  However, this application is using no GPIO.

     

Children
  • When you say one CANNOT use GPIO and GPIOTE I assume you mean that it is forbidden to have the following in the prj.conf:
    CONFIG_GPIO=y
    CONFIG_NRFX_GPIOTE=y

    No, nrfx_gpiote HAL module and gpio_nrfx both work with the expectations that nrfx_gpiote_irq_handler is called to handle the interrupts. gpio_nrfx.c is calling 

    	IRQ_CONNECT(DT_IRQN(GPIOTE_NODE), DT_IRQ(GPIOTE_NODE, priority),
    		    nrfx_isr, nrfx_gpiote_irq_handler, 0);
     

    and your application is calling the below in main.c

    	IRQ_CONNECT(DT_IRQN(DT_NODELABEL(gpiote)),
    		    DT_IRQ(DT_NODELABEL(gpiote), priority),
    		    nrfx_isr, nrfx_gpiote_irq_handler, 0);

    That means you are trying to connect the irq handler twice (Even though both are trying to connect the same irq handler, the linker thinks that this most likely is a mistake and throws an error.

    If you comment out the IRQ_CONNECT thing in your application (as nrfx_gpiote_irq_handler is already registered as irq handler by Zephyr gpio driver gpio_nrfx.c) then you can see that you code will compile. It might work for your case as luckily there does not seems to be anything that gpio_nrfx.c is remembered and there are no status get API that will be affected by using nrfx_gpio.c outside the zephyr driver framework . So you might just be fine by commenting out the IRQ_CONNECT (line 127 of main.c of your application)  you might be able to get what you want.

  • Susheel,

    I commented out the IRQ connect and the GPIOTE init code and it did build and work so thank you very much for that good advise.

    However, I am only able to get it to work with the "sw0" pin using the call:

    #define INPUT_PIN	DT_GPIO_PIN(DT_ALIAS(sw0), gpios)

    Because the define INPUT_PIN is some kind of "node index" that is generated from the special macro expansions, I'm not sure what macros I would need to use to map my pin "37" to be used.  I believe pin 37 is GPIO1.06 with my hardware.

    If I can get help for how to declare "INPUT_PIN" I think I will be able to proceed.

    Thanks,
    Peter

  • This is most likely because you are using DT_ALIAS macro inside which works for sw0 since there is an alias defined for sw0 and led0 in \zephyr\boards\arm\nrf5340dk_nrf5340\nrf5340_cpuapp_common.dts. Try creating an alias for your pin number "37" as well for the same macro conversion to work. If you do not like to create a new alias, then you could try using the define without ALIAS as below.

    #define INPUT_PIN	DT_GPIO_PIN(your_pin_name_in_devicetree, gpios)

  • Susheel,

    I am now having a different issue.  Basically, anything on "gpio1" bank is not working.

    Here is my overlay code where I declare my GPIO pins:

    / {
    	chosen {
    		nordic,nus-uart = &uart0;
    	};
    
    	buttons {
    		compatible = "gpio-keys";
    		button0: button_0 {
    			gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    			label = "Button Left Arrow";
    		};
    		button1: button_1 {
    			gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    			label = "Button Right Arrow";
    		};
    		button2: button_2 {
    			gpios = <&gpio1 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    			label = "Button Right Wheel";
    		};
    		button3: button_3 {
    			gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    			label = "Button Left Wheel";
    		};
    	};
    
    	encoders {
    		compatible = "gpio-keys";
    		encoder0: encoder_0 {
    			gpios = <&gpio1 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    			label = "Encoder Left A";
    		};
    		encoder1: encoder_1 {
    			gpios = <&gpio1 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    			label = "Encdoer Left B";
    		};
    		encoder2: encoder_2 {
    			gpios = <&gpio1 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    			label = "Encoder Right A";
    		};
    		encoder3: encoder_3 {
    			gpios = <&gpio1 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    			label = "Encdoer Right B";
    		};
    	};
    
    	aliases{
    		button0 = &button0;
    		button1 = &button1;
    		button2 = &button2;
    		button3 = &button3;
    	};
    };

    Here are my defines using the macros to expand the "node" value:

    //#define INPUT_PIN           DT_GPIO_PIN(DT_ALIAS(sw0), gpios)
    #define GPIO_ENC_LEFT_A     DT_GPIO_PIN(DT_NODELABEL(encoder0), gpios)
    #define GPIO_ENC_LEFT_B     DT_GPIO_PIN(DT_NODELABEL(encoder1), gpios)
    #define GPIO_ENC_RIGHT_A    DT_GPIO_PIN(DT_NODELABEL(encoder2), gpios)
    #define GPIO_ENC_RIGHT_B    DT_GPIO_PIN(DT_NODELABEL(encoder3), gpios)

    For the sake of my "INPUT PIN" I'm using "GPIO_ENC_RIGHT_A" pin to test with:

    	static const nrfx_gpiote_input_config_t input_config = {
    		.pull = NRF_GPIO_PIN_PULLUP,
    	};
    	const nrfx_gpiote_trigger_config_t trigger_config = {
    		.trigger = NRFX_GPIOTE_TRIGGER_HITOLO,
    		.p_in_channel = &in_channel,
    	};
    	static const nrfx_gpiote_handler_config_t handler_config = {
    		.handler = encoder_handler,
    	};
    	err = nrfx_gpiote_input_configure(GPIO_ENC_RIGHT_A,
    					  &input_config,
    					  &trigger_config,
    					  &handler_config);
    	LOG_INF("nrfx_gpiote_input_configure pin=%u", GPIO_ENC_RIGHT_A);
    	if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_gpiote_input_configure error: 0x%08X", err);
    		return;
    	}

    So this all builds just great, but I can only get it to work when I use a pin that happens to be on "gpio0".  For example, it works with button0 and button1 from my overlay.  If I try button2, 3, or encoder0, 1, 2, or 3 it builds fine but does not actually fire the interrupt.  I can see in my overlay that all of those pins are on "gpio1".

    I have verified that button2 and button3 are electrically working.  They work fine using the DK button callback APIs.  I think that something is going wrong getting the node/pin value from the macros.

  • As a side note, my management is concerned about how long this is taking to resolve.  I am hoping we can solve it with your next response.  Otherwise, they are going to want to call a meeting with Nordic.

Related