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
  • Hi Elijah,

    You can set any GPIO pin in the CONFIG[n] register through the PSEL and PORT fields.

    Kind Regards,

    Priyanka

  • Hi Priyanka,

    Referring to my code in the configure_digital_pins_for_gpiote() function on line 95, you can see how I utilized the CONFIG register in the way you described. Unfortunately, the board freezes after a few 100 clock cycles with no other processes running. Is there an issue with the current way I have handled the interrupts?

    Thanks!

    Elijah

  • Hi Elijah,

    I am sorry but I do not understand the term "freezing". But this may be due to configuration problems. Did you configure the GPIO pins as input through the NRF_P1 registers as well? This is required before the pins can be used with the GPIOTE peripheral. It should look somrhting like this:

    You could check out the nrfx_gpiote driver, and see that they are reconfiguring GPIO through nrf_gpio HAL functions. Also, are you usinf the nrf5 SDK, NCS/Zephyr or Arduino? In case of nrf5 SDK, the priority 1 is used by it's softdevice and since you are using this for the GPIOTE interrupts, this could be a problem.

    -Priyanka

  • Hi Pryanka,

    I thought it possibly was, but I found no issues with my current configuration, but I will list it below for your benefit.

    I configure the GPIO Pins as follows:

    NRF_P0->PIN_CNF[11] = 0x0UL;
    NRF_P0->PIN_CNF[12] = 0x0UL;
    NRF_P0->PIN_CNF[15] = 0x0UL;
    NRF_P1->PIN_CNF[13] = 0x0UL;
    NRF_P1->PIN_CNF[14] = 0x0UL;
    NRF_P1->PIN_CNF[23] = 0x0UL;
    NRF_P1->PIN_CNF[21] = 0x0UL;
    NRF_P1->PIN_CNF[27] = 0x0UL;

    I perform this configuration prior to setting the GPIOTE registers. 

    Also, are you usinf the nrf5 SDK, NCS/Zephyr or Arduino?

    I am using Arduino (Arduino mbed source code located here: https://github.com/arduino/ArduinoCore-mbed). This may be causing the crashing, though I found no areas in the source to suggest there are conflicting issues with the GPIOTE and GPIO pins. The issue, it seems, rests in the interrupts.

Reply
  • Hi Pryanka,

    I thought it possibly was, but I found no issues with my current configuration, but I will list it below for your benefit.

    I configure the GPIO Pins as follows:

    NRF_P0->PIN_CNF[11] = 0x0UL;
    NRF_P0->PIN_CNF[12] = 0x0UL;
    NRF_P0->PIN_CNF[15] = 0x0UL;
    NRF_P1->PIN_CNF[13] = 0x0UL;
    NRF_P1->PIN_CNF[14] = 0x0UL;
    NRF_P1->PIN_CNF[23] = 0x0UL;
    NRF_P1->PIN_CNF[21] = 0x0UL;
    NRF_P1->PIN_CNF[27] = 0x0UL;

    I perform this configuration prior to setting the GPIOTE registers. 

    Also, are you usinf the nrf5 SDK, NCS/Zephyr or Arduino?

    I am using Arduino (Arduino mbed source code located here: https://github.com/arduino/ArduinoCore-mbed). This may be causing the crashing, though I found no areas in the source to suggest there are conflicting issues with the GPIOTE and GPIO pins. The issue, it seems, rests in the interrupts.

Children
  • Hi Elijah,

    I can see that you set the priority 1 to your GPIOTE , but as you can see from the GithHub page, the priority 1 is reserved for the SoftDevice and this might cause a problem. You can read more about interrupt priority levels too.

    -Priyanka

  • 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);
    }

Related