Interrupts, Exceptions, and Real-Time OperationIntroductionA microprocessor normally executes instructions in sequence, but embedded systems must also respond to events that occur independently of the current program flow. A timer may expire, an analogue-to-digital conversion may complete, a communication character may arrive, or a fault may occur. Interrupt mechanisms allow the processor to suspend ordinary execution, execute a service routine, and then resume the interrupted program. Interrupts are central to real-time embedded design because they connect physical events with software actions. Correct design requires more than writing an interrupt service routine (ISR). The designer must configure the interrupt controller, establish vector addresses, select priorities, control masking, preserve processor context, manage shared data, and demonstrate that timing requirements are satisfied. An interrupt is an asynchronous request generated by hardware or software. An exception is a processor-detected event associated with instruction execution, such as an invalid opcode, memory fault, or division error. The exact terminology varies among architectures, but the engineering principles are broadly applicable to ARM Cortex-M, AVR, PIC, MSP430, RISC-V, and other microcontroller families. Learning ObjectivesAfter studying this chapter, the reader should be able to: - distinguish interrupts, exceptions, traps, faults, and software-generated requests;
- explain interrupt vectors, controllers, priorities, masking, nesting, and pre-emption;
- write and evaluate interrupt service routines;
- calculate interrupt latency, execution time, response time, and utilization;
- identify race conditions and select suitable atomicity mechanisms;
- design watchdog, timer, and scheduling strategies for real-time systems;
- analyse jitter and determine whether a system can meet a deadline;
- apply safe and deterministic interrupt design practices.
1. Interrupt and Exception Architecture1.1 Basic sequenceA typical interrupt sequence is: - A peripheral or processor condition asserts a request.
- The interrupt controller records the pending condition.
- The controller applies enable, mask, priority, and routing rules.
- The processor completes the current instruction or reaches an architecturally defined boundary.
- Processor context is saved, either automatically or by software.
- The vector associated with the event supplies the ISR address.
- The ISR identifies and services the source.
- The interrupt condition is cleared or acknowledged.
- Saved context is restored and normal execution resumes.
The precise order differs among processors. For example, Cortex-M processors automatically stack selected registers on exception entry, whereas some processors require compiler-generated or hand-written prologues. 1.2 Interrupts and exceptionsAn external interrupt originates outside the instruction currently executing. Examples include a timer compare event, GPIO edge, DMA completion, or received UART byte. It is often asynchronous to the instruction stream. An exception is generated internally by the processor. Examples include a reset, non-maskable interrupt, breakpoint, memory-management fault, bus fault, or undefined instruction. Synchronous exceptions are caused by a particular instruction and are therefore easier to associate with a program location. Asynchronous exceptions may resemble hardware interrupts. A trap is usually an intentional synchronous transfer to privileged or supervisory software, such as a system call or debugging breakpoint. A fault indicates an error that may sometimes be recoverable; an abort generally indicates a serious error for which continuation may not be safe. These names are architecture-dependent and should always be checked against the processor reference manual. 1.3 Vector tablesA vector table maps an event number to an entry address or handler address. It may contain an initial stack pointer followed by exception and interrupt handler addresses, or it may contain branch instructions to handlers. The table must be located at an address permitted by the architecture, aligned as required, and initialized before interrupts are enabled. A robust startup sequence is: - initialize the stack and low-level processor state;
- relocate or configure the vector table if required;
- install valid default handlers;
- configure peripheral status and interrupt flags;
- configure priorities and masks;
- enable individual sources;
- finally enable global interrupt acceptance.
A default handler should not silently return from an unexpected interrupt. It should record diagnostic information and place the system in a safe state, or deliberately halt while allowing debugging. 2. Interrupt Controllers, Masking, and PrioritiesAn interrupt controller is hardware that receives requests and decides which request is presented to the processor. Common functions include pending-bit storage, source enable bits, global masking, priority comparison, vector generation, nesting, software triggering, and routing to processor cores. A request can generally be in one of four logical states: inactive, pending, active, or masked. Masking does not necessarily remove the event; in many controllers the request remains pending and is delivered when the mask is removed. A level-sensitive source may remain pending while its signal is asserted. An edge-sensitive source may record one or more edges, depending on hardware capability. 2.1 Priority and nestingPriority determines which eligible interrupt is serviced first. A higher-priority request may pre-empt a lower-priority ISR if nesting is enabled. Some architectures use numerically smaller values for higher priority, so numerical comparisons must not be assumed without consulting documentation. Priority design should reflect deadline urgency, not merely perceived importance. A fast control-loop timer may need higher priority than a diagnostic UART. However, excessive priority levels increase analysis complexity. A useful policy is to keep ISRs short and assign only as many priority classes as the timing requirements justify. If interrupts of priority levels 1 through n execute for times C₁ through Cₙ, a simple upper bound on one ISR's blocking by non-pre-emptible work is the longest lower-priority critical section. More complete response-time analysis must also include higher-priority interference and release rates. 2.2 MaskingGlobal masking disables a broad class of interrupts. Selective masking disables particular sources or priority classes. Masking is appropriate for protecting a very short critical section, but it increases worst-case interrupt latency. Non-maskable interrupts should be reserved for events that require response even during ordinary masking, such as a severe power or safety fault. Masking must be restored to its previous state rather than blindly enabled or disabled. This is especially important when code can execute inside nested critical sections. Many operating systems provide lock and interrupt-save primitives for this purpose. 3. Interrupt Service RoutinesAn ISR should perform the minimum work necessary to capture the event, preserve data, and arrange deferred processing. A common pattern is: ISR:
identify source
clear or acknowledge source according to device rules
capture time-sensitive data
place data in a buffer or set an event flag
return
background task:
process the captured dataThe correct order of clearing and servicing depends on the peripheral. Clearing a status bit too early may lose an event; clearing it too late may cause immediate retriggering. Some peripherals clear a flag by writing a one, while others require a read-then-write sequence or a read of a data register. An ISR should generally avoid blocking calls, dynamic memory allocation, long loops, formatted printing, and operations with unbounded execution time. It should not call a non-reentrant library function unless that function is explicitly designed for interrupt use. Floating-point operations may also increase context-saving cost on processors with floating-point units. Context preservationThe processor or compiler must preserve all state that the interrupted code may need. This includes registers, condition flags, return state, and sometimes floating-point registers. A hand-written assembly ISR must follow the architecture's calling convention. A compiler-qualified interrupt function may generate the required entry and return sequence, but the generated code should be inspected when timing is critical. Shared dataVariables shared between an ISR and foreground code require careful treatment. A declaration such as volatile tells the compiler that the value can change outside the current flow and prevents inappropriate optimization. It does not make a multi-byte access atomic, impose mutual exclusion, or guarantee memory ordering on every architecture. A single naturally aligned machine-word read or write is often atomic, but this is an architectural property, not a universal C-language guarantee. A counter increment is a read-modify-write operation and is not atomic merely because each individual word access is atomic. 4. Latency, Response Time, and JitterInterrupt latency is the time from the physical or logical assertion of an interrupt request until execution of the corresponding ISR begins. It may include synchronization delays, completion of the current instruction, higher-priority ISR execution, disabled-interrupt intervals, stacking, bus contention, and vector lookup. A useful decomposition is: L = Lsync + Linstr + Lmask + Lhp + Lentry Here, L is total latency; L_sync is input synchronization delay; L_instr is the delay required to reach an interruptible instruction boundary; L_mask is delay caused by masking or a critical section; L_hp is delay caused by higher-priority activity; and L_entry is context stacking and vector-entry time. All terms have units of time. The expression is a design model, not a universal architectural equation; terms that do not apply should be set to zero, and worst-case values should be used for hard real-time analysis. Execution time is the time spent in the ISR after entry. Response time additionally includes any waiting for software processing after the ISR, such as a task released by the ISR. These terms must not be confused. Jitter is variation in timing. If observed response times are t₁, t₂, ..., tₙ, the peak-to-peak jitter is: Jpp = tmax − tmin where t_max and t_min are the largest and smallest measured response times under the stated test conditions. This measure is useful for periodic control, communications, and sampling. Measurement must include relevant worst-case conditions; an average alone cannot establish a deadline guarantee. Worked example: interrupt latencyA timer interrupt experiences 0.8 μs of synchronizer delay, up to 1.2 μs before the current instruction completes, 4.0 μs of disabled-interrupt time, and 2.5 μs of entry overhead. No higher-priority ISR is active. The worst-case latency is: L = 0.8 μs + 1.2 μs + 4.0 μs + 2.5 μs = 8.5 μs If the control requirement permits at most 10 μs, the calculated margin is 1.5 μs. That conclusion applies only if the listed delays are genuine upper bounds and if no unmodelled bus, cache, DMA, or priority effects exist. 5. Real-Time Scheduling and UtilizationA real-time system is correct only when it produces logically correct results at acceptable times. Hard real-time systems have deadlines that must not be missed; soft real-time systems tolerate occasional misses with degraded service. For a periodic task i with execution time Cᵢ and period Tᵢ, processor utilization is: U = Σ(Cᵢ / Tᵢ) Cᵢ and Tᵢ must use the same time unit, and U is dimensionless. The formula estimates processor demand for periodic tasks; it does not by itself prove schedulability. Interrupt overhead, blocking, sporadic tasks, context switches, and operating-system activity must also be included. A periodic interrupt often releases a task rather than performing all computation directly. For a simple fixed-priority system, response-time analysis for task i is commonly written as an iterative bound: Rᵢ = Cᵢ + Bᵢ + Σ⌈Rᵢ / Tⱼ⌉ Cⱼ The summation covers higher-priority tasks j. Rᵢ is worst-case response time, Bᵢ is blocking from lower-priority critical sections, Cᵢ is task execution time, and Tⱼ and Cⱼ are the period and execution time of higher-priority task j. The equation is solved by iteration, beginning with Rᵢ⁽⁰⁾ = Cᵢ + Bᵢ. It applies to a fixed-priority pre-emptive model with suitable assumptions, including known execution bounds and priority assignments. A task is schedulable with deadline Dᵢ if the converged Rᵢ ≤ Dᵢ. Worked scheduling exampleSuppose a task has Cᵢ = 1 ms, blocking Bᵢ = 0.2 ms, and one higher-priority task with Cⱼ = 0.5 ms and Tⱼ = 4 ms. Start with R⁽⁰⁾ = 1.2 ms. Since ⌈1.2/4⌉ = 1: R⁽¹⁾ = 1.0 + 0.2 + 1(0.5) = 1.7 ms. Again, ⌈1.7/4⌉ = 1, so R⁽²⁾ = 1.7 ms. If the deadline is 2 ms, this model predicts that the task is schedulable. The result excludes additional interrupts and therefore requires an engineering margin. 6. Concurrency, Race Conditions, and AtomicityA race condition occurs when the result depends on the timing or ordering of concurrent operations. Consider a foreground routine that tests count > 0 while an ISR decrements count. The foreground operation may observe a value that becomes invalid before it acts. A more subtle race occurs when a multi-byte value is updated one byte at a time and the ISR reads it between writes. Common protection techniques include: - briefly disabling interrupts around a short critical section;
- using atomic processor instructions;
- using a lock or scheduler-aware mutex in an operating system;
- using single-producer/single-consumer ring buffers;
- using double buffering or sequence counters;
- transferring ownership rather than sharing mutable data.
A lock-free ring buffer can be safe when exactly one context writes the producer index and exactly one context writes the consumer index, provided index accesses are atomic and memory ordering is correct. A multi-producer or multi-consumer buffer requires stronger synchronization. A correct critical section must protect the complete invariant, not merely one statement. It should be short, bounded, and free of calls that can block. Priority inversion can occur when a high-priority task waits for a resource held by a low-priority task while a medium-priority task continues executing. Priority inheritance or priority ceilings can reduce this problem in real-time kernels. 7. Watchdogs and Fault RecoveryA watchdog timer resets or otherwise reacts to software that fails to service it within a permitted interval. It can detect deadlock, runaway execution, clock failure, or severe resource exhaustion. A watchdog is not a substitute for correctness: blindly refreshing it from a frequently executing ISR can conceal a failed foreground application. A stronger design uses a supervisory task. Each critical task sets a health indicator after completing its required function. The supervisor refreshes the watchdog only when all indicators are valid and timing constraints have been met. The watchdog timeout must exceed the legitimate worst-case service interval, including startup and temporary overload, but should be short enough to limit unsafe operation. Recovery should record a reset cause, preserve useful diagnostic information, place actuators in a safe state, and avoid repeatedly restarting without indicating the fault. In safety-related systems, watchdog design may be subject to standards such as IEC 61508, ISO 26262, or sector-specific requirements. Applicable standards depend on the product and jurisdiction. 8. Illustrative Case: Motor-Control Sampling SystemBackgroundConsider an illustrative 32-bit microcontroller controlling a motor. A timer triggers current sampling every 100 μs, giving a 10 kHz control period. A UART receives diagnostic commands, and a watchdog supervises the application. ProblemThe original design performed current conversion, filtering, control calculation, logging, and command parsing inside the timer ISR. The motor occasionally exhibited control jitter, and diagnostic traffic caused missed sampling deadlines. AnalysisThe timer period is 100 μs. Measurements show that the control ISR requires 62 μs in the normal case and 91 μs in the worst case. UART processing can add up to 35 μs because it parses variable-length messages. Since both execute at interrupt level, the combined worst-case demand can exceed the sampling interval. In addition, a 20 μs critical section used by a shared buffer increases latency. ApproachThe redesigned system performs only time-critical operations in the timer ISR: capture ADC results, update a fixed-size control state, and release a high-priority control task. A DMA channel transfers ADC samples into a buffer. UART reception uses a ring buffer and releases a lower-priority parser task. The critical section is reduced to an atomic index update. The watchdog is refreshed only by a supervisor after the control task and communication task report valid progress. Assume the measured execution times per 100 μs period are 18 μs for the control task, 8 μs for buffer management, and an average of 12 μs for communication, with communication treated as a lower-priority sporadic activity. The nominal periodic utilization is approximately: U = (18 + 8) / 100 = 0.26 The communication activity must still be analysed by its maximum arrival rate and execution time; the average 12 μs value cannot establish a hard guarantee. OutcomeThe control path no longer depends on message length. Measured sampling jitter falls substantially because DMA and short ISRs replace long interrupt work. The system also provides better diagnostics because missed task reports and watchdog reset causes are recorded. Learning pointsThe case demonstrates that interrupt design is an architectural issue. Short ISRs, deferred processing, DMA, explicit priority assignment, bounded critical sections, and watchdog supervision work together. Optimizing one ISR instruction sequence would not have solved the original concurrency and scheduling problem. 9. Design Verification and Best PracticesVerification should combine static reasoning, instrumentation, stress testing, and fault injection. Useful measurements include ISR entry and exit timestamps, maximum masked-interrupt duration, queue occupancy, deadline misses, and watchdog reset causes. A spare GPIO can be toggled at ISR entry and exit and observed with an oscilloscope or logic analyser, but the instrumentation overhead must be measured. Best practices include: - document every interrupt source, trigger type, flag-clearing rule, priority, and deadline;
- initialize vectors and default handlers before enabling sources;
- bound ISR and critical-section execution times;
- use
volatile where appropriate, but do not confuse it with atomicity; - use hardware reference manuals rather than assumptions about flag behavior;
- separate event capture from substantial processing;
- analyse worst-case rather than average timing;
- test simultaneous requests, interrupt storms, buffer overflow, clock variation, and reset recovery;
- record faults and fail safely;
- review compiler output and calling conventions for critical ISRs.
Contemporary microcontrollers increasingly provide nested interrupt controllers, DMA, event systems, hardware timestamping, memory protection, TrustZone-like isolation, and real-time operating-system support. These features reduce software overhead but introduce additional configuration and verification obligations. Artificial intelligence can assist with log classification or test generation, but it must not replace deterministic timing analysis, code review, or safety validation. Generated code requires the same verification as hand-written code. Challenges and LimitationsInterrupt-driven systems can suffer from interrupt storms, priority inversion, starvation, missed edge events, re-entrant handlers, stack exhaustion, and unbounded library calls. Disabling interrupts improves atomicity but worsens latency. Increasing priority may improve one deadline while harming another. Polling can be simpler and more deterministic for very high-rate or tightly bounded events, whereas interrupts are efficient for sparse events. DMA can reduce CPU load but requires correct cache coherency, buffer ownership, and completion handling. No timing equation is meaningful without stated assumptions. Oscillator tolerance, flash wait states, bus arbitration, cache behavior, compiler optimization, and electrical synchronization can all alter timing. A credible real-time claim therefore specifies hardware, software version, clock configuration, workload, measurement method, and environmental conditions. Chapter SummaryInterrupts and exceptions provide controlled transfers from ordinary execution to event-handling software. Vector tables map events to handlers, while interrupt controllers apply pending, enable, mask, priority, and nesting rules. Effective ISRs preserve context, acknowledge sources correctly, capture urgent data, and defer substantial processing. Real-time correctness depends on bounded latency, execution time, response time, and jitter. Utilization is a useful demand measure but is not a complete schedulability proof. Race conditions require atomic operations, short critical sections, suitable buffers, or synchronization protocols. Watchdogs should supervise meaningful system progress rather than merely being refreshed by any active code. Professional interrupt design combines architecture-specific knowledge with timing analysis, instrumentation, fault recovery, and safety-conscious verification. The central principle is deterministic handling of urgent events without allowing concurrency mechanisms to compromise system correctness. Key TermsInterrupt: An event-driven request that temporarily transfers processor execution to a handler. Exception: A processor-generated event associated with execution or system state. Interrupt service routine (ISR): Software executed to handle an interrupt. Vector table: A table mapping exception or interrupt identifiers to entry addresses. Interrupt controller: Hardware that manages interrupt requests, priorities, masks, and routing. Pending: A state indicating that an interrupt request has occurred but is awaiting service. Masking: Preventing selected interrupt requests from being accepted temporarily. Priority: Relative urgency used to select among simultaneous eligible requests. Nesting: Permitting a higher-priority interrupt to pre-empt a lower-priority handler. Interrupt latency: Time from request assertion to ISR execution. Jitter: Variation in the timing of a recurring event or response. Atomicity: Execution of an operation as an indivisible unit with respect to relevant concurrency. Race condition: Timing-dependent behavior caused by unsafe concurrent access. Critical section: A bounded region protected from interfering concurrent activity. Deadline: Latest acceptable completion time for an operation. Watchdog timer: A timer that initiates recovery when software fails to demonstrate progress. Priority inversion: A condition in which a high-priority activity is delayed by lower-priority resource ownership. DMA: Direct memory access performed by hardware without continuous CPU intervention. Review QuestionsShort Answer Questions- What is the purpose of an interrupt vector table?
- Distinguish an interrupt from a synchronous exception.
- Why does
volatile not guarantee atomicity? - Define interrupt latency and jitter.
- State two operations that should generally be avoided in an ISR.
Long Answer Questions- Explain the complete sequence from interrupt assertion to return from an ISR.
- Discuss how priority, masking, and nesting affect response time.
- Explain race conditions using a shared counter and propose two solutions.
- Describe a robust watchdog supervision strategy.
- Compare performing work in an ISR with deferring it to a real-time task.
Analytical / Application Questions- A system has a 10 μs interrupt deadline. Synchronization, instruction completion, masking, higher-priority interference, and entry delays have worst-case values of 0.5, 1.0, 2.0, 3.0, and 1.5 μs. Determine the latency and assess the margin.
- Design a priority and buffering strategy for a motor-control timer, UART receiver, and emergency shutdown input. Justify the priority order and identify possible race conditions.
- A periodic task has C = 2 ms, T = 10 ms, and blocking B = 0.5 ms. A higher-priority task has C = 1 ms and T = 5 ms. Apply the stated response-time iteration and determine whether a 5 ms deadline is met under the model.
Multiple Choice Questions with AnswersQuestion 1Which component normally maps an interrupt source to its handler address? A. The vector table B. The arithmetic logic unit C. The watchdog oscillator D. The stack data cache Correct Answer: A. The vector table Question 2What does volatile primarily communicate to a compiler? A. The variable is always atomic B. The variable may change outside the current execution flow C. The variable is stored in read-only memory D. The variable is protected by a mutex Correct Answer: B. The variable may change outside the current execution flow Question 3A timer interrupt has delays of 0.8 μs, 1.2 μs, 4.0 μs, and 2.5 μs with no higher-priority interference. What is the worst-case latency? A. 6.5 μs B. 7.5 μs C. 8.5 μs D. 9.5 μs Correct Answer: C. 8.5 μs Question 4Which ISR design practice is generally preferred? A. Perform formatted printing in every ISR B. Use unbounded loops to ensure completion C. Capture urgent data and defer substantial processing D. Allocate dynamic memory before every return Correct Answer: C. Capture urgent data and defer substantial processing Question 5What does peak-to-peak jitter equal? A. The average response time B. The maximum response time minus the minimum response time C. The minimum response time divided by the maximum D. The ISR execution time multiplied by its priority Correct Answer: B. The maximum response time minus the minimum response time Question 6Which condition is a race condition? A. A constant is read from flash B. A result depends on the timing of unsynchronized shared accesses C. A vector table is aligned correctly D. A timer is configured before being enabled Correct Answer: B. A result depends on the timing of unsynchronized shared accesses Question 7For periodic tasks, utilization is calculated as which expression? A. Σ(Tᵢ/Cᵢ) B. Σ(Cᵢ + Tᵢ) C. Σ(Cᵢ/Tᵢ) D. Π(Cᵢ/Tᵢ) Correct Answer: C. Σ(Cᵢ/Tᵢ) Question 8Why should a watchdog not be refreshed indiscriminately by a frequently executing ISR? A. It can conceal failure of the main application B. It always disables interrupts C. It permanently clears the vector table D. It prevents DMA transfers Correct Answer: A. It can conceal failure of the main application Question 9In a fixed-priority response-time model, Bᵢ represents: A. The task deadline B. Blocking from lower-priority critical sections C. The number of interrupt vectors D. The processor clock frequency Correct Answer: B. Blocking from lower-priority critical sections Question 10Which event is typically a synchronous exception? A. A UART character arriving B. A timer edge from a peripheral C. An invalid instruction detected during execution D. A GPIO input transition Correct Answer: C. An invalid instruction detected during execution
|