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
  • Hi Nordic team ! This issue is showstopper for me too. I have been successfully using the following IRQ handler for long time.

    void GPIOTE_IRQHandler(void) {
    uint8_t  i,j;
    uint32_t pins_state = 0;
    uint32_t sense_set = 0;
    
    // Clear event.
    NRF_GPIOTE->EVENTS_PORT = 0;
    
    do{
    	pins_state = NRF_GPIO->IN;
    	// Check all users.
    	for (i = 0; i < m_user_count; i++)
    	{
    		gpiote_user_t * p_user = &mp_users[i];
    
    		// Check if user is enabled.
    		if (((1 << i) & m_enabled_users_mask) != 0)
    		{
    			uint32_t transition_pins;
    			uint32_t event_low_to_high;
    			uint32_t event_high_to_low;
    
    			// Find set of pins on which there has been a transition.
    			transition_pins = (pins_state ^ p_user->last_state_pins) & p_user->pins_mask;
    			p_user->last_state_pins = pins_state;
    
    			// if there is no changes for this user, look for next user
    			if( !transition_pins )
    				continue;
    
    			// Mark the IO pins which sense needs to be set again
    			sense_set |= p_user->pins_mask;
    			pins_sense_disable( i );
    
    			// Toggle SENSE level for all pins that have changed state.
    			// not needed anymore, as the sense will be set according to the pins_state
    			//sense_level_toggle(p_user, transition_pins);
    
    			// Call user event handler if an event has occurred.
    			event_high_to_low = (~pins_state & p_user->pins_high_to_low_mask) & transition_pins;
    			event_low_to_high = (pins_state & p_user->pins_low_to_high_mask) & transition_pins;
    
    			p_user->event_handler(event_low_to_high, event_high_to_low);
    		}
    	}
    }while( pins_state ^ NRF_GPIO->IN ); // loop until some pins have been changed in between
    
    // re-assign the sense states to the pins
    pins_sense_set( pins_state, sense_set );
    

    }

Reply
  • Hi Nordic team ! This issue is showstopper for me too. I have been successfully using the following IRQ handler for long time.

    void GPIOTE_IRQHandler(void) {
    uint8_t  i,j;
    uint32_t pins_state = 0;
    uint32_t sense_set = 0;
    
    // Clear event.
    NRF_GPIOTE->EVENTS_PORT = 0;
    
    do{
    	pins_state = NRF_GPIO->IN;
    	// Check all users.
    	for (i = 0; i < m_user_count; i++)
    	{
    		gpiote_user_t * p_user = &mp_users[i];
    
    		// Check if user is enabled.
    		if (((1 << i) & m_enabled_users_mask) != 0)
    		{
    			uint32_t transition_pins;
    			uint32_t event_low_to_high;
    			uint32_t event_high_to_low;
    
    			// Find set of pins on which there has been a transition.
    			transition_pins = (pins_state ^ p_user->last_state_pins) & p_user->pins_mask;
    			p_user->last_state_pins = pins_state;
    
    			// if there is no changes for this user, look for next user
    			if( !transition_pins )
    				continue;
    
    			// Mark the IO pins which sense needs to be set again
    			sense_set |= p_user->pins_mask;
    			pins_sense_disable( i );
    
    			// Toggle SENSE level for all pins that have changed state.
    			// not needed anymore, as the sense will be set according to the pins_state
    			//sense_level_toggle(p_user, transition_pins);
    
    			// Call user event handler if an event has occurred.
    			event_high_to_low = (~pins_state & p_user->pins_high_to_low_mask) & transition_pins;
    			event_low_to_high = (pins_state & p_user->pins_low_to_high_mask) & transition_pins;
    
    			p_user->event_handler(event_low_to_high, event_high_to_low);
    		}
    	}
    }while( pins_state ^ NRF_GPIO->IN ); // loop until some pins have been changed in between
    
    // re-assign the sense states to the pins
    pins_sense_set( pins_state, sense_set );
    

    }

Children
No Data
Related