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
  • Here's a version of mine with some optimization:

    void GPIOTE_IRQHandler(void)
    {		
    uint8_t i;
    uint32_t pins_state = NRF_GPIO->IN;	//save current input state
    uint32_t triggered_pins = 0ul;			//save pins that actually generated IRQ
    uint8_t sense[NO_OF_PINS];					//save sense configuration
    
    //clear event
    NRF_GPIOTE->EVENTS_PORT = 0ul;
    
    // Backup and then disable all SENSE settings to ensure that DETECT signal is deasserted.
    // Check if pin value and sense agree and store it in triggered_pins
    for (i = 0; i < NO_OF_PINS; i++)
    {
    	//store sense value of each pin
    	sense[i] = (uint8_t) ( (NRF_GPIO->PIN_CNF[i] & GPIO_PIN_CNF_SENSE_Msk) >> GPIO_PIN_CNF_SENSE_Pos) );	
    	NRF_GPIO->PIN_CNF[i] &= ~GPIO_PIN_CNF_SENSE_Msk;		//disable sense field in pincnf
    	if ( (sense[i] == GPIO_PIN_CNF_SENSE_High) && ((pins_state & (1ul << i)) != 0) )	//sense high, pin high
    	{
    		triggered_pins |= (1u << i);		//flag current pin caused IRQ
    		sense[i] = GPIO_PIN_CNF_SENSE_Low;	//flip sense value (IRQ won't be recalled until pin changes value again
    	} else if ( (sense[i] == GPIO_PIN_CNF_SENSE_Low) && ((pins_state & (1ul << i)) == 0) )							//sense low, pin low
    	{
    		triggered_pins |= (1u << i);		//flag current pin caused IRQ
    		sense[i] = GPIO_PIN_CNF_SENSE_High;	//flip sense value
    	}
    }
    
    //***
    // here check if bits in triggered_pins are one of the ISRs you need, and compare it with pins_state for the transition you need
    // call related ISRs
    // i.e.
    // if ( triggered_pins & pins_state & (1ul << IRQpin) ) {dosmth} <- for lowtohi
    // if ( triggered_pins & ~pins_state & (1ul << IRQpin) ){dosmth} <- for hitolow
    //***
    
    // now restore modified sense values in PIN_CNF
    for (i = 0; i < NO_OF_PINS; i++)
     {
    	NRF_GPIO->PIN_CNF[i] |= (sense[i] << GPIO_PIN_CNF_SENSE_Pos);
     }
    
    }
    
Reply
  • Here's a version of mine with some optimization:

    void GPIOTE_IRQHandler(void)
    {		
    uint8_t i;
    uint32_t pins_state = NRF_GPIO->IN;	//save current input state
    uint32_t triggered_pins = 0ul;			//save pins that actually generated IRQ
    uint8_t sense[NO_OF_PINS];					//save sense configuration
    
    //clear event
    NRF_GPIOTE->EVENTS_PORT = 0ul;
    
    // Backup and then disable all SENSE settings to ensure that DETECT signal is deasserted.
    // Check if pin value and sense agree and store it in triggered_pins
    for (i = 0; i < NO_OF_PINS; i++)
    {
    	//store sense value of each pin
    	sense[i] = (uint8_t) ( (NRF_GPIO->PIN_CNF[i] & GPIO_PIN_CNF_SENSE_Msk) >> GPIO_PIN_CNF_SENSE_Pos) );	
    	NRF_GPIO->PIN_CNF[i] &= ~GPIO_PIN_CNF_SENSE_Msk;		//disable sense field in pincnf
    	if ( (sense[i] == GPIO_PIN_CNF_SENSE_High) && ((pins_state & (1ul << i)) != 0) )	//sense high, pin high
    	{
    		triggered_pins |= (1u << i);		//flag current pin caused IRQ
    		sense[i] = GPIO_PIN_CNF_SENSE_Low;	//flip sense value (IRQ won't be recalled until pin changes value again
    	} else if ( (sense[i] == GPIO_PIN_CNF_SENSE_Low) && ((pins_state & (1ul << i)) == 0) )							//sense low, pin low
    	{
    		triggered_pins |= (1u << i);		//flag current pin caused IRQ
    		sense[i] = GPIO_PIN_CNF_SENSE_High;	//flip sense value
    	}
    }
    
    //***
    // here check if bits in triggered_pins are one of the ISRs you need, and compare it with pins_state for the transition you need
    // call related ISRs
    // i.e.
    // if ( triggered_pins & pins_state & (1ul << IRQpin) ) {dosmth} <- for lowtohi
    // if ( triggered_pins & ~pins_state & (1ul << IRQpin) ){dosmth} <- for hitolow
    //***
    
    // now restore modified sense values in PIN_CNF
    for (i = 0; i < NO_OF_PINS; i++)
     {
    	NRF_GPIO->PIN_CNF[i] |= (sense[i] << GPIO_PIN_CNF_SENSE_Pos);
     }
    
    }
    
Children
No Data
Related