GPIOTE on *Both* P0 & P1 GPIOs in NRF52840

Hello,

I would like to attach interrupts to the following pins on the P0 GPIO and the P1 GPIO:

P0:

  • 21
  • 23
  • 27

P1:

  • 11
  • 12
  • 13
  • 14
  • 15

However, it seems that there is only one GPIOTE instance on the NRF52840 (which corresponds to P0).

How would I go about attaching interrupts to the P1 pins?

To give you some background, I am developing on an Arduino Nano 33 BLE, and would like to have interrupts attached to pins on both GPIO instances through its NRF52840.

Right now, the calling the function: init_gpio_interrupts() causes the board to freeze a few 100 clock cycles later.

// Rising Edge Interrupt for GPIO (D2-9) Events
extern "C" void GPIOTE_IRQHandler_v() {
  if (NRF_GPIOTE->EVENTS_IN[0] == 1)
  {
    NRF_GPIOTE->EVENTS_IN[0] = 0;
    
    // Code Here
  }
  else if (NRF_GPIOTE->EVENTS_IN[1] == 1)
  {
    NRF_GPIOTE->EVENTS_IN[1] = 0;
    
    // Code Here
  }
  else if (NRF_GPIOTE->EVENTS_IN[2] == 1)
  {
    NRF_GPIOTE->EVENTS_IN[2] = 0;
    
    // Code Here
  }
  else if (NRF_GPIOTE->EVENTS_IN[3] == 1)
  {
    NRF_GPIOTE->EVENTS_IN[3] = 0;
    
    // Code Here
  }
  else if (NRF_GPIOTE->EVENTS_IN[4] == 1)
  {
    NRF_GPIOTE->EVENTS_IN[4] = 0;
    
    // Code Here
  }
  else if (NRF_GPIOTE->EVENTS_IN[5] == 1)
  {
    NRF_GPIOTE->EVENTS_IN[5] = 0;
    
    // Code Here
  }
  else if (NRF_GPIOTE->EVENTS_IN[6] == 1)
  {
    NRF_GPIOTE->EVENTS_IN[6] = 0;
    
    // Code Here
  }
  else if (NRF_GPIOTE->EVENTS_IN[7] == 1)
  {
    NRF_GPIOTE->EVENTS_IN[7] = 0;
    
    // Code Here
  }
}


#define GPIO_P0 0UL
#define GPIO_P1 1UL

#define D2_PIN_NUM 11UL
#define D3_PIN_NUM 12UL
#define D4_PIN_NUM 15UL
#define D5_PIN_NUM 13UL
#define D6_PIN_NUM 14UL
#define D7_PIN_NUM 23UL
#define D8_PIN_NUM 21UL
#define D9_PIN_NUM 27UL

constexpr uint32_t GPIOTE_PIN_NUMS[] = {D2_PIN_NUM, 
                                        D3_PIN_NUM, 
                                        D4_PIN_NUM, 
                                        D5_PIN_NUM, 
                                        D6_PIN_NUM, 
                                        D7_PIN_NUM, 
                                        D8_PIN_NUM, 
                                        D9_PIN_NUM};

constexpr uint32_t GPIOTE_PINS[] = {D2, 
                                    D3, 
                                    D4, 
                                    D5, 
                                    D6, 
                                    D7, 
                                    D8, 
                                    D9};

constexpr uint32_t NUM_GPIOTE_PINS = sizeof(GPIOTE_PINS) / sizeof(uint32_t);

enum NRF_GPIOTE_CONFIG_POS
{
  GPIOTE_CONFIG_MODE_POS     = 0UL,
  GPIOTE_CONFIG_PSEL_POS     = 8UL,
  GPIOTE_CONFIG_PORT_POS     = 13UL,
  GPIOTE_CONFIG_POLARITY_POS = 16UL,
  GPIOTE_CONFIG_OUTINIT_POS  = 20UL
};

void configure_digital_pins_for_gpiote()
{
  NRF_GPIOTE->CONFIG[0] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                          (D7_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                          (GPIO_P0                    << GPIOTE_CONFIG_PORT_POS)     |
                          (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);

  NRF_GPIOTE->CONFIG[1] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                          (D8_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                          (GPIO_P0                    << GPIOTE_CONFIG_PORT_POS)     |
                          (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
  
  NRF_GPIOTE->CONFIG[2] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                          (D9_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                          (GPIO_P0                    << GPIOTE_CONFIG_PORT_POS)     |
                          (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
                          
  NRF_GPIOTE->CONFIG[3] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                          (D2_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                          (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                          (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);

  NRF_GPIOTE->CONFIG[4] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                          (D3_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                          (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                          (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);

  NRF_GPIOTE->CONFIG[5] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                          (D4_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                          (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                          (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);

  NRF_GPIOTE->CONFIG[6] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                          (D5_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                          (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                          (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);

  NRF_GPIOTE->CONFIG[7] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                          (D6_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                          (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                          (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
}

void configure_gpiote_for_events()
{

  configure_digital_pins_for_gpiote();

  // Enable GPIOTE Interrupts
  nrf_gpiote_int_enable(NRF_GPIOTE_INT_IN0_MASK |
                        NRF_GPIOTE_INT_IN1_MASK |
                        NRF_GPIOTE_INT_IN2_MASK |
                        NRF_GPIOTE_INT_IN3_MASK |
                        NRF_GPIOTE_INT_IN4_MASK |
                        NRF_GPIOTE_INT_IN5_MASK |
                        NRF_GPIOTE_INT_IN6_MASK |
                        NRF_GPIOTE_INT_IN7_MASK);

  NVIC_SetVector(GPIOTE_IRQn, (uint32_t)&GPIOTE_IRQHandler_v);
  NVIC_SetPriority( GPIOTE_IRQn, 1UL );
  NVIC_EnableIRQ( GPIOTE_IRQn );
  
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///   
///   INITIALIZATION
///   
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void init_gpio_interrupts()
{
  init_event_buffer_ptrs();
  
  configure_gpiote_for_events();
}

Thanks!

Parents Reply Children
  • There seems to be a conflict with Arduino's mbed OS, and the GPIOTE interrupts. I have included a similar forum below for reference. 

    https://devzone.nordicsemi.com/f/nordic-q-a/82675/nrf_gpiote--intenset-1-crashes-with-gpiote_config_polarity_lotohi

    I opened an issue with Arduino mbed OS's github seeking some clarification in this area. I will keep Nordic updated.

    github.com/.../373

  • I may have come up with a solution; however, would like a quick clarification. Thank you very much Priyanka for your assistance.

    I would like to connect the GPIOTE "IN" Event to another interrupt handler through the EGU so that when a falling edge is detected on a configured pin, the interrupt is triggered. This way I can avoid the GPIOTE interrupts while still having a quick response on those pin changes. 

    Is that workaround possible, and how would I go about binding the two together?

    Thanks!

  • Hi Elijah,

    That looks like a good workaround and I guess this ticket could actually help you a lot with this. Thank you very much for letting us know Slight smile

    Regards,

    Priyanka

  • Hi Priyanka,

    Thanks for showing me that ticket. This is my current (nonworking) implementation. I will continue to investigate why the SWI0_EGU0_IRQHandler_v is not triggering when I start the "configure_gpiote_for_events()" function.

    I'll keep your team updated.

    // Rising Edge Interrupt for GPIO (D2-9) Events
    extern "C" void SWI3_IRQHandler_v() {
      pinMode(LEDG, OUTPUT);
      if (NRF_EGU3->EVENTS_TRIGGERED[0] == 1)
      {
        NRF_EGU3->EVENTS_TRIGGERED[0] = 0;
        
        // Code Here
      }
      else if (NRF_EGU3->EVENTS_TRIGGERED[1] == 1)
      {
        NRF_EGU3->EVENTS_TRIGGERED[1] = 0;
        
        // Code Here
      }
      else if (NRF_EGU3->EVENTS_TRIGGERED[2] == 1)
      {
        NRF_EGU3->EVENTS_TRIGGERED[2] = 0;
        
        // Code Here
      }
      else if (NRF_EGU3->EVENTS_TRIGGERED[3] == 1)
      {
        NRF_EGU3->EVENTS_TRIGGERED[3] = 0;
        
        // Code Here
      }
      else if (NRF_EGU3->EVENTS_TRIGGERED[4] == 1)
      {
        NRF_EGU3->EVENTS_TRIGGERED[4] = 0;
        
        // Code Here
      }
      else if (NRF_EGU3->EVENTS_TRIGGERED[5] == 1)
      {
        NRF_EGU3->EVENTS_TRIGGERED[5] = 0;
        
        // Code Here
      }
      else if (NRF_EGU3->EVENTS_TRIGGERED[6] == 1)
      {
        NRF_EGU3->EVENTS_TRIGGERED[6] = 0;
        
        // Code Here
      }
      else if (NRF_EGU3->EVENTS_TRIGGERED[7] == 1)
      {
        NRF_EGU3->EVENTS_TRIGGERED[7] = 0;
        
        // Code Here
      }
    }
    
    #define GPIO_P0 0UL
    #define GPIO_P1 1UL
    
    // P0
    #define D7_PIN_NUM 23UL
    #define D8_PIN_NUM 21UL
    #define D9_PIN_NUM 27UL
    
    // P1
    #define D2_PIN_NUM 11UL
    #define D3_PIN_NUM 12UL
    #define D4_PIN_NUM 15UL
    #define D5_PIN_NUM 13UL
    #define D6_PIN_NUM 14UL
    
    
    constexpr uint32_t GPIOTE_PINS[] = {D2, 
                                        D3, 
                                        D4, 
                                        D5, 
                                        D6, 
                                        D7, 
                                        D8, 
                                        D9};
    
    constexpr uint32_t NUM_GPIOTE_PINS = sizeof(GPIOTE_PINS) / sizeof(uint32_t);
    
    enum NRF_GPIOTE_CONFIG_POS
    {
      GPIOTE_CONFIG_MODE_POS     = 0UL,
      GPIOTE_CONFIG_PSEL_POS     = 8UL,
      GPIOTE_CONFIG_PORT_POS     = 13UL,
      GPIOTE_CONFIG_POLARITY_POS = 16UL,
      GPIOTE_CONFIG_OUTINIT_POS  = 20UL
    };
    
    /**
     * Configure the Digital Pins for input
     */
    void configure_digital_pins()
    {
      NRF_P0->PIN_CNF[23] = 0x0UL;
      NRF_P0->PIN_CNF[21] = 0x0UL;
      NRF_P0->PIN_CNF[27] = 0x0UL;
      
      NRF_P1->PIN_CNF[11] = 0x0UL;
      NRF_P1->PIN_CNF[12] = 0x0UL;
      NRF_P1->PIN_CNF[15] = 0x0UL;
      NRF_P1->PIN_CNF[13] = 0x0UL;
      NRF_P1->PIN_CNF[14] = 0x0UL;
    }
    
    /**
     * Configure the Digital Pins on the Nano 33 for GPIOTE Signalling
     */
    void configure_digital_pins_for_gpiote()
    {
      configure_digital_pins();
      
      NRF_GPIOTE->CONFIG[0] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                              (D7_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                              (GPIO_P0                    << GPIOTE_CONFIG_PORT_POS)     |
                              (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
    
      NRF_GPIOTE->CONFIG[1] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                              (D8_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                              (GPIO_P0                    << GPIOTE_CONFIG_PORT_POS)     |
                              (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
      
      NRF_GPIOTE->CONFIG[2] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                              (D9_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                              (GPIO_P0                    << GPIOTE_CONFIG_PORT_POS)     |
                              (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
                              
      NRF_GPIOTE->CONFIG[3] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                              (D2_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                              (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                              (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
    
      NRF_GPIOTE->CONFIG[4] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                              (D3_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                              (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                              (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
    
      NRF_GPIOTE->CONFIG[5] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                              (D4_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                              (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                              (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
    
      NRF_GPIOTE->CONFIG[6] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                              (D5_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                              (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                              (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
    
      NRF_GPIOTE->CONFIG[7] = (1UL                        << GPIOTE_CONFIG_MODE_POS)     |
                              (D6_PIN_NUM                 << GPIOTE_CONFIG_PSEL_POS)     |
                              (GPIO_P1                    << GPIOTE_CONFIG_PORT_POS)     |
                              (NRF_GPIOTE_POLARITY_LOTOHI << GPIOTE_CONFIG_POLARITY_POS);
    }
    
    /**
     * Configure the PPI for GPIOTE Events
     */
    void configure_ppi_for_gpiote()
    {
      NRF_PPI->CH[0].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[0];
      NRF_PPI->CH[0].TEP = (uint32_t)&NRF_EGU3->TASKS_TRIGGER[0];
    
      NRF_PPI->CH[1].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[1];
      NRF_PPI->CH[1].TEP = (uint32_t)&NRF_EGU3->TASKS_TRIGGER[1];
    
      NRF_PPI->CH[2].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[2];
      NRF_PPI->CH[2].TEP = (uint32_t)&NRF_EGU3->TASKS_TRIGGER[2];
    
      NRF_PPI->CH[3].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[3];
      NRF_PPI->CH[3].TEP = (uint32_t)&NRF_EGU3->TASKS_TRIGGER[3];
    
      NRF_PPI->CH[4].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[4];
      NRF_PPI->CH[4].TEP = (uint32_t)&NRF_EGU3->TASKS_TRIGGER[4];
    
      NRF_PPI->CH[5].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[5];
      NRF_PPI->CH[5].TEP = (uint32_t)&NRF_EGU3->TASKS_TRIGGER[5];
    
      NRF_PPI->CH[6].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[6];
      NRF_PPI->CH[6].TEP = (uint32_t)&NRF_EGU3->TASKS_TRIGGER[6];
    
      NRF_PPI->CH[7].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[7];
      NRF_PPI->CH[7].TEP = (uint32_t)&NRF_EGU3->TASKS_TRIGGER[7];
    
      NRF_PPI->CHENSET = 0x000000FFUL;
    }
    
    void configure_gpiote_for_events()
    {
    
      configure_digital_pins_for_gpiote();
    
      NVIC_DisableIRQ( SWI3_IRQn ); 
      NVIC_ClearPendingIRQ( SWI3_IRQn );
    
      configure_ppi_for_gpiote();
    
      NRF_EGU3->INTENSET = 0x000000FFUL;
      
      NVIC_SetPriority( SWI3_IRQn, 7UL );
      NVIC_EnableIRQ( SWI3_IRQn );
    
      while(1);
    }

  • Hi Priyanka,

    Unfortunately, after some testing, the workaround produced the same stalling issue once the EGU3 interrupt was enabled via the NVIC (refer to the code in previous reply for full implementation.) 

    As stated previously in another reply, I did contact the Arduino MBed OS team on their GitHub and am awaiting their reply. 

    I will keep Nordic in the loop. I have spoken to a few other individuals who are experiencing the same issue with this board, so hopefully there can be a resolution shortly.

Related