Lec - 6 Interrupts
Lec - 6 Interrupts
Topic Outlines:
➢ Interrupt Enable/Disable
➢ Interrupt Priorities
➢ The term “exception”, in ARM definition, means any deviation of program flow which may be
caused by an external event (an interrupt) or any internal CPU event whether initiated by the
program executing specific instructions or by an exceptional condition:
▪ The term “trap” or “software interrupt” is defined as programmer initiated and expected
transfer of control to a special routine. It is an instruction known by various mnemonics:
▸ SVC (supervisor call) and SWI (software interrupt) by ARM
▸ INT (interrupt) by Intel (x86)
▸ TRAP by Motorola (HC12)
➢ An I/O operation can be initiated either by the (1) the CPU or (2) the peripheral module:
1) The CPU requests a sample from the ATD module and reads it when ready.
2) The SCI receives a byte and signals the CPU for data ready.
➢ Typically CPUs are much faster than the I/O peripherals serving it.
➢ Due to this speed mismatch, a CPU and its peripherals must be synchronized using
SOFTWARE and HARDWARE techniques
1. Software synchronization
– Delay loops (Blind cycles)
– Polling
2. Interrupts (Hardware + Software)
– An I/O device causes a software routine to execute upon request
– Periodic interrupts check the I/O status (Periodic polling) and act accordingly
3. Direct Memory Access (DMA) (Hardware)
An I/O device interface can be configured for transfer of data to/from memory
directly not through data transfer instructions executed by the CPU.
Synchronization
by Software (1) Delay Loops
Delay loops used by the CPU to perform I/O with a Initiate I/O
peripheral module takes the following steps: Operation
1. Initialize the I/O task with the peripheral module. COUNT = Max
COUNT = 0
?
3. Perform the I/O operation. N
Y
Transfer
I/O Data
Synchronization
by Software (2) Polling
CPU initializes the peripheral module and selects suitable configuration.
CPU initiates CPU initiates CPU initiates
input operation output operation output operation
▪ When the specified event occurs, an interrupt occurs triggering the following sequence:
1) CPU does some hard-wired processing to save its current context, to be able to come back, and identify what to
execute to service the interrupt.
2) CPU executes the identified interrupt service routine ISR which includes a return instruction at its end.
time
3
Basic GPIO Example
▪ Goal: light either LED1 or LED2 based on switch SW1 position pressed/not
pressed.
▪ We can achieve that by letting the CPU execute an infinite loop of instructions that
keeps polling the state of the switch and change the LEDs accordingly.
▪ This polling scheme is wasteful to the CPU time as the CPU becomes unavailable to
do anything else useful.
▪ Try interrupts: Use special hardware in MCU to detect event, run specific code
(interrupt service routine - ISR) in response.
7
Basic Questions when Considering Interrupts
➢ How does the interrupting source identify itself to the CPU to get the service in case we have many sources
of interrupt?
➢ Which code should the CPU execute to service the identified interrupt?
➢ How is the interrupted code status saved so that the CPU is able to resume it after the interrupt is serviced?
➢ What does the CPU do if an interrupt is requested while servicing another interrupt?
➢ How to share data between different pieces of code in a system that allows interrupts?
8
CORTEX-M0+ INTERRUPTS
9
ARM Interrupts
➢ In the ARM programmer’s model, interrupts are a type of exception.
➢ Interrupts are caused by an event in the peripheral which is asynchronous to the CPU.
It can be caused by:
1. A condition in an on-chip peripheral module such as Timer, ADC, UART …
2. A signal on a pin of the MCU.
➢ An event is logical: a signal level or edge (sometimes software selectable)
— High level
— Low level
— Positive edge
— Negative edge
➢ The ARM core uses vectored interrupts which means that each interrupt source has:
• An interrupt request number identifying itself
• A vector (an address) to tell the CPU where to go to execute the service to the interrupt
➢ The ARM core uses prioritized interrupts: it uses priority numbers to assign precedence to different sources.
Priority means which interrupt is serviced first when simultaneous requests are made, or can a new interrupt preempt
a running interrupt service routine.
➢ The Nested Vector Interrupt Controller NVIC, part of the ARM core, is configured to control the peripheral’s interrupt
generation behavior. It employs a priority resolution that can be customized by software.
Cortex-M0+ Exception Sources
➢ The Cortex-M has an on-chip interrupt controller called Nested Vector Interrupt Controller (NVIC) to interface the
CPU to different interrupt sources. It allows some degree of standardization among the ARM Cortex-Mx (M0, M1,
M3, and M4) family members.
➢ The NVIC of the ARM Cortex-M has room for the total of 255 interrupts and exceptions.
• when errors occur e.g., when the code tries to access a peripheral that hadn’t been enabled yet through
clock gating).
• when system services are requested. (Supervisor call; SVC instruction)
▪ Non-Core 32 interrupt sources (IRQ0-IRQ31):
• These interrupts are caused by peripheral modules, so they are manufacturer dependent.
➢ The lowest 1024 bytes (256 × 4 = 1024) of memory space are set aside for the interrupt vector table that maps
the interrupt request number IRQn to the interrupt vector and must not be used for any other function.
11
Selected Cortex-M0+ Core Exception Sources
Vector Address Vector # Source Description Priority
0x0000_0004 1 Reset CPU reset −3
Priority:
0x0000_0008 2 NMI Nonmaskable interrupt −2 The lower the number, the
0x0000_000C 3 HardFault Hard fault error −1 higher the priority
NMI: The non-maskable interrupt request to the NVIC is controlled by the external NMI signal.
The pin the NMI signal is multiplexed on, must be configured for the NMI function to generate
12
the non-maskable interrupt request.
Selected Cortex-M0+ Core Exception Sources
Vector Address Vector # Source Description Priority
0x0000_0004 1 Reset CPU reset −3
Priority:
0x0000_0008 2 NMI Nonmaskable interrupt −2 The lower the number, the
0x0000_000C 3 HardFault Hard fault error −1 higher the priority
HardFault: The catchall for assorted system failures that can take place such as accesses to bad memory, divide-by-zero errors
and illegal unaligned accesses.
SVCall: Exception handler invoked when a Supervisor Call (svc) instruction is executed.
PendSV & SysTick: System level interrupts triggered by software. They are typically used when running a RTOS to manage
when the scheduler runs and when context switches take place.
Beside these core exceptions, there are interrupts that are external to the core itself.
These interrupt lines are usually routed to vendor-specific peripherals on the MCU such as DMA engines or GPIOs.
All of these interrupts are configured via a peripheral known as the Nested Vectored Interrupt Controller (NVIC).
13
KL25Z Interrupt Sources and Interrupt Vector table
Vector address Vector # IRQ Description
0x0000_0040, 44, 48, 4C 16–19 0–3 Direct memory access controller Mapping IRQ number to interrupt vector:
0x0000_0058 22 6 Power management controller For example, if PORTD requests an interrupt:
1. The port control module signals the
0x0000_005C 23 7 Low leakage wake up
2
NVIC.
0x0000_0060, 64 24–25 8–9 I C communications 2. The NVIC will issue interrupt request
0x0000_0068, 6C 26–27 10–11 SPI communications #31 to the CPU.
0x0000_0070, 74, 78 28–30 12–14 UART communications 3. The CPU will read the vector table to
find the location of the ISR for IRQ #31
0x0000_007C 31 15 Analog to digital converter
(vector #47). In particular, it will read the
0x0000_0080 32 16 Comparator word starting at address 0x0000_00BC
0x0000_0084, 88, 8C 33–35 17–19 Timers and pulse-width modulation and load it into the PC so the ISR will
0x0000_0090, 94 36–37 20–21 Real-time clock alarm and seconds execute.
0x0000_0098 38 22 Programmable interval timer
0x0000_00A0 40 24 USB on-the-go
0x0000_00A4 41 25 Digital to analog converter
0x0000_00A8 42 26 Touch sense interface
0x0000_00AC 43 27 Main clock generator
0x0000_00B0 44 28 Low power timer
0x0000_00B8 46 30 Port control module, Port A pin detect
0x0000_00BC 47 31 Port control module, Port D pin detect
14
ARM Cortex-M NVIC
➢ If any enabled interrupts are requested, the NVIC selects the one with the highest priority and directs the CPU to start executing its ISR.
➢ The Wakeup Interrupt Controller WIC duplicates the interrupt masking of NVIC which enables NVIC to be turned off
when the system is idle or sleeping to reduce power.
The WIC will wake up the NVIC if new interrupts are requested, ensuring they are processed and not lost.
NVIC Registers
Size in
Address Name bits Description Read/Write At RESET
0 No effect
Interrupt Set-Pending
1 Change state of associated
0xE000E200 NVIC_ISPR 32 Register interrupt to pending
0x00000000
0 No effect
Interrupt Clear-Pending
1 Change state of associated
0xE000E280 NVIC_NCPR 32 Register interrupt to not pending
0x00000000
0xE000E400- NVIC_IPR0- 32 Eight interrupt Priority Each register has 4 fields to set Each is zero
0xE000E41C NVIC_IPR7 each Registers or read priorities of 4 IRQs. 0x00000000
Interrupt Enable & Disable
Interrupts and other exceptions of configurable priority can be enabled or disabled globally or selectively.
(1) Globally:
➢ The CPU controls whether interrupts and other exceptions of configurable priority are recognized or not via
bit zero (PM) of the programmable-interrupts mask core register PRIMASK:
– A PRIMASK.PM value of one prevents them.
The PRIMASK register is accessed by the move special register instructions, MSR or MRS:
• MSR primask,<Rn> ; reads the PRIMASK register into general purpose register Rn
• MRS <Rd>,primask ; writes to the PRIMASK register from general purpose register Rd
In addition, Change Processor State instruction (CPS) changes the PRIMASK (in privilege mode):
• CPSID i ; set PRIMASK.PM to 1 to disable interrupts globally.
• CPSIE i ; set PRIMASK.PM to 0 to enable interrupts globally.
CMSIS-CORE API
– void __enable_irq() - clears PM flag
– void __disable_irq() - sets PM flag Only NMI, Hardfault, and Reset
– uint32_t __get_PRIMASK() - returns value of PRIMASK exceptions can still occur.
– void __set_PRIMASK(uint32_t x) - sets PRIMASK to x
Interrupt Enable & Disable
(2) Selectively:
➢ Each interrupt source can be enabled or disabled separately using two NVIC registers:
Each is 32 bits, with each bit corresponding to one IRQ, IRQ0 to IRQ31:
CMSIS Interface:
– NVIC_EnableIRQ(IRQn) to enable interrupt of type IRQn
– NVIC_DisableIRQ(IRQn) to disable interrupt of type IRQn
➢ Reading ISER or ICER will return the enabled/disabled state for all 32 IRQ sources.
Pending Interrupt
Pending Interrupt:
It is an interrupt that has been requested by a peripheral but is not yet serviced.
CMSIS Interface:
• Uint32_t NVIC_GetPendingIRQ(IRQnum) Returns 1 if interrupt from IRQnum is pending
• NVIC_SetPendingIRQ(IRQnum) Sets interrupt pending flag for IRQnum
• NVIC_ClearPendingIRQ(IRQnum) Clears interrupt pending flag for IRQnum
Prioritizing Interrupts
➢ Each exception source has a priority that determines the order in which simultaneous exception requests are
handled.
➢ The priority of each interrupt is determined by a priority number, set by software in an NVIC register.
➢ The requested exception with the lowest priority number (highest priority) will be handled first.
➢ The rest of the exceptions and interrupts have lower priority and are programmable.
Programmable priority levels range from 0 to 3, with 3 has the lowest priority.
All IRQn have lower priorities that are programmable and stored in the 8 interrupt priority registers IPR0-7.
➢ Only the higher priority interrupts ae allowed to preempt a lower priority ISR.
The programmer is responsible to assign the proper priority to each IRQ to determine which interrupt may
preempt other’s ISRs.
➢ NVIC resolves priority and has the ability to capture the pending interrupts and keeps track of each one until
all are serviced.
Setting/Changing Interrupt Priority
➢ The NVIC contains eight interrupt priority registers (IPR0-7).
➢ Four interrupt sources per register.
➢ Each IPR has an 8-bit field for each interrupt sources, two of these bits specify the
priority level and six bits reserved.
➢ Multiple interrupt sources can have the same priority.
Values that can be stored in each 8-bit field in the interrupt priority register (IPR0-7)
– Priority level 0 0x00 0 (highest priority)
– Priority level 1 0x40 64
– Priority level 2 0x80 128
– Priority level 3 0xC0 192 (lowest)
CMSIS Interface:
NVIC_SetPriority(IRQnum, priority)
Special Cases of Prioritization
➢ Simultaneous exception requests:
– The exception with the lower priority number is serviced first, the other one is set pending.
When the one with higher priority is finished, the one pending starts execution.
– If multiple interrupts have the same priority number, the one with the lowest IRQ number takes
precedence for example IRQ3 precedes IRQ5.
2. New exception has priority lower than or equal to current priority, then
» Hold new exception pending state.
» Current handler continues and completes execution.
» Previous priority level restored.
» Start new exception handler if its priority level allows.
Initializing the Interrupt Vector Table
➢ CMSIS-CORE specifies standard names for system exception handlers.
➢ Different microcontrollers have different peripherals, so the interrupt handler’s names and vectors are
defined in the MCU-specific startup code.
➢ The Define Constant Data DCD symbol tells the assembler to define a constant data word with the value
specified. In this case it is the address of the specified handler (the interrupt vector).
The definition of the Interrupt Vector Table IVT in the KL25Z4 MCUs assembly language file startup_MKL25Z4.s (16 exceptions)
Initializing the Interrupt Vector Table
The rest of the IVT in the KL25Z4 MCUs assembly language file startup_MKL25Z4.s (IRQ0-22 out of 32)
Initializing the Interrupt Vector Table
The rest of the IVT in the KL25Z4 MCUs assembly language file startup_MKL25Z4.s (IRQ23-31 out of 32)
Interrupt Configuration
➢ In order to use hardware interrupts from a peripheral module we must go through three steps to configure the
interrupt from that module on three levels :
1 2 3
Configuration: Level 1 ─ Peripheral Module
(Example PORTD)
Here we will examine the Kinetis KL25Z’s PORT module
1
with its pin control in the pin control register (PCR) .
The Interrupt Request Condition IRQC field in the PCR
controls the pin condition which will generate interrupt. It
should be set according to the table. Code Condition Selected
0 Interrupt/DMA request disabled
CMSIS interface:
PORTD->PCR[SW1_POS] = PORT_PCR_IRQC(9) | PORT_PCR_MUX(1) ;
Each port, PORTA or PORTD, is assigned only one IRQ number; IRQ30 for PORTA and IRQ31 for PORTD.
Therefore, when one of these IRQs occurs, the corresponding ISR should be able to identify which bit in the port
caused the interrupt.
This information is found in the port module Interrupt Status Flag Register (ISFR)
Configuration: Level 1 ─ Peripheral Module
(Example PORTD)
➢ The port module Interrupt Status Flag Register (ISFR), 32-bit, indicates which interrupts have been detected for
this port.
A bit value of one indicates the corresponding interrupt has been detected.
➢ The ISR needs to write a one to this bit to clear it to zero ! to prevent recurrent interrupts.
– With CMSIS-CORE interface, the ISFR is accessed as PORTD->ISFR.
The ISFR is part of the PORT module. One register for each port e.g., PORTA_ISFR, PORTD_ISFR…
➢ The corresponding bit is read only for pins that do not support interrupt generation.
➢ The ISF bit for a pin is also visible in the corresponding PCR register. Each flag can be cleared in either location.
➢ If the pin is configured for a level sensitive interrupt and the pin remains asserted, then the flag is set again
immediately after it is cleared (a should-be-avoided situation).
Configuration: Level 2 ─ NVIC
2
➢ Pending
The flag is set by hardware when the interrupt is requested. Software can also set the flag to request the interrupt.
The ISR must clear its source’s pending IRQ flag or else the handler will run repeatedly.
The CMSIS-CORE API provides this interface:
Configuration Level 3 ─ Core
3
Finally, the processor core is configured to accept configurable interrupts by resetting the PRIMASK.PM flag to 0.
Note that when the CPU is reset or powers up, PM is set to zero, so interrupts are not ignored.
Interrupt 1. Entering
occurs Exception Sequence
time
3. Exiting Exception
Sequence
Code operations
Hardware operations (Done transparently)
32
ENTERING AN EXCEPTION HANDLER
33
[1] Entering an Exception Handler (Done Transparently)
1. Finish current instruction (except for lengthy instructions)
5. Load LR with EXC_RETURN code. (Note LR does not hold the Return Address which is saved on the stack)
6. Load IPSR with exception number and start executing code of exception handler.
➢ Interrupt latency:
It is defined as the time from the exception request to the execution of first instruction in handler.
Usually 16 cycles in the M0, and 15 cycles in the M0+.
34
1. Finish Current Instruction
➢ Most instructions are short and finish quickly in one cycle
Load Multiple (LDM), Store Multiple (STM), Push, Pop, MULS (32 cycles for some CPU core implementations)
Waiting for such instructions to complete will delay interrupt response significantly.
➢ If one of these instructions is executing when the interrupt is requested, the processor does the following:
35
2. Push Context onto Current Stack
▪ Push context (832-bit words) onto current stack (MSP or PSP) Following the AAPCS conventions,
(What about other registers: R4, R5, …?) exception handlers and thread mode
code can be regular C functions
(Note Return Address now is on the stack)
▪ Two SPs: Main (MSP), process (PSP)
• Which is active depends on operating mode (Thread mode/Handler Mode): CONTROL register bit 1.
• When pushing context, the hardware decrements the stack pointer to the end of the new stack frame before
it stores data onto the stack. .
• When popping context, the hardware reads the data from the stack frame then increments the stack pointer.
36
▪ Stack grows toward smaller addresses
3. Switch to Handler/Privileged Mode
Reset
Thread
Mode.
MSP or PSP.
Handler Mode
MSP
37
4. Load PC With Address Of Exception Handler
The INT# is multiplied by 4 to fetch the interrupt vector from IVT and load it in PC.
Reset Interrupt
Service Routine start
Non-maskable Interrupt
Service Routine NMI_IRQHandler
38
Can Examine Vector Table With Debugger
39
5. Load LR With EXC_RETURN Code
▪ EXC_RETURN value is generated by CPU and loaded into the LR so that upon executing a return instruction
at the end of the ISR and this code is loaded into the PC, it forces a return from exception sequence not a return
from a function call.
40
6. Start Executing Exception Handler
▪ IPSR is loaded with exception number and exception handler starts running, unless
preempted by a higher-priority exception
41
EXITING AN EXCEPTION HANDLER
42
[3] Exiting an Exception Handler
1. Execute instruction triggering exception return processing
There is no “RETURN FROM INTERRUPT” instruction. Instead use regular instruction:
i. BX LR - Branch to address in LR by loading PC with LR contents.
ii. POP …, PC - Pop address from stack into PC.
… with a special value EXC_RETURN loaded into the PC to trigger exception handling processing
i. BX LR used if EXC_RETURN is still in LR
ii. POP used if EXC_RETURN has been saved on stack
45
EXECUTING AN EXCEPTION HANDLER
46
[2] Executing The Exception Handler
Rules to write an exception handler:
▪ No arguments or return values – void is only valid type
▪ Name the ISR according to CMSIS-CORE system exception names, to ensure that the software toolchain places
ISR addresses in the IVT correctly.
The linker will load the vector table with this handler rather than the default handler.
Examples:
▪ void PORTA_IRQHandler(void); PORTA_IRQHandler,
▪ void RTC_IRQHandler(void); RTC_IRQHandler, etc.
▪ Keep it short and simple: Much easier to debug and improves system response time.
▪ In case this IRQn can possibly be caused by more than one event, identify the exact cause of the interrupt.
▪ Make sure to clear interrupting flag at the end of the ISR before the “Return” instruction.
47 This step is essential to avoid recurrent interrupts from the same source.
Differences Between Interrupt and Subroutine Call (BL)
➢ A BL instruction is used by the programmer in the sequence of instructions
➢ The interrupt is caused by a hardware event; it comes at any time.
➢ When returning from the subroutine that has been called by the BL instruction, the PC is
restored to the address of the next instruction after the BL instruction.
➢ When returning from the interrupt handler, the registers saved when the CPU entered into
ISR (the xPSR, R15, R14, R12, R3–R0 registers) are restored from the top of stack.
48
EXAMPLE USING PORT MODULE AND
EXTERNAL INTERRUPTS
49
Example System with Interrupt
▪ Goal: Change color of RGB LED each time the switch is pressed
▪ We can achieve that by letting the CPU execute an infinite loop of instructions that keeps polling the state of
the switch and change the LED accordingly. (We did that before in GPIO lecture)
▪ This polling scheme is wasteful to the CPU time as the CPU becomes unavailable to do anything else useful.
▪ Try interrupts: Use special hardware in MCU to detect event, run specific code (interrupt service routine - ISR)
in response.
50
KL25Z GPIO Ports with Interrupts
▪ The KL25Z has five GPIO ports: Port A (PTA)
through Port E (PTE).
51
FREEDOM KL25Z Physical Set-up for The Example
Switch Input
Ground
52
Program Requirements & Design
RGB
LED
SW ISR count Main
(does initialization,
then updates LED
ISR Task
based on count)
Global Variable
▪ Req2: Main code will light LEDs according to count value in binary sequence (Blue: 4, Green: 2, Red: 1)
▪ Req3: Main code will toggle its debug line DBG_MAIN each time it executes
▪ Req4: ISR will raise its debug line DBG_ISR (and lower main’s debug line DBG_MAIN) whenever it is
executing
▪ The ISR and the main code share the count value.
53
Building a Program – Break into Pieces
▪ First break into threads, then break thread into steps
▪ Main thread:
◦ First initialize system:
initialize switch: configure the pin connected to the switch to be input
initialize LEDs: configure the pins connected to the LEDs to be outputs
initialize interrupts: initialize the interrupt controller
◦ Then repeat
Update LEDs based on count
▪ Switch ISR:
◦ Update count
▪ main
▪ top level of main thread code
▪ switches
▪ #defines for switch connections
▪ declaration of count variable
▪ Code to initialize switch and interrupt hardware
▪ ISR for switch
▪ LEDs
▪ #defines for LED connections
▪ Code to initialize and light LEDs
▪ debug_signals
▪ #defines for debug signal locations
▪ Code to initialize and control debug lines
55
Configure MCU to Respond to the Interrupt
2) Set up NVIC
56
Set Up Port Module
Port Module
57
Pin Control Register
▪ ISF indicates if interrupt has been detected - different way IRQC Configuration
to access same data as ISFR 0000 Interrupt Disabled
…. DMA, reserved
▪ IRQC field of PCR defines behavior for external hardware
1000 Interrupt when logic zero
interrupts
1001 Interrupt on rising edge
▪ Can also trigger direct memory access (not covered here) 1010 Interrupt on falling edge
1011 Interrupt on either edge
1100 Interrupt when logic one
… reserved
58
Switch Interrupt Initialization
void init_switch(void) {
/* enable clock for port A */
SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK;
/* Select GPIO and enable pull-up resistors and interrupts
on falling edges for pin connected to switch */
PORTA->PCR[SW_POS] |= PORT_PCR_MUX(1) |
PORT_PCR_PS_MASK | PORT_PCR_PE_MASK |
PORT_PCR_IRQC(0x0a);
/* Set port A switch bit to input */
PTA->PDDR &= ~MASK(SW_POS);
/* Enable Interrupts */
NVIC_SetPriority(PORTA_IRQn, 128);
NVIC_ClearPendingIRQ(PORTA_IRQn);
NVIC_EnableIRQ(PORTA_IRQn);
61
}
Main Function
int main (void) {
init_switch();
init_RGB_LEDs();
init_debug_signals();
__enable_irq(); // enable interrupts globally
while (1) {
DEBUG_PORT->PTOR = MASK(DBG_MAIN_POS);
control_RGB_LEDs(count&1, count&2, count&4);
__wfi(); // sleep now, wait for interrupt
}
}
The wfi instruction suspends execution until interrupt occurs.
The wfi instruction suspends execution until one of the following events occurs:
▪ An exception
63
SHARING DATA SAFELY BETWEEN ISRs
AND OTHER THREADS
64
Overview
▪ Volatile data:
Can be updated outside of the program’s immediate control
65
Volatile Data
▪ Cases of volatile data:
▪ Memory-mapped peripheral register – register changes on its own
▪ Global variables modified by an ISR – ISR changes the variable
▪ Global variables in a multithreaded application – another thread or ISR changes the variable
▪ Need to tell compiler which variables may change outside of its control.
▪ Use volatile keyword in the variable definition to force compiler to reload these variables from memory for each use:
Example:
volatile unsigned int num_ints;
Now each C source reference to the variable (e.g., status register) will result in an assembly language load instruction.
67
Atomic Operations
▪ An atomic operation is a sequence that once started cannot be interrupted until completion.
Examples:
• Execution of a single instruction
• A sequence of actions completed in hardware
▪ Instructions on the ARM Cortex-M processor are atomic except for some instructions like store and load multiple,
STM, LDM, PUSH, and POP.
▪ To make a section of code atomic, we can run that code with PRIMASK.PM=1.
In this way, interrupts will not be able to break apart the sequence.
Interrupts that are requested while PRIMASK.PM =1 are not dismissed, but simply be pending until PRIMASK.PM=0.
Make sure the atomic section is short as it blocks interrupts and slows down system response.
▪ Accessing values changed by ISRs, e.g. getting time of day that is updated by ISR.
▪ Accessing a variable shared among tasks e.g., a single counter of errors or events incremented
by more than one task.
69
Non-Atomic Shared Data Example
void GetDateTime(DateTimeType * DT){
▪ Want to keep track of current time and date DT->day = TimerVal.day;
DT->hour = TimerVal.hour;
DT->minute = TimerVal.minute;
▪ Use 1 Hz interrupt from timer
DT->second = TimerVal.second;
}
▪ System
▪ TimerVal structure tracks time and days since
void DateTimeISR(void){
some reference event TimerVal.second++;
▪ TimerVal’s fields are updated by periodic 1 Hz if (TimerVal.second > 59){
TimerVal.second = 0;
timer ISR
TimerVal.minute++;
if (TimerVal.minute > 59) {
TimerVal.minute = 0;
TimerVal.hour++;
if (TimerVal.hour > 23) {
TimerVal.hour = 0;
TimerVal.day++;
… etc.
}
70
Non-Atomic Shared Data Example Problem: Checking the Time
▪ Problem
▪ An interrupt at the wrong time will lead to half-updated data in DT
▪ Failure Case
▪ TimerVal is {10, 23, 59, 59} … (10th day, time is 23:59:59)
▪ Task code calls GetDateTime(), which starts copying the TimerVal fields to DT: day = 10, hour = 23
▪ A timer interrupt occurs, which updates TimerVal to {11, 0, 0, 0}
▪ GetDateTime() resumes executing, copying the remaining TimerVal fields to DT: minute = 0, second = 0
▪ DT now has a time stamp of {10, 23, 0, 0}.
▪ The system thinks time just jumped backwards one hour!
71
Examining the Problem More Closely
72
Definitions
▪ Race condition:
Anomalous behavior due to unexpected critical dependence on the relative timing of
events. Result of example code depends on the relative timing of the read and write
operations.
▪ Critical section:
A section of code which creates a possible race condition. The code section can only
be executed by one process at a time. Some synchronization mechanism is required at
the entry and exit of the critical section to ensure exclusive use.
73
Solution: Briefly Disable Preemption
▪ Prevent preemption within
critical section. Use disable interrupt to void GetDateTime(DateTimeType * DT){
prevent data race conditions with code uint32_t m;
needing atomicity
▪ If an ISR can write to the shared data m = __get_PRIMASK();
object, need to disable interrupts __disable_irq();
▪ save current interrupt
masking state in m
DT->day = TimerVal.day;
▪ disable interrupts
DT->hour = TimerVal.hour;
▪ Restore previous state afterwards because
interrupts may have already been disabled DT->minute = TimerVal.minute;
for another reason DT->second = TimerVal.second;
▪ Use CMSIS-CORE to save, control and __set_PRIMASK(m);
restore interrupt masking state }
▪ Avoid if possible
▪ Disabling interrupts delays response to all
other processing requests
▪ Make this time as short as possible (e.g. a
few instructions)
74
Summary for Sharing Data
▪ Declare (and initialize) shared variables as volatile in main file (or globals.c)
▪ volatile int my_shared_var=0;
▪ When using long (non-atomic) shared data, save, disable and restore interrupt masking status
▪ CMSIS-CORE interface:
__disable_irq()
__get_PRIMASK()
__set_PRIMASK()
75
Interrupt Jargon
• Interrupt Request (IRQ): This is the signal with which some device, such as a timer
overflow flag or an external signal, requests that it be serviced.
• Asynchronous Event: An event that can happen at any time in the MCU instruction execution
cycle.
• Peripheral Interrupt Enable: A bit in an interrupting peripheral that enables the peripheral
to generate an interrupt request.
• Interrupt Service Routine (ISR) / Interrupt Handler : The software written to deal with
the interrupt request for a particular interrupt source.
• Interrupt Flag Clearing: When an interrupt occurs (an interrupt flag is raised), the ISR
must clear the flag that caused the interrupt.
▪ Interrupt Mask: A control bit that stops (masks) interrupt requests from being acted
upon by the CPU. The CPU will have instructions that can mask or unmask interrupts.
▪ Interrupt Prioritization: When multiple interrupts occur simultaneously the system must
have a way to establish which of them is the most important and should be serviced first.
Also, it determines whether a new interrupt can pre-empt a running ISR.
76
Interrupt Jargon
▪ Interrupt Vector: When an interrupt occurs the CPU fetches the starting address of
the ISR from a specific and dedicated location in memory. The ISR starting address is
called the vector and the memory location where it is stored is called the vector location
or vector address.
▪ Interrupt Vector Table: The interrupt vectors are stored in a table in memory called
the interrupt vector table IVT.
• Interrupt Latency: The time between the moment when the interrupt request is
asserted and the moment the CPU starts to execute the ISR. Three factors may
contribute o the interrupt latency:
1. The number of clock cycles needed to complete the interrupted instruction if it should
be completed
2. The number of clock cycles needed to push the necessary registers onto the stack
3. The interrupt priority in case of simultaneous higher priority interrupts
77
Interrupt Jargon
▪ Pending Interrupt: When an interrupt request has occurred and the ISR for that interrupt
has not been entered, the interrupt is said to be pending.
• Nested Interrupts: While executing an ISR, another interrupt is activated. If the new
interrupt has a higher priority, it will preempt the lower priority interrupt.
If the new interrupt has a lower or equal priority it will not get service and will be pending
until ISR completes.
78