Multiple GPIO interrupts

Hello

I have 2 peripherals on my custom nRF52840 board: accelerometer and a touch button

I configured the gpio callbacks for both parts but see strange behavior: On a button press both  button and accelerometer GPIO callbacks trigger. But on the accelerometer event the accelerometer GPIO callback DOES NOT  trigger. I am 100% certain that the accelerometer is configured correctly and generates interrupt events.

Details below

Any ideas what is wrong??
Thank you

DTS

custom_pins {
        compatible = "gpio-keys";
button1: button_1 {
            gpios = <&gpio0 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
            label = "Touch button";
        };
// accelerometer int1
        acc_int1: acc_int1 {
            gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
        };
};
proj.conf
CONFIG_GPIO=y
---------------------------------
// buttton init code
static const struct gpio_dt_spec _btn_map[] = {
    GPIO_DT_SPEC_GET_OR(DT_ALIAS(sw1), gpios, {0}),
};

      
int btn_init(btn_cb_t cb)
{
    int ret;
    uint32_t btn_mask = 0;

    // Setup common callback. Note the callback struct must not be a local var.
    static struct gpio_callback gpio_cb;
   
    for (unsigned i=0; i<NUM_BTNS; ++i) {
        ret = gpio_pin_configure_dt(&_btn_map[i], GPIO_INPUT);
        if (ret != 0) {
            LOG_ERR("Error %d: failed to configure %s pin %d", ret, _btn_map[i].port->name, _btn_map[i].pin);
            return -1;
        }
        btn_mask |= BIT(_btn_map[i].pin);
        gpio_init_callback(&gpio_cb, btn_gpio_evt_cb, btn_mask);
        gpio_add_callback(_btn_map[i].port, &gpio_cb);
        ret = gpio_pin_interrupt_configure_dt(&_btn_map[i], GPIO_INT_EDGE_BOTH);
        if (ret != 0) {
            LOG_ERR("Error %d: failed to configure interrupt on %s pin %d", ret, _btn_map[i].port->name, _btn_map[i].pin);
            return -2;
        }
    }

    LOG_DBG("button config done.");

    return 0;
}
//------------------------
Accelerometer INT1 init  code
static const struct gpio_dt_spec _int1_dt_spec = GPIO_DT_SPEC_GET_OR(DT_ALIAS(accint1), gpios, {0});
gpio_pin_configure_dt(&_int1_dt_spec, GPIO_INPUT);
gpio_init_callback(&_gpio_int1_cb,gpio_int1_callback, BIT(_int1_dt_spec.pin));
gpio_add_callback(_int1_dt_spec.port, &_gpio_int1_cb);
gpio_pin_interrupt_configure_dt(&_int1_dt_spec,GPIO_INT_LEVEL_ACTIVE);

Parents
  • Question, Is it OK for the accelerometer int1 pin to be under "gpio-keys"  binding? The documentation says this is for buttons

    If no - what binding should be under ?

    Thanks

  • Hi,

    Just to be clear, are you saying that _gpio_int1_cb() is called when you press the GPIO button, but it's not called when accint1 is toggled by the accelerometer? 

    AndyM said:
    Question, Is it OK for the accelerometer int1 pin to be under "gpio-keys"  binding? The documentation says this is for buttons

    Yes, this should be fine,

    regards

    Jared 

  • Hi Andy,

    Can you set a breakpoint at line : gpio_init_callback(&_gpio_int1_cb,gpio_int1_callback, BIT(_int1_dt_spec.pin));

    And see what the third parameter BIT(_int1_dt_spec.pin) is when you run the program with the debugger?

    Can you share a screenshot of the variable from debug view?

    regards

    Jared 

  • Jared

    Your hunch was correct. I was including a header which redefined the BIT macro so the pin used for the button was added to the pin mask for the accelerometer interrupt and that' caused the accelerometer gpio callback to be called  on a button press. I fixed that and now the button press works fine and does not trigger the accelerometer gpio callback. .Thank you!

    However the accelerometer interrup callback still is not called on a movement event, as expected. I'm certain that the part generates the interrupt - if I poll the control register of the accelerometer in a loop I see the interrupt bit set when the event occurs. I tried using  GPIO_INT_EDGE_TO_ACTIVE  and GPIO_INT_LEVEL_ACTIVE flags in gpio_pin_interrupt_configure_dt() function - makes no difference

    Any ideas ?
  • AndyM said:
    Your hunch was correct. I was including a header which redefined the BIT macro so the pin used for the button was added to the pin mask for the accelerometer interrupt and that' caused the accelerometer gpio callback to be called  on a button press. I fixed that and now the button press works fine and does not trigger the accelerometer gpio callback. .Thank you!

    Good,

    AndyM said:
    However the accelerometer interrup callback still is not called on a movement event, as expected. I'm certain that the part generates the interrupt - if I poll the control register of the accelerometer in a loop I see the interrupt bit set when the event occurs. I tried using  GPIO_INT_EDGE_TO_ACTIVE  and GPIO_INT_LEVEL_ACTIVE flags in gpio_pin_interrupt_configure_dt() function - makes no difference

    Can you double check it by probing the interrupt line either with an oscilloscope or logic analyzer and confirm that the pin is asserted by the accelerometer? 

    regards

    Jared 

  • Can you double check it by probing the interrupt line either with an oscilloscope or logic analyzer and confirm that the pin is asserted by the accelerometer? 

    I put in a request but it's out of my hands,l hopefully later this week.

    One peculiar thing is that  gpio_pin_get_dt() always returns 0  but the pin is configured as 

    GPIO_INPUT|GPIO_ACTIVE_HIGH so I expected to see a 1
    Is my expectation correct? And if it is wouldn't this point to hardware?
    Thanks
  • AndyM said:
    I put in a request but it's out of my hands,l hopefully later this week.

    Got it,

    AndyM said:
    GPIO_INPUT|GPIO_ACTIVE_HIGH so I expected to see a 1
    Is my expectation correct?

    If by this you mean that you configure the pin as GPIO_ACTIVE_HIGH in the dts and as an INPUT in the application with for example gpio_pin_configure_dt() then that is OK. But you still need to configure what interrupt that should trigger the callback handler which you have already done in gpio_pin_interrupt_configure_dt().

    I therefore wonder, does the accelerometer pull the signal to a logical 1 or a logical 0 when it enables the interrupt? Have you tried switching it to a GPIO_ACTIVE_LOW and see if that fixes the issue?

    regards

    Jared 

Reply
  • AndyM said:
    I put in a request but it's out of my hands,l hopefully later this week.

    Got it,

    AndyM said:
    GPIO_INPUT|GPIO_ACTIVE_HIGH so I expected to see a 1
    Is my expectation correct?

    If by this you mean that you configure the pin as GPIO_ACTIVE_HIGH in the dts and as an INPUT in the application with for example gpio_pin_configure_dt() then that is OK. But you still need to configure what interrupt that should trigger the callback handler which you have already done in gpio_pin_interrupt_configure_dt().

    I therefore wonder, does the accelerometer pull the signal to a logical 1 or a logical 0 when it enables the interrupt? Have you tried switching it to a GPIO_ACTIVE_LOW and see if that fixes the issue?

    regards

    Jared 

Children
  • Jared, just to clarify, I made the following changes  but it did not make a difference

    acc_int1: acc_int1 {
                gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
            };
    gpio_pin_configure_dt(&_int1_dt_spec, GPIO_INPUT|GPIO_ACTIVE_LOW);
    gpio_pin_interrupt_configure_dt(&_int1_dt_spec,GPIO_INT_LEVEL_INACTIVE);

    I also tried  GPIO_INT_EDGE_TO_ACTIVE when configuring the interrupt - no luck

    Did I miss anything?

    Thank you

     
  • Hi,

    AndyM said:
    Did I miss anything?

    That looks correct, were you able to verify if the interrupt line is toggled by the slave and if so in what direction?

    Another suggestion, can you try to move the gpio_pin_interrupt_configure_dt() call before gpio_init_callback() and see if that changes anything? Also try using 

    GPIO_INT_EDGE_TO_ACTIVE instead of GPIO_INT_LEVEL_ACTIVE as well. 
    regards
    Jared
  • Yes, in the code gpio_pin_interrupt_configure_dt is called before gpio_init_callback

    Unfortunately did not work

    Waiting on the results of the hardware analysis, will keep you posted

    Anything else worth trying in the meantime?

    Thank you

  • Jared

    I checked the spec - by default the INT1 pin polarity is active-high

    Also my gpio nodes are configured with sense-edge-mask i.e

    &gpio0 {
        status = "okay";
        sense-edge-mask = <0xffffffff>;
    };
    I believe this is done to avoid the limitation of 8 gpiote channels in the NRF52
    Not sure it matters, it does not work without that property either. Thought I'd bring it up just in case 
    Thank you
  • AndyM said:
    I believe this is done to avoid the limitation of 8 gpiote channels in the NRF52

    You might be into something here, what happens if you disable the other button interrupts completely by removing all code related to it. Both in the dts and main.c file. Only include the interrupt for the accelerometer. 

    This whole issue is a bit strange as setting up an interrupt for a button or an external slave should be exactly the same, effectively you should be able to replace the connection of one of the buttons to the pin with the accelerometer and see that it triggers the same interrupt. 

    regards

    Jared 

Related