4. Handling Multiple Interruption Sources

4.1. Latching the Interrupt Source

If your application is required to handle multiple event sources, the wake-up handler will need to be aware of the source of the interrupt. This can be done by utilizing the GPIO sub block of the Wake-Up Timer.

4.2. Configuring Additional Sources

For this example, we will configure the K1 push button of Pro DevKit as well as the P0_24 pin as two possible sources of events. In addition, the appropriate PDC LUT events should be registered so that the ARM Cortex M33 can wake up following an event on these specific pins. Please note that during a sleep cycle the M33 is completely turned off. In main.c file, replace the prvSetupHardware routine with the following code:

/**
 * @brief Hardware Initialization
 */
static void prvSetupHardware(void)
{


        /*
         * Add a PDC LUT entry so that to wake up the M33 core following an event on PORT0
         * This is important since M33 is turned off when the device enters sleep.
         */
        uint32_t pdc_wkup_gpio_id_1 = hw_pdc_add_entry(HW_PDC_LUT_ENTRY_VAL(KEY1_PORT,
                                                     KEY1_PIN, HW_PDC_MASTER_CM33, 0));
        OS_ASSERT(pdc_wkup_gpio_id_1 != HW_PDC_INVALID_LUT_INDEX);

        /* Do the trick! */
        hw_pdc_set_pending(pdc_wkup_gpio_id_1);
        hw_pdc_acknowledge(pdc_wkup_gpio_id_1);


        /*
         * Add a PDC LUT entry so that to wake up the M33 core following an event on PORT0
         * This is important since M33 is turned off when the device enters sleep.
         */
        uint32_t pdc_wkup_gpio_id_2 = hw_pdc_add_entry(HW_PDC_LUT_ENTRY_VAL(KEY1_PORT,
                                                  TRIGGER_PIN, HW_PDC_MASTER_CM33, 0));
        OS_ASSERT(pdc_wkup_gpio_id_2 != HW_PDC_INVALID_LUT_INDEX);

        /* Do the trick! */
        hw_pdc_set_pending(pdc_wkup_gpio_id_2);
        hw_pdc_acknowledge(pdc_wkup_gpio_id_2);



        /* Init hardware */
        pm_system_init(periph_init);


        /* Enable the COM power domain before handling any GPIO pin */
        hw_sys_pd_com_enable();

        /* Configure the KEY1 push button on Pro DevKit */
        HW_GPIO_SET_PIN_FUNCTION(KEY1);
        HW_GPIO_PAD_LATCH_ENABLE(KEY1); /* Lock pin's mode */

        /* Lock the mode of the target GPIO pin */
        HW_GPIO_PAD_LATCH_DISABLE(KEY1);

        /* Configure a 2nd GPIO pin on Pro DevKit */
        hw_gpio_set_pin_function(KEY1_PORT, TRIGGER_PIN, HW_GPIO_MODE_INPUT_PULLUP,
                                                                  HW_GPIO_FUNC_GPIO);
        hw_gpio_pad_latch_enable (KEY1_PORT, TRIGGER_PIN);
        hw_gpio_pad_latch_disable(KEY1_PORT, TRIGGER_PIN); /* Lock pin's mode */

        /* Disable the COM power domain after handling the GPIO pins */
        hw_sys_pd_com_disable();
}

Then we configure the Wake-up Timer block. Please note that the GPIO sub block does not incorporate a debounce circuitry.

/* Initialize the WKUP controller */
static void wkup_init(void)
{

        /* Initialize the WKUP controller */
        hw_wkup_init(NULL);


        /*
         * Enable interrupts produced by the GPIO block of the wakeup controller
         *(non-debounce circuitry) and register a callback function to hit
         * following a GPIO event.
         */
        hw_wkup_register_gpio_p0_interrupt(button_interrupt_cb, 1);


        /*
         * Set the polarity (rising/falling edge) that triggers the WKUP controller.
         *
         * \note The polarity is applied both to KEY and GPIO blocks of the controller
         *
         */
        hw_wkup_gpio_configure_pin(KEY1_PORT, KEY1_PIN, 1, HW_WKUP_PIN_STATE_LOW);
        hw_wkup_gpio_configure_pin(KEY1_PORT, TRIGGER_PIN, 1, HW_WKUP_PIN_STATE_LOW);


        /* Enable interrupts of WKUP controller */
        hw_wkup_enable_irq();
}

4.3. Handling the Interrupt

When an interrupt occurs, it is now necessary to check the source of the interrupt. This is done by calling hw_wkup_get_status(). It is also necessary, since the input is latched, to clear the pin from the latch register. The interrupt handler registered will become:

void button_interrupt_cb(void)
{
        /* This is important!!! */
        hw_wkup_reset_interrupt();

        uint32_t status;

        /* Read the status of PORT0 */
        status = hw_wkup_get_status(KEY1_PORT);

        /* Check the status of POTR0 */
        if (status & (1 << KEY1_PIN)) {
                /* Notify the main task */
                OS_TASK_NOTIFY_FROM_ISR(task_h, 0x1, OS_NOTIFY_SET_BITS);

                /* Clear the latch status */
                hw_wkup_clear_status(KEY1_PORT, (1 << KEY1_PIN));
                /* Check the status of POTR0 */
        } else if (status & (1 << TRIGGER_PIN)) {
                /* Notify the main task */
                OS_TASK_NOTIFY_FROM_ISR(task_h, 0x2, OS_NOTIFY_SET_BITS);

                /* Clear the latch status */
                hw_wkup_clear_status(KEY1_PORT, (1 << TRIGGER_PIN));
        }
}

Now the application can verify the different notification events and act accordingly. In main.c file, replace the prvTemplateTask application task with the following code:

#include "hw_wkup.h"
#include "hw_pdc.h"


#define TRIGGER_PIN   HW_GPIO_PIN_24


/**
 * @brief Template task increases a counter every mainCOUNTER_FREQUENCY_MS ms
 */
static void prvTemplateTask( void *pvParameters )
{
        uint32_t ulNotifiedValue;

        wkup_init();

        printf("\n\rDemo\n\r");

        for( ;; ) {

                     /* Wait for the external interruption notification */
                     OS_TASK_NOTIFY_WAIT(0x0, OS_TASK_NOTIFY_ALL_BITS,
                                             &ulNotifiedValue, OS_TASK_NOTIFY_FOREVER);

                     /* Check the notification is button 1 */
                      if(ulNotifiedValue & 0x1){
                              /* Send the character on the UART */
                             printf("#");
                             fflush(stdout);
                     /* Check the notification is button 2 */
                     } else if(ulNotifiedValue & 0x2) {
                             /* Send the character on the UART */
                            printf("$");
                            fflush(stdout);

                     }
             }
}

This example results in different characters being sent depending on the button pressed, as depicted in Figure 3

_images/multiple_interrupt.png

Figure 3 Multiple Interrupt Sources