Introduction red_ball.gif (129 bytes)



Multitasking enables a complex job to be implemented by designing separate tasks that operates independently or cooperates. Each task must so simple that it can be described by some sequential behavior. Each task is simple, but the total collection of tasks enables a complex job to be solved.

State machines and timeslicing are two popular multitasking methods with long traditions. State machines have been used to design complex systems with high reliability requirements. State machines requires that the task is split into states. The state machine stays in one state at a time, and switch to another state when the specified conditions are met. Actions are performed during the transitions. States represent a situation that is stable for some time interval. State machines can be implemented on ALL PICmicros, also on the smallest PIC16C52.

Timeslicing means that the kernel interrupts each process after some milliseconds and give control to another task. Thus, each task is given CPU processing at regular intervals. This mechanism is general but requires that the kernel can pop and push program addresses on the stack, and is thus not available on the midrange PICmicro devices.

Designing processes for timeslicing is very similar to designing independent programs. Programmers find this to be natural and straight forward. State machines are usually more complex to design than a process. At least there are more code writing to get the definitions right.

  State Machines Timeslicing Systems
Fast response +  
Code readability   +
Ease of design   +
Predictability +  
Max response delay +  
Reliability +  
Debugging +  

State machines have faster response than a timeslicing system. One of the reasons for this is that state machines does not require the context to be saved during a task switch. Timeslicing is done by interrupt and requires that CPU registers, stack and local workspace are saved before a new task can start execution. The second reason for the slower response is that each task executes for a predefined time period before control is given to the next task. So, when many tasks are executing, the delay becomes longer. Pre-emptive scheduling may cure much of the slow response and make a timeslicing system more predictive. Still, state machines are faster because each task is divided into small fragments by the programmer.

Debugging a timeslicing system can be extremely difficult. State machines are significantly easier to debug. State machines operates independently of interrupts, and the individual states can be transmitted to the outside world and displayed on a monitor. This have shown to be very efficient during debugging.

State machines scores highest on the reliability issues also. Designing a RTOS is an very complex task, and RTOS kernels bugs can be a problem. Because of the interrupt mechanisms, both application and RTOS bugs are often not easily reproduced. Using the reset button is not satisfactory on a real-time system. State machines operates without a RTOS kernel and without the interrupt mechanism.

Easier code writing seems to be the only advantage of a timeslicing system over state machines.

Deterministic Multitasking

The idea of Deterministic Multitasking is to make state machines look more like system processes. This enhances readability and makes code writing easier. Still, the concept is fully compatible with state machines, and inherits all the advantages.

An Example Task

The task ventilationControl() controls ventilation on/off depending on temperature. The behavior is:

  1. switch ventilation off
  2. wait until high temperature
  3. switch on ventilation
  4. wait until the temperature goes below limit again
  5. delay 100 seconds until stopping ventilation
  6. keep ventilation on if the temperature goes high again while waiting
  7. Go to step 1 (turn ventilation off)

An implementation of ventilationControl() as a state machines may look like:

char stateVC;
void ventilationControl(void)
    switch (stateVC)  {

      case 0:
        ventilation = Off;
        stateVC = 1;

      case 1:
        if (!highTemperature)

        stateVC = 2;
        ventilation = On;

      case 2:
        if (highTemperature)

        stateVC = 3;

      case 3:
        if (!timeout1)  {
            if (highTemperature)
                stateVC = 2:
        stateVC = 0;

Note that there are no wait loops in a state machine. At each iteration, a short check is performed to determine if it is time to change state. The iterations are performed by making calls to the function regularly.

The new concept of deterministic multitasking allows the task to be written like a procedure or process. Note that the implementation is fully equivalent to the above state machine definition.

Task ventilationControl(void)
    ventilation = Off;

    while (!highTemperature)

    ventilation = On;


    while (highTemperature)

    while (!timeout1)  {
        if (highTemperature)
            goto VENTILATION_ON;
    restartTask(); // restart this task
    //ventilation is turned off at next startup

The main difference from the state machine definition is the hiding of state information and insertion of waitState(). This enables the compiler to select the state during compilation. The size of the above task is only 22 instructions, plus code in main for starting and calling the task (3 instructions).

The ventilationControl() implementation uses active waiting while the timer is decremented. This allows the delay to be truncated if the temperature goes high again. Unconditional waiting can be implemented using the delay() function which hides the waitState().

A typical application area is process control. Several tasks can be executed concurrently. They can operate independently or cooperate. One of the risks with multitasking is deadlocks. This can be solved by writing supervisors tasks that look for exceptions and deadlocks, both internally or externally.

The main program is simple:

void main( void)
    // initialize IO

    startTask( ventilationControl);
    // start other tasks

    while (1)  {
        // handle IO: sample AD channels, etc.
        // decrement software timers

        taskSlicer();  // execute tasks

LEANSLICE is the name of the implemented deterministic multitasking. It is available on the EXTENDED compiler editions. More details, multitasking examples, detailed documentation and compiler demo editions supporting LEANSLICE  is found on the LEANSLICE main page.

End line