arduino / ArduinoCore-mbed

328 stars 191 forks source link

Seeking Clarification: GPIOTE IRQHandler Inquiry - Interrupts #373

Open ElijahBasile opened 2 years ago

ElijahBasile commented 2 years ago

Hello,

I noticed while working with the GPIOTE peripheral directly on the Arduino Nano 33 BLE through the NRF52840, there seems to be a conflict between the mbed OS and the peripheral's interrupts. I am seeking a clarification on why this may be the case, and if it is possible to utilize the GPIOTE peripheral on Arduino?

The below section of code (by itself) causes the Arduino Nano 33 BLE to freeze (likely a hardfault):

  // Enable GPIOTE Interrupts
  NRF_GPIOTE->INTENSET = 0x01 |
                         0x02 |
                         0x04 |
                         0x08 |
                         0x10 |
                         0x20 |
                         0x40 |
                         0x80;

The code above was also completed after configuring the GPIOTE LoToHi for pins D2-D9 (two below). I have tested with the configuration and without the configuration. The pin assignments were done with the following pin assignments (one below) followed the Arduino Nano 33 BLE schematic here: https://content.arduino.cc/assets/NANO33BLE_V2.0_sch.pdf

#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
  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);

The following lines I added below the above sections; however they do not have an impact on the crashing at the moment:

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

UPDATE 1:

I noticed another issue elsewhere where this coincides with attachInterrupt(). This may be helpful to establish some context. Issue: https://github.com/arduino/ArduinoCore-nRF528x-mbedos/issues/7 Proposed Fix: https://github.com/ohazi/ArduinoCore-nRF528x-mbedos Pull Request: https://github.com/arduino/ArduinoCore-nRF528x-mbedos/pull/10

UPDATE 2:

Additionally, is one places an NVIC_DisableIRQ() first (refer to code below). This will prevent the error; however, this still does not allow GPIOTE interrupt usage. Once the NVIC commands in the code block above are triggered after, the board freezes.

  NVIC_DisableIRQ( GPIOTE_IRQn ); 
  NVIC_ClearPendingIRQ( GPIOTE_IRQn );

  // Enable GPIOTE Interrupts
  NRF_GPIOTE->INTENSET = 0x01 |
                         0x02 |
                         0x04 |
                         0x08 |
                         0x10 |
                         0x20 |
                         0x40 |
                         0x80;

UPDATE 3:

I tried a workaround (triggering an interrupt instead through the EGU via a PPI/GPIOTE/EGU linkage) with similar results unfortunately. Below is my implementation. When the EGU3's interrupt is enabled, this causes the Arduino Nano 33 BLE to stall/freeze. The last function is called in setup and promptly causes the system to freeze (tested with Serial)

// Rising Edge Interrupt for GPIO (D2-9) Events
extern "C" void SWI3_IRQHandler_Custom() {
  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;
    CNN_OFF_IRQHandler();
  }
  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 Signaling
 */
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_SetVector(SWI3_IRQn, (uint32_t)&SWI3_IRQHandler_Custom);
  NVIC_SetPriority( SWI3_IRQn, 7UL );
  NVIC_EnableIRQ( SWI3_IRQn );

  while(1); // This is where the board will freeze - I verified using Serial output, but nothing is located here for simplicity.
}

void setup()
{
  Serial.begin(9600);

  configure_gpiote_for_events();
}
sheepfy commented 1 year ago

@ElijahBasile Hi I'm dealing with the same issue. I have a nordic DK with a jlink on it so I can run the debugger in VS Code tho. However, after few tries, I've manage to keep the nano 33 ble working buy setting manually registers as they were set in nordic DK. Here is a snippet:

int k = 0;

void setup()
{
    Serial.begin(9600);
    NVIC_DisableIRQ(TIMER1_IRQn);
    NVIC_DisableIRQ(TIMER2_IRQn);
    NVIC_DisableIRQ(TIMER3_IRQn);
    NVIC_DisableIRQ(TIMER4_IRQn);
    NVIC_DisableIRQ(GPIOTE_IRQn);
    NVIC_ClearPendingIRQ(GPIOTE_IRQn);
    NRF_GPIOTE->CONFIG[0] = 0x00031B01; // pin P0.27, toggle, event mode, port 0
    NRF_GPIOTE->INTENSET = 1UL;
    NVIC_EnableIRQ(GPIOTE_IRQn);
}

void loop()
{
    Serial.println(k);
}

extern "C" void GPIOTE_IRQHandler_v(void)
{
    for (int i = 0; i < 8; i++) {
        if (NRF_GPIOTE->EVENTS_IN[i] == 1) {
            NRF_GPIOTE->EVENTS_IN[i] = 0;
            k = i;
        }
    }
}

Problem is that if no pins are connected, board will keep going. However, if you change the state of pin P0.27, board will freeze.