Using Interrupts with ARM Cortex M (with Ambiq Micro Apollo MCU software example)

The interrupt part of ARM Cortex M MCUs is described in CMSIS. The interrupt controller of ARM Cortex M MCUs is called NVIC. The NVIC is part of CMSIS and is decribed at the CMSIS website: https://www.keil.com/pack/doc/CMSIS/Core/html/group__NVIC__gr.html

In general ARM Cortex M based MCUs having two types of IRQs: Core peripheral IRQs and MCU peripheral IRQs. Core Peripherals are ARM Cortex M specific like SysTick and the Fault IRQs. MCU peripherals are peripherals provided by the MCU vendor like UART, Timers, etc.

Core Peripherals – SysTick

To initialize the SysTick core peripheral with the IRQ handle SysTick_Handler is pretty easy:

First of all the system clock must be updated to deliver the correct clock-speed in the global variable SystemCoreClock:

SystemCoreClockUpdate(); //update clock variable SystemCoreClock (defined by CMSIS)

Now the SysTick can be configured:

SysTick_Config(SystemCoreClock / 1000); //setup 1ms SysTick (defined by CMSIS)

The interrupt service routine looks like the following code:

static volatile uint32_t u32Counter; //ms counter

void SysTick_Handler(void)
{
     u32Counter++;
}

See also SysTick in CMSIS: https://www.keil.com/pack/doc/CMSIS/Core/html/group__SysTick__gr.html

MCU Peripherals – Ambiq Micro Apollo MCU external IRQ

For MCU peripherals the available IRQs are defined in the  typedef enum IRQn_Type in the MCU header file. For Ambiq Micro in the “apollo1.h” or “apollo2.h” header file. For example the GPIO interrupt handler of Apollo 1 can be found as “GPIO_IRQn”. The same way is the handler defined in the startup assembler or C file, but instead of IRQn the handler is named “Handler”.

Example:

GPIO_IRQn => GPIO_Handler

To initialize the interrrupt, first of all the peripheral must be configured and after that the NVIC (example GPIO0):

/* peripheral setup */
GPIO->INT0EN &= ~(1 << 0); //disable IRQ before configurating
GPIO->PADKEY = 0x00000073; //unlock GPIO setup
GPIO->PADREGA_b.PAD0FNCSEL = 0x3; //use as GPIO0
GPIO->PADREGA_b.PAD0INPEN = 1; //enable input

GPIO->CFGA_b.GPIO0INTD = 1; //set falling-edge
GPIO->CFGA_b.GPIO0INCFG = 1; //use as GPIO0 as input

GPIO->PADKEY = 0x00000000; //lock GPIO setup
GPIO->INT0EN |= (1 << 0); //enable IRQ in peripheral setup
//see also http://blog.io-expert.com/using-gpios-of-ambiq-micros-apollo1-and-apollo2-mcus

/* NVIC setup */
NVIC_ClearPendingIRQ(GPIO_IRQn); //clear pending flag
NVIC_EnableIRQ(GPIO_IRQn); //enable IRQ
NVIC_SetPriority(GPIO_IRQn,1); //set priority, smaller value means higher priority

At last the IRQ handler must be written:

void GPIO_IRQHandler(void)
{
    uint32_t u32Status;
    u32Status = GPIO->INT0STAT;
    if(u32Status & (1 << 0))
    {
        //do the IRQ handling here…
    }
    GPIO->INT0CLR = u32Status; //clear IRQ flags
}

Run the Code

The complete example is workable with MCU Templates for Apollo1 and Apollo2 from FEEU http://www.fujitsu.com/feeu or by contacting  FEEU directly info.feeu@de.fujitsu.com

See also MCU Templates

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.