Embedded Systems/Super Loop Architecture

When programming an embedded system, it is important to meet the time deadlines of the system, and to perform all the tasks of the system in a reasonable amount of time, but also in a good order. This page will talk about a common program architecture called the Super-Loop Architecture, that is very useful in meeting these requirements

Definition
A super loop is a program structure comprised of an infinite loop, with all the tasks of the system contained in that loop. Here is a general pseudocode for a superloop implementation:

Function Main_Function {  Initialization; Do_Forever {    Check_Status; Do_Calculations; Output_Response; } }

We perform the initialization routines before we enter the super loop, because we only want to initialize the system once. Once the infinite loop begins, we don't want to reset the values, because we need to maintain persistent state in the embedded system.

The loop is in fact a variant of the classic "batch processing" control flow: Read input, calculate some values, write out values. Do it until you run out of input data "cards". So, embedded systems software is not the only type of software which uses this kind of architecture. For example, computer games often use a similar loop. There the loop is called (tight) (main) game loop.

Power-Save Super Loop
Let's say we have an embedded system which has an average loop time of 1ms, and needs only to check a certain input once per second. It seems a waste to continue looping the program, especially when we don't need to do anything most of the time. In this situation, the program will loop 1000 times before it needs to read the input, and the other 999 loops of the program will just be a countdown to the next read. In this case, it is sorely inefficient to have the processor chugging away at 100% capacity all the time. We will now implement an expanded superloop to build in a delay:

Function Main_Function {  Initialization; Do_Forever {    Check_Status; Do_Calculations; Output_Response; Delay_For_Next_Loop; } }

Notice how we added a delay at the end of the super loop? If we build this delay to delay for 999ms, we don't need to loop 1000 times, we can read the input on every loop.

Also, it is important to note that many microcontrollers have power-save modes, where they will require less electrical power, which can be especially good if the system is running off a battery.

Power Use Calculations
Let's say that we have a microcontroller that uses 20mW of power in "normal mode", but only needs 5mW of power in "Low-Power Mode". Let's also say that we are using the example superloop above, which is in "Low-Power Mode" 99.9% of the time (1ms of calculations every second), and is only in normal mode 0.1% of the time:

$$ \mathrm{Power} = \frac{(99.9\% \times 5\ \mathrm{mW})+(0.1\% \times 20\ \mathrm{mW})}{100\%} = 5.015\ \mathrm{mW} \quad \mathrm{Average}$$

Notice how we can cut down our power consumption by adding in a substantial delay? This is especially important because few embedded applications will require 100% of processor resources. Most embedded systems are able to just sit and wait in a low-power state until needed.