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!

  • Thank you for the response and status update for support.  We are using the NRFX GPIOTE driver.  The problem we are solving is having more than one QDEC.  The QDEC driver works for one rotary encoder but not more than one currently.

    Here are our includes:

    #include "nrfx_qdec.h"
    #include <nrfx_gpiote.h>

    I am able to get the absolute pin number by using the following macros:

    //#define INPUT_PIN	          DT_GPIO_PIN(DT_ALIAS(sw0), gpios)
    #define GPIO_ENC_LEFT_A     NRF_GPIO_PIN_MAP(DT_PROP(DT_GPIO_CTLR(DT_NODELABEL(encoder0), gpios), port), DT_GPIO_PIN(DT_NODELABEL(encoder0), gpios))
    #define GPIO_ENC_LEFT_B     NRF_GPIO_PIN_MAP(DT_PROP(DT_GPIO_CTLR(DT_NODELABEL(encoder1), gpios), port), DT_GPIO_PIN(DT_NODELABEL(encoder1), gpios))
    #define GPIO_ENC_RIGHT_A    NRF_GPIO_PIN_MAP(DT_PROP(DT_GPIO_CTLR(DT_NODELABEL(encoder1), gpios), port), DT_GPIO_PIN(DT_NODELABEL(button2), gpios))
    #define GPIO_ENC_RIGHT_B    NRF_GPIO_PIN_MAP(DT_PROP(DT_GPIO_CTLR(DT_NODELABEL(encoder3), gpios), port), DT_GPIO_PIN(DT_NODELABEL(encoder3), gpios))

    I tested the absolute pin address using one of the existing buttons on GPIO1 and it worked fine.

    The new issue I am having is that our rotary encoder has its own pull-ups and filtering on the A and B "sensors" or "contacts" (encoder is electro-mechanical).  The problem is that it seems like GPIO and/or GPIOTE pins are forced to have pull-ups or pull-downs declared in the device map and that causes a voltage divider with the hardware encoder.  Thus, we do not see valid edges when turning the encoder.

    Below is my current device map:

    	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";
    		};
    

    Is there a method to declare GPIO pins w/o having any pull set?

    I also see some GPIOTE configuration in the code as well:

    	static const nrfx_gpiote_input_config_t input_config = {
    		.pull = NRF_GPIO_PIN_NOPULL,
    	};
    	const nrfx_gpiote_trigger_config_t trigger_config = {
    		.trigger = NRFX_GPIOTE_TRIGGER_TOGGLE,
    		.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;
    	}

    With those settings I am still not seeing edges on when I rotate the rotary encoder.

  • TrulliDev said:
    The problem we are solving is having more than one QDEC.  The QDEC driver works for one rotary encoder but not more than one currently.

    This seems strange. Did you investigate the qdec_nrfx driver or something else? I am not familiar with any of them, but I would assume expect that a decoder driver should support multiple instances, since it is quite common to use multiple decoders.

    I am just asking to see if you want to double check on this point. I could help if you wish to. If you are fully invested in the nrfx solution, let's just forget about it.

    TrulliDev said:
    The problem is that it seems like GPIO and/or GPIOTE pins are forced to have pull-ups or pull-downs declared in the device map

    This is not right. You can simply remove the pull flag from its declaration, and it would mean no pull.

    However, the nrfx driver controls the pin directly. So regardless of how the pins are defined in the DTS, the nrfx driver should be able to override it.

    However, unless you are using the Zephyr driver somewhere, the DTS definition should have no effect, and the nrfx driver should have the final say.

    In the case of two drivers both configuring one pin, then I cannot be sure of the behavior without investigating. However, I would guess with some confidence that the API that is called later will have the final effect.

    TrulliDev said:
    Is there a method to declare GPIO pins w/o having any pull set?

    The code you included should do exactly that.

    How did you check if the pull configuration is set correctly or not?

    Here is how I setup a simple test where I both set the pull configuration using nrfx Driver API and confirm its effect with nrfx HAL API:

    #include <nrfx_gpiote.h>
    
    void print_pull(uint8_t port, uint8_t pin)
    {
    	nrf_gpio_pin_pull_t t = nrf_gpio_pin_pull_get(NRF_GPIO_PIN_MAP(port, pin));
    	printk("P%d.%02d ", port, pin);
    	switch (t)
    	{
    		case NRF_GPIO_PIN_NOPULL: 	printk("NRF_GPIO_PIN_NOPULL"); break;
    		case NRF_GPIO_PIN_PULLDOWN: printk("NRF_GPIO_PIN_PULLDOWN"); break;
    		case NRF_GPIO_PIN_PULLUP: 	printk("NRF_GPIO_PIN_PULLUP"); break;
    		default: printk("DEADBEEF");
    	}
    	printk("\n");
    }
    
    void nrfx_configure(uint8_t port, uint8_t pin, const nrf_gpio_pin_pull_t pull)
    {
    	uint32_t err;
    	const nrfx_gpiote_input_config_t input_config = {
    		.pull = pull,
    	};
    	err = nrfx_gpiote_input_configure(NRF_GPIO_PIN_MAP(port, pin),
    					  &input_config,
    					  NULL,
    					  NULL);
    	printk("nrfx_gpiote_input_configure %d\n", err);
    }
    
    void main(void)
    {
    	nrfx_configure(0, 14, NRF_GPIO_PIN_PULLUP);
    	nrfx_configure(0, 15, NRF_GPIO_PIN_PULLDOWN);
    
    	print_pull(0, 14);
    	print_pull(0, 15);
    }

    With this test, I can see that the pins are configured correctly no matter how the pins are defined in my DTS. That is including undefined, or defined with completely different pull, or defined with no pull.


    What happened when you change the pull configuration in your DTS, for example, like this?

    		encoder0: encoder_0 {
    			gpios = <&gpio1 10 (GPIO_ACTIVE_LOW)>;
    			label = "Encoder Left A";
    		};

    The expectation is that it should not have any effect. If it does, then you are having the Zephyr driver running.

  • Hieu,

    If you look at nrfx_qdec.h you will see that they hard coded the functions for "QDEC0" so they are only able to take one instance of a QDEC.  It is my impression that the driver could be extended to support more than one QDEC but it would have to be taken out-of-tree.  We are also having a different issue with the QDEC driver that causes us to get too many interrupts per rotation.  For those reasons we are attempting to roll our own driver.

    Regarding the pin configuration, the hardware is in an enclosure that prevents me from easily probing the circuit.  I will remove the hardware and see if I can characterize what is going on.

    Regards,
    Peter

  • Peter,

    Thanks for the information. I will wait for your update. Susheel will be back this week so either he or I will continue supporting you.

    Regards,

    Hieu

  • Hello,

    I was able to scope my pins and they do appear to have the proper voltage.  We are using a CR 2032 button cell battery at 3V and I am seeing the A and B signals swing between 0V and 3V as expected.

    What I discovered is that I was missing a call that would enable the trigger for my sensor pins.

    	// Enable encoder sensor trigger events
    	nrfx_gpiote_trigger_enable(GPIO_ENC_RIGHT_A, true);
    	nrfx_gpiote_trigger_enable(GPIO_ENC_RIGHT_B, true);

    After adding the above code I finally started to get the trigger events for "GPIO_ENC_RIGHT_A" but now I have a new problem.  I am not getting trigger events for "GPIO_ENC_RIGHT_B" pin.  When it is all said and done I have two rotary encoders each with an A and B sensor pin so I need a total of four triggers to fire.

    Is there some limitation of GPIOTE to lmiit only to one trigger or how do I enable up to four triggers at once?

    Thanks,
    Peter

Related