The Cortex-M0 processor supports advanced interrupt handling and wakeup capabilities to enable low-power and efficient embedded applications. This article provides a comprehensive overview of the interrupt and wakeup features of the Cortex-M0, explaining how they work and how to utilize them effectively.
Cortex-M0 Interrupt System
The Cortex-M0 implements an advanced nested vectored interrupt controller (NVIC) to manage interrupts from peripheral devices and system exceptions. Key aspects of the Cortex-M0 interrupt system include:
- 32 vectored exception entries for handling standard exceptions like resets, faults, and interrupts.
- Flexible priority scheme with up to 32 priority levels for interrupts.
- Low latency exception handling using a vectored exception model.
- Hardware stacking to allow nested exceptions.
- Configurable tail-chaining of exception handlers.
- Wakeup from sleep on interrupt mechanism.
The NVIC unit handles prioritization and dispatching of exceptions. When an exception occurs, the processor automatically stacks its context and jumps to the corresponding vector in the vector table. This table contains handler addresses for each exception source. The NVIC allows assigning a priority level of 0-31 to each interrupt, with 0 being highest priority. Higher priority interrupts can preempt lower priority handlers.
Cortex-M0 Exception Types
The Cortex-M0 supports the following types of exceptions:
- Resets – Caused by power-on reset, external reset pin, watchdog reset, etc. Resets force the CPU to a known good state.
- NMI – Non-maskable interrupt caused by critical system exceptions. Cannot be ignored.
- Hard fault – For reporting fatal hardware errors.
- SVC – For handling supervisor calls from threads.
- PendSV – Triggered by software to force a context switch.
- SysTick – 24-bit system timer that generates periodic interrupts.
- External interrupts – Generated by external peripheral modules connected to the Cortex-M0.
The first entries in the vector table (addresses 0x0-0x1C) are reserved for handling these standard exceptions. The remaining space is available for device-specific external interrupts.
Interrupt Handling Process
Here are the typical steps involved when handling an interrupt on Cortex-M0:
- Interrupt signal received by the NVIC from a peripheral or exception source.
- NVIC suspends the currently running process and saves its context.
- Exception handler address fetched from corresponding vector table entry.
- Code execution jumps to the handler function.
- Handler runs to completion and issues an exception return command.
- Context restored and previous application continues executing.
The entire process occurs very quickly, resulting in minimum interrupt latency. Tail-chaining can further accelerate it by eliminating context saving for certain exceptions.
Defining Interrupt Handlers
Interrupt handlers can be defined in C/C++ or assembly language. A typical handler written in C takes the following form: void TIMER0_IRQHandler(void) { // Clear timer interrupt flag // Handler code }
The handler function name matches the corresponding entry in the vector table. Compiler intrinsics or assembly instructions are used to clear the source interrupt flag. Any context saving, if needed, is also done here.
Prioritizing Interrupts
The NVIC supports up to 32 interrupt priority levels, with 0 being the highest and 31 the lowest. Priority is split between preemption priority (high 4 bits) and subpriority (low 4 bits). The full 8-bit priority register combines both parts to derive the composite priority.
Preemption priority determines the exception preemption behavior. Subpriority helps break priority ties when multiple exceptions have the same preemption level. The NVIC always picks the highest composite priority interrupt to service first.
Priority levels can be set statically at build time or dynamically changed in firmware. Lower priority interrupts can be masked if needed. Setting an interrupt priority to 0 prevents all preemptions by that exception.
Wakeup from Sleep
The Cortex-M0 interrupt system allows waking up from sleep/low power modes when an interrupt occurs. This helps implement low-power designs. The processor sleeps when idle and instantly wakes up on external events requiring attention.
Wakeup from sleep can be enabled for specific interrupt sources like EXTI pins. Alternatively, non-maskable interrupt (NMI) can be used to wakeup from any low power mode. This allows critical exceptions to always reach the processor in sleep state.
Cortex-M0 Low Power Modes
The Cortex-M0 CPU integrates power control options to reduce power consumption in idle or inactive periods. The processor offers the following low power modes:
- Sleep – Stops CPU but keeps peripherals running. Wakeup in a few clock cycles.
- Deep sleep – Stops CPU and most peripherals. Only low-power peripherals can run.
- Standby – Shuts down everything except wakeup logic. External reset needed to restart.
In sleep and deep sleep modes, wakeup can occur via external interrupts from enabled peripheral modules or the SysTick timer. Standby mode requires a complete system reset to restart.
The Cortex-M0 enters low power mode when there are no active application tasks to execute. This helps reduce average power consumption significantly in idle periods. Applications can force the CPU into sleep/low power mode and wakeup later on peripheral events using WFI/WFE instructions.
Wait For Interrupt (WFI)
The WFI instruction is used to put the Cortex-M0 CPU into sleep mode until the next interrupt occurs. When executed, WFI completes any pending writes to memory, disables interrupts, and puts the processor in a low-power state. The core immediately wakes up on interrupt, allowing minimum latency response. WFI; //Sleep until next IRQ
WFI does not affect register contents or peripheral states. However, some processor cycles are lost during entry/exit from WFI mode. For deterministic response, WFI wakeup using the SysTick timer or external interrupts is recommended.
Wait For Event (WFE)
WFE is similar to WFI but allows waking up on events other than interrupts. The processor enters sleep mode until the event flag it is waiting for becomes set. WFE depends on explicit event flag manipulation using SEV/WFE instructions and is useful for thread synchronization. WFE; //Sleep until event flag set
The event wait mechanism allows one thread to sleep until an event flag is set by another, eliminating active wait states. This again enables lower power consumption when threads need to synchronize within embedded application firmware.
Sleeping and Waking up
A typical low-power firmware flow using WFI involves:
- Checking for idle/no active tasks conditions.
- Optionally disabling interrupts not needed during sleep.
- Issuing a WFI instruction.
- On wakeup, resuming application execution.
For event flags, threads set the flags when specific conditions are met. Other threads waiting on those flags can then wakeup and respond accordingly. This facilitates efficient synchronization.
Design Guidelines
Here are some key guidelines for working with Cortex-M0 interrupts and low power modes:
- Assign higher priorities to time-critical and important interrupt handlers.
- Balance priorities to ensure lower priority interrupts are not starved for long durations.
- Keep handler code short and optimal avoid affecting other interrupts.
- Use tail-chaining to improve exception latency where applicable.
- Enter sleep mode whenever the processor is idle or waiting.
- Configure peripherals and external interrupts carefully for wakeup support.
- Use event flags for thread communication and synchronization.
Testing interrupt handler execution times and latency is important. Logic analyzers and probes can be used to view interrupt activity and execution flows.
For lowest power, unused peripheral clocks should be disabled and GPIOs configured as analog inputs. Minimizing active current draw allows lower sleep mode current and longer battery lifetimes.
Conclusion
The Cortex-M0 interrupt architecture and power control features enable robust and efficient embedded application development. Interrupts allow responsiveness to external events with low-latency handler execution. Meanwhile, sleep modes reduce average power consumption considerably.
Using the NVIC priority settings judiciously, defining ISR code carefully, and leveraging low power modes result in an optimal balance of performance and power savings. Event flags allow simplified thread synchronization logic during low power operation.
Overall, the Cortex-M0 capabilities provide significant flexibility to develop feature-rich IoT edge devices while maintaining long battery life and real-time response. With careful configuration and firmware design, interrupts and low power modes can be leveraged effectively for a wide range of energy-efficient embedded applications.