Use external interrupts in real-time capable applications

Azure Sphere supports the use of external interrupts in RTApps for the MT3620. On the MT3620 real-time cores, such interrupts do not use GPIO directly; instead, they are wired independently of GPIO. An RTApp can configure an external interrupt so that it can detect and respond to a signal on an external pin.

See the MT3620 M4 User Manual for information about the real-time cores on the MT3620. For additional information about register base addresses, interrupt numbers, and similar details, request the "MT3620 M4 Datasheet" from Avnet by emailing Azure.Sphere@avnet.com.

External interrupt requirements

To use an external interrupt in an RTApp on the MT3620:

  • Request the interrupt in the app_manifest.json file.
  • Write an interrupt handler that responds to the signal.
  • Initialize, configure, and enable the interrupt functionality.

Application manifest settings

To use an external interrupt, an RTApp must list it in the "ExternalInterrupt" field of the Capabilities section of the application manifest. Identify the interrupt by a string from EINT0 to EINT23. For example, the following line specifies external interrupt 8:

   "Capabilities": {
    "ExternalInterrupt": [ "EINT8"]
  }

External interrupts are multiplexed with GPIO in the same way as other peripherals, and the same rules apply regarding multiplexing. Your RTApp can use any EINT you prefer, provided that no other application (either high-level or RTApp) on the device uses a peripheral that maps to the same block. See I/O Peripherals for information about how peripheral interfaces are multiplexed.

If your Azure Sphere application scenario also includes an Ethernet shield, EINT4-EINT7 are unavailable to the RTApp, because the shield uses GPIO 5 (which maps to EINT5) in a high-level app, thus reserving all other pins within that block.

Interrupt handler

Your interrupt handler must have the same name as the requested interrupt in the vector table for the M4. See the Codethink Labs MT3620 M4 driver samples on GitHub for sample VectorTable.h and VectorTable.c files.

In the sample VectorTable.c file, the following entry in the vector table represents EINT8, which is pin 0 in block 3:

[INT(28)] = gpio_g2_irq0,

The corresponding interrupt handler in the sample is gpio_g2_irq0:

void gpio_g2_irq0(void)
{
    UART_Print(debug, "Interrupt handled.\r\n");
}

In the vector table for your own application, you can name the interrupt handler whatever you want.

Initialize, configure, and enable the interrupt

In the main() function of your RTApp, include code to initialize the vector table, configure the EINT control register for the interrupt, and enable the interrupt handler.

The Codethink driver samples define a VectorTableInit() function. You can adapt this initialization function to your requirements.

To configure the EINT control register, you'll need to initialize it as defined in the M4 Datasheet. For example, the following function initializes the block that contains a specified pin. The function defines all external interrupts with the register value 0x300, which enables debouncing and active-low interrupts.

#define MT3620_CM4_IRQ_DBNC_CNTRL_DEF 0x300

int32_t EINT_ConfigurePin(uint32_t pin)
{
    mt3620_gpio_block_e block = pinToBlock(pin);

    if ((block < MT3620_GPIO_BLOCK_0) || (block > MT3620_GPIO_BLOCK_5)) {
        return ERROR_EINT_NOT_A_PIN;
    }

    uint32_t pinMask  = getPinMask(pin, block);
    uint32_t eintBlock = block - MT3620_GPIO_BLOCK_0;

    switch(pinMask) {
        case 1:
            mt3620_cm4_irq[eintBlock]->cm4_dbnc_con0 = MT3620_CM4_IRQ_DBNC_CNTRL_DEF;
            break;
        case 2:
            mt3620_cm4_irq[eintBlock]->cm4_dbnc_con1 = MT3620_CM4_IRQ_DBNC_CNTRL_DEF;
            break;
        case 4:
            mt3620_cm4_irq[eintBlock]->cm4_dbnc_con2 = MT3620_CM4_IRQ_DBNC_CNTRL_DEF;
            break;
        case 8:
            mt3620_cm4_irq[eintBlock]->cm4_dbnc_con3 = MT3620_CM4_IRQ_DBNC_CNTRL_DEF;
            break;
        default:
            break;
    }

    return ERROR_NONE;
}

An app can call this function as follows:

if (EINT_ConfigurePin(8) != ERROR_NONE) {
    UART_Print(debug, "ERROR: EINT initialization failed\r\n");
}

Finally, the app must enable the interrupt; this example uses the NVIC_Enable function from the Codethink driver samples:

NVIC_EnableIRQ(28, 2);

External interrupt API and sample code

In addition to the general example code from Codethink Labs, you can find a driver API and corresponding documentation from MediaTek.