Super Loops, Sandwich Delays and Foreground/Background Scheduling


This entry is part 1 of 3 in the series RTOS Alternatives.

RTOS Alternatives

As microcontrollers increase in speed and capacity, it’s becoming much more tempting to simply fit a full Real-Time Operating System (RTOS) into a design, without considering other options. This is a shame, because over time a number of alternatives have been developed that can be simple and effective. In this series, I will be discussing some of these, starting with the very simplest — the super loop.

Continue reading Super Loops, Sandwich Delays and Foreground/Background Scheduling →


Simple Co-Operative Scheduling


This entry is part 2 of 3 in the series RTOS Alternatives.

RTOS Alternatives

Last time, I looked at some of the simplest alternatives to using a Real-Time Operating System. The problem is, as soon as you need both accurate timing and prioritised tasks, you are out of luck — a foreground/background system would need a separate interrupt source per task priority, which can bring its own problems to the table:

Graph of predictability and functionality against number of interrupt sources

In order to meet our requirements and avoid these issues, we really need a scheduler… luckily, they aren’t too hard to write. The simplest of all schedulers is the Time-Triggered Co-operative (TTC) scheduler, in which tasks are released by a single timer interrupt (hitting the green ‘sweet spot’ on the above graph). This differs from foreground/background scheduling in that tasks are actually executed from the main function and not from the interrupt handler itself.

Continue reading Simple Co-Operative Scheduling →


Handling Delays without Blocking


This entry is part 3 of 3 in the series RTOS Alternatives.

RTOS Alternatives

In an earlier article we looked at the design and implementation of a time-triggered scheduler, but we didn’t consider the implications of actually using it. This can take some getting used to if you have never used such a system before. Imagine that we wanted to create a simple traffic light system… in a more traditional event-triggered design, it might look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typedef enum {
    LIGHT_RED,
    LIGHT_RED_AMBER,
    LIGHT_GREEN,
    LIGHT_AMBER
} traffic_light_state;

// Event triggered RTOS version.
void Traffic_Light_Controller(void *parameters) {
    while (1) {
        Set_Lights(LIGHT_RED);
        Delay(15000); // wait 15 seconds
        Set_Lights(LIGHT_RED_AMBER);
        Delay(2000); // wait 2 seconds
        Set_Lights(LIGHT_GREEN);
        Delay(15000);
        Set_Lights(LIGHT_AMBER);
        Delay(2000);
    }
}

In a typical RTOS, calling the Delay function will cause the task to become blocked for the given duration (it is often hard to tell from the documentation if the delay is up to or at least the value — I have seen both). Blocking a task involves removing it from the list of tasks that the scheduler can execute (the ready list) and using a context switch to resume another task instead. Obviously this functionality is not available in our simple scheduler, as we do not have the ability to save and restore contexts (which generally requires platform-specific assembly code).

Continue reading Handling Delays without Blocking →