This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

NRF51422 - GPIOTE PORT events stop being generated - why?

I am encountering a problem with GPIOTE PORT events on the NRF51422 in a custom design. The chip occasionally seems to be able to get into a state in which the registers are set up correctly for a PORT event and interrupt to be generated, but despite this no event occurs.

I have a pin which is connected to a push switch and external pullup resistor, which normally triggers various visible actions on the system. The symptom of the problem is that the system stops responding to the button.

If I hold the switch down when the problem is occuring and then halt the CPU, I can see in the debugger that:

  • PIN_CNF is set to input, connected, no pull, standard drive, sense low.
  • The IN register for the pin shows the input level as low.
  • The GPIOTE INTENSET register shows the PORT enable bit set.
  • EVENTS_PORT is zero.

If I set a breakpoint at the GPIOTE interrupt, then:

  • With the system working normally, the breakpoint is hit when the button is pressed and shows the registers in the state above, except that EVENTS_PORT reads 1, indicating the event has occured.

  • When the problem is occuring, the breakpoint is not hit, and if I halt the CPU I see the registers in the same state as above with EVENTS_PORT reading zero.

I can reproduce this problem on two copies of the board.

What could be preventing this event from being generated?

Parents
  • I believe I have now identified the race in the app_gpiote ISR which triggers this problem. It requires at least two pins to be involved. The sequence is as follows:

    1. Initially, pins A and B are both low, and are set to sense high. The DETECT signal and PORT event are both deasserted.

    2. Pin A goes high, the DETECT signal is asserted, and the PORT event bit is set.

    3. The GPIOTE ISR is triggered, and reads the IN register which shows A high and B low.

    4. Pin B goes high.

    5. The GPIOTE ISR sets Pin A to sense low, and B to sense high. Because B is already high, the DETECT signal remains asserted.

    The ISR is trying to force the DETECT signal to be deasserted by setting all the pin sense levels to the opposite of the current input. This can never be reliable because the input can always change between reading the IN register and writing the new SENSE settings.

    I believe the solution is to first set SENSE to disabled on all pins, before writing the new SENSE settings. This will force the DETECT signal to be deasserted. If the inputs have changed before the new SENSE settings are written, DETECT will be then re-asserted when the new settings are applied. This will trigger a new PORT event and the ISR will then be re-entered to deal with the new change.

    I will make this change to the app_gpiote ISR and see if it resolves the problem here. If so I will post a patch.

  • I agree on you line of thought, but when I'm testing this, I'm not able to generate a lockup, only losing the second interrupt. If I add a delay a in the IRQ handler between reading IN and toggling SENSE, and then toggle two pins with an interval b < a, I see that most often only the first toggle is detected.

    Have you been able to consistently get this to fail? If so, could you share the project you've been working with? Also, did you get anywhere with a workaround?

Reply
  • I agree on you line of thought, but when I'm testing this, I'm not able to generate a lockup, only losing the second interrupt. If I add a delay a in the IRQ handler between reading IN and toggling SENSE, and then toggle two pins with an interval b < a, I see that most often only the first toggle is detected.

    Have you been able to consistently get this to fail? If so, could you share the project you've been working with? Also, did you get anywhere with a workaround?

Children
No Data
Related