š CMPE1250: Interrupts Part 2
By the end of this lesson, students will be able to:
- Explain what interrupts are and why embedded systems rely on them
- Compare polling and interruptādriven designs
- Identify the components involved in interrupt handling (peripheral, NVIC, ISR)
- Locate IRQ numbers and ISR names in STM32 documentation
- Configure and enable a basic interrupt on the STM32G0
- Write a minimal, correct Interrupt Service Routine (ISR)
1ļøā£ What Are Interrupts?
An interrupt is a hardwareādriven event that temporarily pauses normal program execution so the CPU can respond to something important. When an interrupt occurs:
- The CPU finishes the current instruction
- It saves its execution context
- It jumps to a special function called an Interrupt Service Routine (ISR)
- The ISR handles the event
- The CPU restores context and resumes where it left off This allows the microcontroller to react immediately to events such as:
- Incoming serial data
- Timer overflows
- External pin changes
- ADC conversion completion Interrupts are the embedded worldās version of: āStop what youāre doing ā something needs attention right now.ā
2ļøā£ Why Use Interrupts Instead of Polling?
Polling requires the CPU to constantly check if something has happened:
while (1)
{
if (USART2->ISR & USART_ISR_RXNE) {
// new data arrived
}
}
This wastes CPU time and risks missing fast events. Interrupts solve this:
- The CPU can do useful work (or sleep)
- Events are handled immediately
- No constant checking
- More deterministic timing
- Lower power consumption Interrupts are essential for responsive, realātime systems.
3ļøā£ Interrupt Masking and Priorit
Masking
- Interrupts can be individually enabled or disabled
- Disabled interrupts can still go pending, but they wonāt fire
- Some interrupts (like NMI) cannot be masked
Priority If two interrupts occur at the same time, the one with higher priority is serviced first. The STM32G0 uses a simple priority scheme:
- Lower IRQ number ā higher natural priority
- Priorities can be changed, but beginners rarely need to This ensures that critical events (e.g., emergency stop) preempt less important ones (e.g., UART RX).
4ļøā£ The Interrupt Workflow (The 5āStep Pattern)
Every interrupt on the STM32 follows the same pattern:
- Configure the peripheral
- Enable the peripheralās interrupt source
- Enable the NVIC IRQ
- Write the ISR with the correct name
- Globally enable interrupts
This pattern will be used throughout the course.
5ļøā£ Finding the Vector Table and IRQ Numbers
To write an ISR, you need two things:
š§© A. The Interrupt Vector Table
The vector table maps interrupt sources to function names.
Example entry (from stm32g0b1xx_Vectors.s):
DCD USART2_IRQHandler ; USART2 global interrupt
This tells you:
-
The ISR must be named
USART2_IRQHandler -
You cannot invent your own name
SEGGER Embedded Studio includes this file under System Files.
š§© B. IRQ Numbers (IRQn_Type)
To enable an interrupt using CMSIS, you need its IRQ number:
NVIC_EnableIRQ(USART2_IRQn);
These are defined in:
-
stm32g0b1xx.h(part of the STM32G0 package) -
Enum:
IRQn_Type
Example:
USART2_IRQn = 28, /*!< USART2 global interrupt */
You can quickly jump to the definition using Go to Definition in SEGGER
6ļøā£ CMSIS NVIC Function
- CMSIS provides portable functions to control interrupts:
- Global interrupt control
__disable_irq(); // Disable all maskable interrupts __enable_irq(); // Enable all maskable interrupts
NVIC control Common functions include:
-
NVIC_EnableIRQ(IRQn) -
NVIC_DisableIRQ(IRQn) -
NVIC_SetPendingIRQ(IRQn) -
NVIC_ClearPendingIRQ(IRQn) -
NVIC_GetPendingIRQ(IRQn) -
NVIC_SetPriority(IRQn, priority)
These functions abstract away CPUāspecific assembly instructions
7ļøā£ Writing an ISR (Interrupt Service Routine)
An ISR is always:
-
A
voidfunction -
With no parameters
-
Using the exact name from the vector table
Example
</pre> void USART2_IRQHandler(void) { if (USART2->ISR & USART_ISR_RXNE) { char c = USART2->RDR; // reading clears the flag // process character } } </pre>
ISR Rules
- Keep it short
- Clear the interrupt flag
- Never block (no long loops, no delays)
- Avoid heavy computation
8ļøā£ Putting It All Together ā USART RX Example
-
Step 1 ā Configure USART2 (baud rate, pins, enable RX)
-
Step 2 ā Enable RX interrupt
USART2->CR1 |= USART_CR1_RXNEIE;
- Step 3 ā Enable NVIC IRQ
NVIC_EnableIRQ(USART2_IRQn);
- Step 4 ā Write the ISR
void USART2_IRQHandler(void)
{
if (USART2->ISR & USART_ISR_RXNE) {
char c = USART2->RDR;
// handle character
}
}
- Step 5 ā Enable global interrupts
__enable_irq();
š Summary
Interrupts allow the microcontroller to react immediately to important events without wasting CPU time.
To use them effectively, you must:
- Know the peripheralās interrupt flag
- Enable the interrupt in the peripheral
- Enable the corresponding NVIC IRQ
- Write the ISR with the correct name
- Clear the flag inside the ISR
- Keep the ISR short and efficient
This foundation prepares you for deeper topics such as:
- NVIC priority
- Tailāchaining
- DMA interrupts
- Timer interrupts
- SysTick
- Multiāsource IRQs