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.

     

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

Reply
  • 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.

Children
  • 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.

  • Hi TrulliDev,

    My apology for the late response. Our team is facing high loading due to unavailability, including Susheel being out of office. I will support you in his absence.

    First of all, I would like to ask you to be certain of the driver choice for your project. Are you using the Zephyr GPIO driver, or are you using the nrfx GPIOTE driver?

    As we have discussed above, mixing the two drivers is not recommended. It could be safe, but it could also result in unexpected behaviors. An even worse case scenario is if worked right now, but after an update, or a feature change in your project, unexpected behaviors occurred.

    Your most recent code suggests that you use the nrfx driver, and your latest issue is also only relevant with the nrfx driver. Therefore, I will answer with the assumption that you choose nrfx.


    It seems that we went at an incorrect direction with defining pins for the GPIO1 bank. Our apology for that.

    First of all, I want to resolve your issue with the current approach:

    This macro:

    #define INPUT_PIN     DT_GPIO_PIN(DT_NODELABEL(input0), gpios)

    will just give you the exact pin number without regards for which port it is.

    Supposed you are using P0.3 and P1.3 here, using DT_GPIO_PIN on them will just give you 3, as noted by its documentation.

    It is the same problem with handling GPIO1 pins discussed in this DevZone question:  Zephyr, nrf5340 and pin number.

    You can follow the approach discussed there to resolve this issue.


    Next, I would like to recommend some alternatives, 

    Since you are using the nrfx driver, it is also appropriate to use the helper macro NRF_GPIO_PIN_MAP(port, pin) defined in hal/nrf_gpio.h to get the absolute pin number instead.

    A different view to this matter is that the nrfx driver assumes use of the nRF SoCs and understanding of their specs. As you already understand that, for example, pin 1.05 has absolute number 37, you can just use the number 37 directly, or instead via a macro define like below for better readability.

    #define P1_05_ABSOLUTE_PIN_NUMBER    37


    TrulliDev said:
    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.

    Unfortunately, we don't set up calls on DevZone. Once more, I would like to apologize for us approaching the GPIO1 issue incorrectly, and for the delay due to my team's scheduling.

    If you would like some special support, please get in touch with the Nordic Regional Sales Manager of your area. I would be happy to get you the contact if you need.

    If you have any further questions, please don't hesitate to let me know. The response might take longer than usual due to our team's current situation; but we will strive to minimize your inconvenience.

    Best regards,

    Hieu

Related