Multiple GPIO interrupts from SYSTEM_SOFT_OFF

OK, so it seems if you accidently hit "VERIFY ANSWER" your discussion gets locked and you can no longer comment, nor reverse that process.  So, I've had to start a new discussion in order to keep on with the old one:

https://devzone.nordicsemi.com/f/nordic-q-a/88286/multiple-gpio-interrupts-from-system_soft_off

What I wanted to say, rather than verify the answer, was:

Hi Simon,

Firstly, I seem to have accidently set your reply to "verified answer" and I can't seem to work out how to reverse that.

Anyway, I'm actually using the nRF Connect SDK (V1.9.1) and Zephyr, and may be 'cross-pollinating" by using those API's.  But I did ask on here if they were the only ones to use and didn't ever get an answer, so have just made them work for the moment.

What I'm seeing I don't think will benefit from button debounce, but I may be wrong.  What seems to be happening is that the first button press will trigger the device out of SYSTEM_OFF mode, and then my code starts running.  But any subsequent button press seems to interrupt the code that is being run and boot the device out of SYSTEM_OFF mode, even though I don't think it is actually in that mode.  This then seems to scramble all the registers I am using to determine how/why it came out of SYSTEM_OFF, and then I can't get it to do what it is supposed to do.

What I want to be able to do is the moment any GPIO triggers an exit from SYSTEM_OFF, that I disable this function so that any subsequent button presses will have no impact.  Essentially a bit like disabling interrupts whilst you service an exisiting interrupt.

But I can't find anywhere online where the functionality to achieve this is described.

I'd be happy to go with a low power mode rather than SYSTEM_OFF if it makes achieving what I want easier.  I can probably deal with quiescent currents of < 5uA.  Its just I couldn't actually find any helpful Zephyr/nRF Connect SDK low power examples, and everyone I have asked seems to look at me blankly.

I had a quick look at the example you listed in the original post.  Can't immediately understand much of it, but I'll go and have a more detailed look.  Also, not sure how relevant it is given I'm not using the nRF5 SDK

Cheers,

Mike

  • Hi Mike

    Yes, verifying an answer will mark your ticket as "resolved" and lock it. For the nRF52832 you also have the option to use the nRF5 SDK, but this SDK is only in maintenance mode, so for new designs we recommend using the nRF Connect SDK instead. See the nRF Connect SDK and nRF5 SDK statement for more details.

    I still think that adding the debounce will fix the issue with multiple button presses after the initial one, as that will not cause any interrupts after pressing the button once until the debounce duration is done. Then you'll have to set the button input as disconnected for example to make the button not do anything until you go to sleep again. I don't think using another low power mode will help much, as the wake up GPIO will function similarly no matter what sleep mode the device is in. 

    Debounce in the nRF Connect SDK uses the GPIO_DEBOUNCE flag to add a debounce to GPIOs I believe, and it can be seen "in action" in the BLE Mesh OnOff Model sample here.

    Best regards,

    Simon

  • Thanks Simon.

    I think I may have solved my problem.  Lets just say I had a convoluted mess of various gpio configs and interrupt configs, and when I stripped everything back to the basics to test what was causing my issue, it looks like the multiple reset issue has gone away.  But I'll need to do a bit more investigations to be sure of that, using something that can operate my GPIO a bit quicker than I can!

    I think my confusion (and it still exists to an extent) is trying to understand the difference between using:

    nrf_gpio_cfg_input(pin, flags) & 
    nrf_gpio_cfg_sense_input(pin, flags)
    compared to using:
    gpio_pin_configure_dt(spec, flags)
    I think its something to do with the difference between GPIO and GPIOTE, in that I need to use the nrf_gpio API's to set up my GPIO to trigger out of System-Off mode, but then need to use the gpio_pin_configure API's to set up those GPIO if I want to read in their status whilst my code is running.  But don't quote me on that!
    Any clarification would be greatly appreciate :-)
    Cheers,
    Mike
  • Hi (again) Simon,

    OK, a little bit more paring down my code, and some late afternoon testing, and I think my issue is somehow related to this:

    Trying to put the system to System OFF while DETECT is high will cause a wakeup from System OFF reset.

    What I do in my code when it first comes out of System OFF is the following:

    reset_reason = NRF_POWER->RESETREAS;
    gpio_trigger = NRF_GPIO->LATCH;
    printk("reset_reason = %d\n", reset_reason);
    printk("gpio_trigger = %d\n", gpio_trigger);

    I then check reset_reason and gpio_trigger to determine what, principally, caused the exit from System_OFF and, in the case of it being a GPIO state change, which of my GPIO was the cause of this.  The printk statements just let me check that what my code thinks has caused the exit, is actually the case.

    What I notice is that if I only push the button the once, I will get the correct values for reset_reason and gpio_trigger.  For example, if I push the button associated with P0.13, I will get:

    reset_reason = 0x1000

    gpio_trigger = 0x2000

    However, if I push the button several times in quick succession, I will not get the correct value for gpio_trigger; this will almost always come back as zero, even though the reset_reason value is correct.

    I put a k_sleep(K_SECONDS(1)); statement just prior to going back into System_OFF, to delay things for a second and thus try and prevent the multiple button press issue.  This doesn't work reliably - if I press one button and then quickly a second one, I can get the issue described above where the gpio_trigger value comes out as zero.

    Does it look like I'm on the right track in terms of thinking the DETECT signal is what is causing the second reset (even though my code is in the middle of operating at the time of the second button press)?  And if so, is a software GPIO debounce at the very start of my code, where I just loop around until all the GPIOs have returned to their non-trigger state, the best approach to resolving it?

    Cheers,

    Mike

  • Hi MIke

    We already have a good discussion on how to implement debouncing to GPIOs in your application in this thread that should be helpful. There is a "verified answer" with a code snippet shoing how/where you can add the debounce. As for the multiple button issue. Does just any button in your design wake the device from System OFF mode, and is that why you need the debounce on multiple buttons?

    As for your confusion between the GPIO functions in your previous answer I'm not sure how to explain it better than the descriptions of the functions themselves.

    nrf_gpio_cfg_input: "Function for configuring the given GPIO pin number as input, hiding inner details. This function can be used to configure a pin as simple input."

    gpio_pin_configure_dt: "Configure a single pin from a @p gpio_dt_spec and some extra flags. This is equivalent to: gpio_pin_configure(spec->port, spec->pin, spec->dt_flags | extra_flags);
    Best regards,
    Simon
  • Hi Simon,

    Thanks for the link.  Seems pretty straight forward.

    I still think there is something else going on.  To test this, I put a simple 1 sec delay (using kmsleep() ) at the very start of my code, and then a similar 1 second delay just prior to my code going back into System OFF.

    This is the behaviour I see:

    Press one of the buttons to bring it out of System OFF mode - it will succesfully detect that a GPIO caused the exit (as indicated by RESETREAS), and will successfully detect which button was pressed (via LATCH).  It will then go back into System OFF mode

    Press one of the buttons to bring it out of System OFF mode, then within 0.5 sec (effectively whilst its still in its waiting mode), press the same button a second time - it will successfully detect that a GPIO caused the exit (as indicated by RESETEREAS) but it no longer is able to detect what button was pressed (via LATCH).  The result for LATCH = 0 in this case, which means I've got a scenario where my code has detected a GPIO has caused the exit from System OFF, but it can't tell which button has caused it.  In this scenario, my code then just goes back into System OFF, and doesn't update any of my counters.

    I'm using buttons in my testing, but ultimately the GPIO's will be triggered via an external signal.  I will have three GPIO's, corresponding to a "Small", "Medium" or "Large" level on the external signal.  These signals are very transient (will only be present for a few tens of milliseconds) and with the behaviour I am seeing at the moment, if I get two external signals within a short period of time, rather than detecting the first and ignoring any subsequent ones (what I would prefer) its essentially not correctly detecting any of them.  And that's what I'm trying to sort out.

    In my limited understanding, I think its something to do with the way the DETECT signal works.  And I've been trying to disable the GPIO from impacting the DETECT signal at the start of my code, via a call to:

    nrf_gpio_cfg_sense_input(pin, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_NOSENSE);

    But this isn't achieving what I want, so perhaps there is another way?

    So, what I want to be able to do the moment my code exits System OFF is:

    1. Check the value of RESETREAS

    2. Check the value of LATCH

    3. Disable any GPIO from triggering anything

    4. Process my counters based on the values of RESETREAS and LATCH

    5. Re-enable GPIO's to allow exit from System OFF

    6. Enter System OFF

    Its step 3 that I seem to be unable to achieve

    Cheers,

    Mike

Related