MSPM0G3507: Rising and falling GPIO interrupt is periodically missing an edge interrupt

Part Number: MSPM0G3507


I have a GPIO input (PB7) on my LP-MSPM0G3507 development board that I'm using as a manually controlled chip select input for a SPI bus. I've configured PB7 to interrupt on both rising (deselected) and falling (selected) edges. This works almost all of the time, but I keep running into a scenario where the falling edge interrupt fires when I read DL_Interrupt_getPendingGroup(DL_INTERRUPT_GROUP_1) in the Group1 ISR I correctly get DL_INTERRUPT_GROUP1_IIDX_GPIOB. Then when I read DL_GPIO_getPendingInterrupt(GPIOB) to get the pin that generated the interrupt I sometimes read GPIO_CPU_INT_IIDX_STAT_NO_INTR. However, capturing the signal, the GROUP1 PortB interrupt is correctly firing, but indicating NO_INTR instead of GPIO_CPU_INT_IIDX_STAT_DIO7?

image.png

In this capture, you can see the first circled CS_INT trace pulse twice for the two CS edges. In the next circled CS_INT trace, the CS_INT trace pulses twice too, but the second is being reported as NO_INT by DL_GPIO_getPendingInterrupt(GPIOB). CS_INT is set on Group1 ISR entry and cleared on Group1 ISR exit and the CS pulses are ~10uS. This behavior is inconsistently happening, but always happens eventually.

Here's my Group1 interrupt handler:

#if defined(__TI_COMPILER_VERSION__)
__attribute__((interrupt, fully_populate_jump_tables))
#endif
void GROUP1_IRQHandler(void)
{
  static mspm0_irq_f foundCallback;
  static uint32_t pin;
  static int32_t groupIndex;
  static int32_t pinIndex;
  
  groupIndex = DL_Interrupt_getPendingGroup(DL_INTERRUPT_GROUP_1);
  switch(groupIndex)
  {
    case DL_INTERRUPT_GROUP1_IIDX_GPIOA:
      switch (DL_GPIO_getPendingInterrupt(GPIOA))
      {
        case DL_GPIO_IIDX_DIO0:
          foundCallback = callbacks[MSPM0_SIGNAL_PA0];
          pin = DL_GPIO_PIN_0;
          break;
        case DL_GPIO_IIDX_DIO1:
          foundCallback = callbacks[MSPM0_SIGNAL_PA1];
          pin = DL_GPIO_PIN_1;
          break;
        case DL_GPIO_IIDX_DIO2:
          foundCallback = callbacks[MSPM0_SIGNAL_PA2];
          pin = DL_GPIO_PIN_2;
          break;
        case DL_GPIO_IIDX_DIO3:
          foundCallback = callbacks[MSPM0_SIGNAL_PA3];
          pin = DL_GPIO_PIN_3;
          break;
        case DL_GPIO_IIDX_DIO4:
          foundCallback = callbacks[MSPM0_SIGNAL_PA4];
          pin = DL_GPIO_PIN_4;
          break;
        case DL_GPIO_IIDX_DIO5:
          foundCallback = callbacks[MSPM0_SIGNAL_PA5];
          pin = DL_GPIO_PIN_5;
          break;
        case DL_GPIO_IIDX_DIO6:
          foundCallback = callbacks[MSPM0_SIGNAL_PA6];
          pin = DL_GPIO_PIN_6;
          break;
        case DL_GPIO_IIDX_DIO7:
          foundCallback = callbacks[MSPM0_SIGNAL_PA7];
          pin = DL_GPIO_PIN_7;
          break;
        case DL_GPIO_IIDX_DIO8:
          foundCallback = callbacks[MSPM0_SIGNAL_PA8];
          pin = DL_GPIO_PIN_8;
          break;
        case DL_GPIO_IIDX_DIO9:
          foundCallback = callbacks[MSPM0_SIGNAL_PA9];
          pin = DL_GPIO_PIN_9;
          break;
        case DL_GPIO_IIDX_DIO10:
          foundCallback = callbacks[MSPM0_SIGNAL_PA10];
          pin = DL_GPIO_PIN_10;
          break;
        case DL_GPIO_IIDX_DIO11:
          foundCallback = callbacks[MSPM0_SIGNAL_PA11];
          pin = DL_GPIO_PIN_11;
          break;
        case DL_GPIO_IIDX_DIO12:
          foundCallback = callbacks[MSPM0_SIGNAL_PA12];
          pin = DL_GPIO_PIN_12;
          break;
        case DL_GPIO_IIDX_DIO13:
          foundCallback = callbacks[MSPM0_SIGNAL_PA13];
          pin = DL_GPIO_PIN_13;
          break;
        case DL_GPIO_IIDX_DIO14:
          foundCallback = callbacks[MSPM0_SIGNAL_PA14];
          pin = DL_GPIO_PIN_14;
          break;
        case DL_GPIO_IIDX_DIO15:
          foundCallback = callbacks[MSPM0_SIGNAL_PA15];
          pin = DL_GPIO_PIN_15;
          break;
        case DL_GPIO_IIDX_DIO16:
          foundCallback = callbacks[MSPM0_SIGNAL_PA16];
          pin = DL_GPIO_PIN_16;
          break;
        case DL_GPIO_IIDX_DIO17:
          foundCallback = callbacks[MSPM0_SIGNAL_PA17];
          pin = DL_GPIO_PIN_17;
          break;
        case DL_GPIO_IIDX_DIO18:
          foundCallback = callbacks[MSPM0_SIGNAL_PA18];
          pin = DL_GPIO_PIN_18;
          break;
        case DL_GPIO_IIDX_DIO19:
          foundCallback = callbacks[MSPM0_SIGNAL_PA19];
          pin = DL_GPIO_PIN_19;
          break;
        case DL_GPIO_IIDX_DIO20:
          foundCallback = callbacks[MSPM0_SIGNAL_PA20];
          pin = DL_GPIO_PIN_20;
          break;
        case DL_GPIO_IIDX_DIO21:
          foundCallback = callbacks[MSPM0_SIGNAL_PA21];
          pin = DL_GPIO_PIN_21;
          break;
        case DL_GPIO_IIDX_DIO22:
          foundCallback = callbacks[MSPM0_SIGNAL_PA22];
          pin = DL_GPIO_PIN_22;
          break;
        case DL_GPIO_IIDX_DIO23:
          foundCallback = callbacks[MSPM0_SIGNAL_PA23];
          pin = DL_GPIO_PIN_23;
          break;
        case DL_GPIO_IIDX_DIO24:
          foundCallback = callbacks[MSPM0_SIGNAL_PA24];
          pin = DL_GPIO_PIN_24;
          break;
        case DL_GPIO_IIDX_DIO25:
          foundCallback = callbacks[MSPM0_SIGNAL_PA25];
          pin = DL_GPIO_PIN_25;
          break;
        case DL_GPIO_IIDX_DIO26:
          foundCallback = callbacks[MSPM0_SIGNAL_PA26];
          pin = DL_GPIO_PIN_26;
          break;
        case DL_GPIO_IIDX_DIO27:
          foundCallback = callbacks[MSPM0_SIGNAL_PA27];
          pin = DL_GPIO_PIN_27;
          break;
        case DL_GPIO_IIDX_DIO28:
          foundCallback = callbacks[MSPM0_SIGNAL_PA28];
          pin = DL_GPIO_PIN_28;
          break;
        case DL_GPIO_IIDX_DIO29:
          foundCallback = callbacks[MSPM0_SIGNAL_PA29];
          pin = DL_GPIO_PIN_29;
          break;
        case DL_GPIO_IIDX_DIO30:
          foundCallback = callbacks[MSPM0_SIGNAL_PA30];
          pin = DL_GPIO_PIN_30;
          break;
        case DL_GPIO_IIDX_DIO31:
          foundCallback = callbacks[MSPM0_SIGNAL_PA31];
          pin = DL_GPIO_PIN_31;
          break;
        default:
          //@todo Anything to do with this? Probably should report it
          foundCallback = NULL;
          break;
      }
      DL_GPIO_clearInterruptStatus(GPIOA, pin);
      break;
    case DL_INTERRUPT_GROUP1_IIDX_GPIOB:
      pinIndex = DL_GPIO_getPendingInterrupt(GPIOB);
      switch(pinIndex)
      {
        case DL_GPIO_IIDX_DIO0:
          foundCallback = callbacks[MSPM0_SIGNAL_PB0];
          pin = DL_GPIO_PIN_0;
          break;
        case DL_GPIO_IIDX_DIO1:
          foundCallback = callbacks[MSPM0_SIGNAL_PB1];
          pin = DL_GPIO_PIN_1;
          break;
        case DL_GPIO_IIDX_DIO2:
          foundCallback = callbacks[MSPM0_SIGNAL_PB2];
          pin = DL_GPIO_PIN_2;
          break;
        case DL_GPIO_IIDX_DIO3:
          foundCallback = callbacks[MSPM0_SIGNAL_PB3];
          pin = DL_GPIO_PIN_3;
          break;
        case DL_GPIO_IIDX_DIO4:
          foundCallback = callbacks[MSPM0_SIGNAL_PB4];
          pin = DL_GPIO_PIN_4;
          break;
        case DL_GPIO_IIDX_DIO5:
          foundCallback = callbacks[MSPM0_SIGNAL_PB5];
          pin = DL_GPIO_PIN_5;
          break;
        case DL_GPIO_IIDX_DIO6:
          foundCallback = callbacks[MSPM0_SIGNAL_PB6];
          pin = DL_GPIO_PIN_6;
          break;
        case DL_GPIO_IIDX_DIO7:
          foundCallback = callbacks[MSPM0_SIGNAL_PB7];
          pin = DL_GPIO_PIN_7;
          break;
        case DL_GPIO_IIDX_DIO8:
          foundCallback = callbacks[MSPM0_SIGNAL_PB8];
          pin = DL_GPIO_PIN_8;
          break;
        case DL_GPIO_IIDX_DIO9:
          foundCallback = callbacks[MSPM0_SIGNAL_PB9];
          pin = DL_GPIO_PIN_9;
          break;
        case DL_GPIO_IIDX_DIO10:
          foundCallback = callbacks[MSPM0_SIGNAL_PB10];
          pin = DL_GPIO_PIN_10;
          break;
        case DL_GPIO_IIDX_DIO11:
          foundCallback = callbacks[MSPM0_SIGNAL_PB11];
          pin = DL_GPIO_PIN_11;
          break;
        case DL_GPIO_IIDX_DIO12:
          foundCallback = callbacks[MSPM0_SIGNAL_PB12];
          pin = DL_GPIO_PIN_12;
          break;
        case DL_GPIO_IIDX_DIO13:
          foundCallback = callbacks[MSPM0_SIGNAL_PB13];
          pin = DL_GPIO_PIN_13;
          break;
        case DL_GPIO_IIDX_DIO14:
          foundCallback = callbacks[MSPM0_SIGNAL_PB14];
          pin = DL_GPIO_PIN_14;
          break;
        case DL_GPIO_IIDX_DIO15:
          foundCallback = callbacks[MSPM0_SIGNAL_PB15];
          pin = DL_GPIO_PIN_15;
          break;
        case DL_GPIO_IIDX_DIO16:
          foundCallback = callbacks[MSPM0_SIGNAL_PB16];
          pin = DL_GPIO_PIN_16;
          break;
        case DL_GPIO_IIDX_DIO17:
          foundCallback = callbacks[MSPM0_SIGNAL_PB17];
          pin = DL_GPIO_PIN_17;
          break;
        case DL_GPIO_IIDX_DIO18:
          foundCallback = callbacks[MSPM0_SIGNAL_PB18];
          pin = DL_GPIO_PIN_18;
          break;
        case DL_GPIO_IIDX_DIO19:
          foundCallback = callbacks[MSPM0_SIGNAL_PB19];
          pin = DL_GPIO_PIN_19;
          break;
        case DL_GPIO_IIDX_DIO20:
          foundCallback = callbacks[MSPM0_SIGNAL_PB20];
          pin = DL_GPIO_PIN_20;
          break;
        case DL_GPIO_IIDX_DIO21:
          foundCallback = callbacks[MSPM0_SIGNAL_PB21];
          pin = DL_GPIO_PIN_21;
          break;
        case DL_GPIO_IIDX_DIO22:
          foundCallback = callbacks[MSPM0_SIGNAL_PB22];
          pin = DL_GPIO_PIN_22;
          break;
        case DL_GPIO_IIDX_DIO23:
          foundCallback = callbacks[MSPM0_SIGNAL_PB23];
          pin = DL_GPIO_PIN_23;
          break;
        case DL_GPIO_IIDX_DIO24:
          foundCallback = callbacks[MSPM0_SIGNAL_PB24];
          pin = DL_GPIO_PIN_24;
          break;
        case DL_GPIO_IIDX_DIO25:
          foundCallback = callbacks[MSPM0_SIGNAL_PB25];
          pin = DL_GPIO_PIN_25;
          break;
        case DL_GPIO_IIDX_DIO26:
          foundCallback = callbacks[MSPM0_SIGNAL_PB26];
          pin = DL_GPIO_PIN_26;
          break;
        case DL_GPIO_IIDX_DIO27:
          foundCallback = callbacks[MSPM0_SIGNAL_PB27];
          pin = DL_GPIO_PIN_27;
          break;
        case DL_GPIO_IIDX_DIO28:
          foundCallback = callbacks[MSPM0_SIGNAL_PB28];
          pin = DL_GPIO_PIN_28;
          break;
        case DL_GPIO_IIDX_DIO29:
          foundCallback = callbacks[MSPM0_SIGNAL_PB29];
          pin = DL_GPIO_PIN_29;
          break;
        case DL_GPIO_IIDX_DIO30:
          foundCallback = callbacks[MSPM0_SIGNAL_PB30];
          pin = DL_GPIO_PIN_30;
          break;
        case DL_GPIO_IIDX_DIO31:
          foundCallback = callbacks[MSPM0_SIGNAL_PB31];
          pin = DL_GPIO_PIN_31;
          break;
        default:
          //@todo Anything to do with this? Probably should report it
          foundCallback = NULL;
          break;
      }
      DL_GPIO_clearInterruptStatus(GPIOB, pin);
      break;
    default:
      foundCallback = NULL;
      break;
  }
  
  if(foundCallback != NULL)
  {
    foundCallback();
  }
}
  • pinIndex = DL_GPIO_getPendingInterrupt(GPIOB);

    [...]

    DL_GPIO_clearInterruptStatus(GPIOB, pin);

    getPendingInterrupt() reads the IIDX register, which clears the RIS bit for the relevant interrupt. clearInterruptStatus() explicitly clears the RIS bit (already cleared), which sets up a race where it could clear the Next interrupt instead.

    I recommend you remove the DL_GPIO_clearInterruptStatus() call(s).

  • That was it. Thank you, Bruce!