Chapter 9: Interrupts, Timers and Tasks
Chapter 9: Interrupts, Timers and Tasks
If you use or reference these slides or the associated textbook, please cite the original authors’ work as follows:
Toulson, R. & Wilmshurst, T. (2016). Fast and Effective Embedded Systems Design - Applying the ARM mbed
(2nd edition), Newnes, Oxford, ISBN: 978-0-08-100880-5.
www.embedded-knowhow.co.uk
Timers and Interrupts
The very first diagram in this book, repeated below, shows the key features of an
embedded system. Among these is time. Embedded systems have to respond in
a timely manner to events as they happen. Usually, this means they have to be
able to:
• Measure time durations;
• Generate time-based events, which may be single or repetitive;
• Respond with appropriate speed to external events, which may occur at
unpredictable times.
Tasks: Event-Triggered and Time-Triggered
In almost all embedded programs, the program has to undertake a number of
different activities. We call these distinct activities tasks.
Once a program has more than one task, we enter the domain of multi-tasking.
Tasks performed by embedded systems tend to fall into two categories:
• event-triggered; occur when a particular external event happens, at a time
which is not predictable;
• time-triggered happen periodically, at a time determined by the microcontroller.
As a simple example, a room temperature controller may have the tasks shown
below.
Function Usage
InterruptIn Create an InterruptIn connected to the specified pin
rise Attach a function to call when a rising edge occurs on
the input
fall Attach a function to call when a falling edge occurs on
the input
mode Set the input pin mode
Introductory Use of an mbed Interrupt
When the interrupt is activated, the ISR executes and LED1 is toggled. This can
occur at any time in program execution. The program has effectively one time-
triggered task, the switching of LED4, and one event-triggered task, the switching
of LED1. The circuit is simple, as shown.
/* Program Example 9.1: Simple interrupt example. External input causes
interrupt, while led flashes
*/
#include "mbed.h"
InterruptIn button(p5); //define and name the interrupt input
DigitalOut led(LED1);
DigitalOut flash(LED4);
int main() {
button.rise(&ISR1); // attach the address of the ISR
//function to the interrupt rising edge
while(1) { //continuous loop, ready to be interrupted
flash = !flash;
wait(0.25);
}
}
Getting Deeper into Interrupts
To deal with more complex interrupt applications, most processors contain four
important mechanisms:
• Interrupts can be prioritised, - some can be defined as more important than
others. If two occur at the same time, then the higher priority one executes first.
• Interrupts can be masked, i.e. switched off, if they are not needed, or are likely
to get in the way of more important activity. This masking could be just for a
short period, for example while a critical program section completes.
• Interrupts can be nested. This means that a higher priority interrupt can
interrupt one of lower priority. Working with nested interrupts increases the
demands on the programmer, and is strictly for advanced players only.
• The location of the ISR in memory can be selected, to suit the memory map and
programmer wishes.
Also - the delay between the interrupt occurring, and the processor responding, is
called the interrupt latency.
While the interrupt is waiting for a response from the processor, it is said to be
pending.
A Typical Microprocessor Interrupt Response –
some greater detail
Interrupt Asserted
This
Interrupt Detected No No immediate response,
Interrupt is
enabled? but flag stays set
No
int main() {
squarewave.rise(&pulse); // attach the address of the pulse function to
// the rising edge
while(1) { // interrupt will occur within this endless loop
flash = !flash;
wait(0.25);
}
}
Interrupts from Analog Inputs
Aside from digital inputs, it is useful to generate interrupts when analog signals
change, for example if an analog temperature sensor exceeds a certain
threshold. One way to do this is by applying a comparator, as shown.
6. What is the maximum value, in decimal, that a 12-bit and a 24-bit counter can
count up to?
7. A 4.0 MHz clock signal is connected to the inputs of a 12-bit and a 16-bit
counter. Each starts counting from zero. How long does it take before each it
reaches its maximum value?
8. A 10-bit counter, clocked with an input frequency of 512 kHz, runs continuously.
Every time it overflows, it generates an interrupt. What is the frequency of that
interrupt stream?
Using the mbed Timer
The LPC1768 has four general-purpose timers, a Repetitive Interrupt Timer, and
a System Tick Timer. All are based on the principles just described.
The mbed makes use of these in three distinct applications, the Timer, used for
simple timing applications, Timeout, which calls a function after a pre-determined
delay, and Ticker, which repeatedly calls a function, at a pre-determined rate.
The mbed also applies a Real Time Clock to keep track of time of day, and date.
The mbed Timer allows basic timing activities to take place, for comparatively
short time durations. A Timer can be created, started, stopped and read, as
shown.
Function Usage
start Start the timer
stop Stop the timer
reset Reset the timer to 0
read Get the time passed in seconds
read_ms Get the time passed in milliseconds
read_us Get the time passed in microseconds
A simple Timer Application
This Program Example measures the time taken to write a message to the
screen, and displays that message on Tera Term or CoolTerm.
#include "mbed.h"
Timer t; // define Timer with name “t”
Serial pc(USBTX, USBRX);
int main() {
t.start(); //start the timer
pc.printf("Hello World!\n");
t.stop(); //stop the timer
//print to pc
pc.printf("The time taken was %f seconds\n", t.read());
}
Using Multiple mbed Timers
/*Program Example 9.4: Program which runs two time-based tasks
*/
#include "mbed.h"
Timer timer_fast; // define Timer with name "timer_fast"
Timer timer_slow; // define Timer with name "timer_slow"
DigitalOut ledA(LED1);
DigitalOut ledB(LED4);
int main() {
timer_fast.start(); //start the Timers
timer_slow.start();
while (1){
if (timer_fast.read()>0.2){ //test Timer value
task_fast(); //call the task if trigger time is reached
timer_fast.reset(); //and reset the Timer
}
if (timer_slow.read()>1){ //test Timer value
task_slow();
timer_slow.reset();
} This program creates two Timers, timer_fast
}
} and timer_slow. The main program starts
these running, and tests when each exceeds
void task_fast(void){ //”Fast” Task a certain number. When the time value is
ledA = !ledA;
} exceeded, a function is called, which flips the
void task_slow(void){ //”Slow” Task associated led.
ledB = !ledB;
}
Using the mbed Timeout
Timeout allows an event to be triggered by an interrupt, with no polling
needed. Timeout sets up an interrupt to call a function after a specified
delay. The API summary is shown.
Function Usage
attach Attach a function to be called by the Timeout,
specifying the delay in seconds
attach Attach a member function to be called by the
Timeout, specifying the delay in seconds
attach_us Attach a function to be called by the Timeout,
specifying the delay in microseconds
attach_us Attach a member function to be called by the
Timeout, specifying the delay in microseconds
detach Detach the function
A Simple Timeout Application
/*Program Example 9.6: Demonstrates Timeout, by triggering an event a fixed
duration after a button press. */
#include "mbed.h"
Timeout Response; //create a Timeout, and name it "Response"
DigitalIn button (p5);
DigitalOut led1(LED1); //blinks in time with main while(1) loop
DigitalOut led2(LED2); //set high fixed period after button press
DigitalOut led3(LED3); //goes high when button is pressed
The mbed Ticker sets up a recurring interrupt, which can be used to call a
function periodically, at a rate decided by the programmer. The API
summary is shown.
Function Usage
attach Attach a function to be called by the Ticker,
specifying the interval in seconds
attach Attach a member function to be called by the
Ticker, specifying the interval in seconds
attach_us Attach a function to be called by the Ticker,
specifying the interval in micro-seconds
attach_us Attach a member function to be called by the
Ticker, specifying the interval in micro-seconds
detach Detach the function
Applying Ticker to the First Example Program
Creating a periodic event is one of the most common requirements in an
embedded system. This program switches the LED every 200 ms, using
Timeout rather than a wait( ) function.
#include "mbed.h"
void led_switch(void);
Ticker time_up; //define a Ticker, with name “time_up”
DigitalOut myled(LED1);
int main(){
time_up.attach(&led_switch, 0.2); //initialises the ticker
while(1){ //sit in a loop doing nothing, waiting for
//Ticker interrupt
}
}
The Real Time Clock
The Real Time Clock (RTC) is an ultra-low-power peripheral on the LPC1768,
which is implemented by the mbed.
The RTC is a timing/counting system which maintains a calendar and time-of-
day clock, with registers for seconds, minutes, hours, day, month, year, day of
month and day of year. It can also generate an alarm for a specific date and
time.
It runs from its own 32 kHz crystal oscillator, and can have its own independent
battery power supply. It can thus be powered, and continue in operation, even
if the rest of the microcontroller is powered down.
The mbed API doesn’t create any C++ objects, but just implements standard
functions from the standard C library, as shown.
Function Usage
Time Get the current time
set_time Set the current time
mktime Converts a tm structure (a format for a time record)
to a timestamp
localtime Converts a timestamp to a tm structure
ctime Converts a timestamp to a human-readable string
strftime Converts a tm structure to a custom format human-
readable string
Switch Debouncing
The mechanical contacts of a switch literally bounce together, as the switch
closes. This lasts for a few milliseconds, and can cause a digital input to swing
wildly between Logic 0 and Logic 1 for a short time after a switch closes, as
illustrated.
There are several techniques, in hardware and software, which allow switch
debouncing.
/* Program Example 9.12: Event driven LED switching with switch debounce
*/
#include "mbed.h"
int main() {
debounce.start();
button.rise(&toggle); // attach the address of the toggle
} // function to the rising
edge
void toggle() {
if (debounce.read_ms()>10) // only allow toggle if debounce timer
led1=!led1; // has passed 10 ms
debounce.reset(); // restart timer when the toggle is
performed
}
Introducing the Real Time Operating
System (RTOS)
Programs so far in this book have almost all been
structured around a main loop (sometimes called a
super loop), as symbolised. This is adequate for
many programs, but there comes point when the
structure is no longer adequate; the loop might
become just too big, or some of the tasks are
intermittent, or the tasks or ISRs cause
unacceptable delay to each other.