Almost since computers were
invented, interrupts have been a
common programming method
to deal with real-time tasks. An interrupt
causes a processor to stop the running
task, and to execute an interrupt handler
instead. The interrupt handler
determines the cause of the interrupt,
responds to the interrupt, whereupon
control is restored to the original task. A
simple example is an interrupt from a
UART (a serial port) stating that a character
has been received, and the interrupt
handler will take the character
from the UART and store it in a queue
in memory for use by the main task.
Figure 1. Example task structure. The background task is green, the interrupt handlers are red, and arrows show interaction.
Programming with interrupts can be
complex and challenging, so in this article
we outline a programming method called
event-driven programming that offers
most of the functionality of interrupts,
while being easier to reason about.
To show why interrupts are a challenge,
consider an Ethernet time-server.
This is a device connected to a high precision
clock that supplies a global reference
clock using an Ethernet protocol.
At the core, this device has four tasks,
serviced by three interrupts (Figure 1):
• The background task responds to a
time request that comes in over
Ethernet. It will, for example, provide
and implement a protocol that estimates
the latency between Ethernet
transmitter and receiver.
• On a clock interrupt: when a new clock
reading is available, the clock value is
incremented by one. Assuming we
have a 64-bit clock value, this may
involve multiple operations to implement
the long addition.
• On an EthernetTX interrupt: check if
there is another packet to be sent, and
if so, provide it.
• On an EthernetRX interrupt: queue
and timestamp the packet.
We can see here that interrupts serve
two fundamental purposes to the system
programmer: they offer a method to
react to external stimuli (Ethernet,
clock), and a method to implement
semi-concurrent execution of code
(between a background task and the
other three tasks).
Programming this system is complex.
Consider the clock interrupt, which
performs an operation along the following
lines (assuming a 32-bit architecture
where LSW is the least significant
word and MSW is the most significant
The background task may observe a
time-stamp at any time by reading the
value from clock.LSW and clock.MSW.
There are two considerations when
• If the clock interrupt happens just
between the background task reading
the LSW and the MSW, the background
task may get an inconsistent
view of the time (off by 4 billion ticks).
The chances of this happening are
slim (1 in 4 billion), which means that
this problem is very unlikely to show
up during testing. This problem can
be solved by protecting the read operation,
for example, by disabling
around the read.
• Since the interrupt may happen at any
time, the interrupt routine can make
little or no assumptions about the state
of the registers. It therefore must save
all registers that are used in the interrupt
routine, and restore all registers
afterwards. In addition, it must load
any values it needs.
Subscribe today to receive the INSIDER, a FREE e-mail newsletter from Embedded Technology featuring exclusive previews of upcoming articles, late breaking NASA and industry news, hot products and design ideas, links to online resources, and much more.