Reconfigurable computing
Small Embedded Systems
Unit 3.3
Interrupts and Race Conditions
Race Conditions
The main code and ISR give us two pieces of code whose execution will interleave and we are not sure at the outset in what order they will occur
Whenever we have this situation, and the two pieces of code can change the state of resource (e.g. write a new value to a variable), then we have the possibility of a race condition
Race Condition Example
A microcontroller receives data at unpredictable intervals from a comms link and processes them
Items ready for processing are held in a buffer
Variable numBuff tracks number if items in the buffer
ISR receives data from comms link and puts it into a buffer and increments numBuff
Main loop processes data items and decrements numBuff
Received from comms link
Items processed
numBuff
Handled by ISR
Handled by main loop
uint8_t numBuff;
void loop() {
// Code to process a data item goes here
numBuff–;
}
void isr_code()
{
// Code to receive data item from comms link goes here
numBuff++;
}
Race Condition Code Skeleton
Received from comms link
Items processed
numBuff
Handled by ISR
Handled by main loop
Processing numBuff
A variable (e.g. numBuff) is held at a particular location in memory
The CPU can only operate on values held in a register
This is the sequence carried out by the main loop:
Read value of numBuff from memory into register
Decrement value in register
Write value of numBuff from register into memory
This is the sequence carried out by the ISR:
Read value of numBuff from memory into register
Increment value in register
Write value of numBuff from register into memory
Correct Operation (Remove Item)
Suppose numBuff initially has a value of 5
This is what we want to happen:
When the main loop processes a data item:
Data memory
CPU
CPU registers
5
numBuff
5
5
Copy value to a register
Correct Operation (Remove Item)
Suppose numBuff initially has a value of 5
This is what we want to happen:
When the main loop processes a data item:
Data memory
CPU
CPU registers
5
numBuff
5
5
Decrement register value
4
Correct Operation (Remove Item)
Suppose numBuff initially has a value of 5
This is what we want to happen:
When the main loop processes a data item:
Data memory
CPU
CPU registers
5
numBuff
5
4
4
Write new value back to memory
Correct Operation (Add Item)
So now numBuff has a value of 4
When an item is added, this is what we want to happen:
When the ISR adds a data item, numBuff increments:
Data memory
CPU
CPU registers
5
numBuff
4
Copy value to a register
4
Correct Operation (Add Item)
So now numBuff has a value of 4
When an item is added, this is what we want to happen:
When the ISR adds a data item, numBuff increments:
Data memory
CPU
CPU registers
5
numBuff
4
4
Increment register value
5
Correct Operation (Add Item)
So now numBuff has a value of 4
When an item is added, this is what we want to happen:
When the ISR adds a data item, numBuff increments:
Data memory
CPU
CPU registers
5
numBuff
4
Write new value back to memory
5
Correct Operation
No problem
We started with 5, then removed an item, added an item
The buffer is still holding 5 items
Data memory
CPU
CPU registers
5
numBuff
5
Incorrect Operation
Now let’s see what can go wrong
Suppose numBuff initially has a value of 5
We start processing an item:
Data memory
CPU
CPU registers
5
numBuff
5
5
Copy value to a register
Incorrect Operation
Before we finish the decrement operation…
A new data item arrives and an interrupt is issued
We jump to the ISR
Data memory
CPU
CPU registers
5
numBuff
5
5
Copy value to a register
5
Incorrect Operation
Before we finish the decrement operation…
A new data item arrives and an interrupt is issued
We jump to the ISR
Data memory
CPU
CPU registers
5
numBuff
5
5
6
Increment register value
5
Incorrect Operation
Before we finish the decrement operation…
A new data item arrives and an interrupt is issued
We jump to the ISR
Data memory
CPU
CPU registers
5
numBuff
5
Write new value back to memory
6
5
This is no longer the correct number
Incorrect Operation
Now the ISR is finished
We resume the main loop, which decrements numBuff
Data memory
CPU
CPU registers
5
numBuff
6
5
Decrement register value
4
Incorrect Operation
Now the ISR is finished
We resume the main loop, which decrements numBuff
Data memory
CPU
CPU registers
5
numBuff
6
Write new value back to memory
4
Result is Wrong
We started with 5, then removed an item, added an item
The Microcontroller think the buffer now has 4 items
Race condition on the memory location holding numBuff
Data memory
CPU
CPU registers
5
numBuff
4
Race Condition
Correctness and consistency of processor state depends critically on precise timing of interrupt
This is the sequence carried out by the main loop:
We are OK if the interrupts occur in these places
Loop forever
Read value of numBuff from memory into register
Decrement value in register
Write value of numBuff from register into memory
Interrupt here
Interrupt here
Race Condition
Correctness and consistency of processor state depends critically on precise timing of interrupt
This is the sequence carried out by the main loop:
Things go wrong if the interrupts occur in these places
Loop forever
Read value of numBuff from memory into register
Decrement value in register
Write value of numBuff from register into memory
Interrupt here
Intermittent Faults
This type of problem will normally manifest itself infrequently
The whole of the main loop is probably quite long
The critical section is only 3 lines long
Statistically we will get lucky most of the time
However, the sporadic nature of the fault means that the design is difficult to debug
It can happen that the fault never manifests during testing, and we go ahead to large scale deployment and then start to see problems
Disabling Interrupts
Simplest solution is to disable interrupts during the critical section, then re-enable afterwards
void loop() {
// Rest of processing code goes here
noInterrupts();
numBuff–;
interrupts();
}
void isr_code()
{
// Code to receive data item from comms link goes here
numBuff++;
}
Disabling Interrupts
These two Arduino functions affect all interrupts:
interrupts();
noInterrupts();
It is possible to disable some interrupts and leave others enabled
Interrupts should not be disabled for long periods; timers and other essential services won’t work properly if you do.
Summary
ISRs give us multiple pieces of code whose execution order is not predictable
Care needs to be taken to avoid race conditions, which can give rise to intermittent faults
/docProps/thumbnail.jpeg