7 Steps To Writing A Simple Cooperative Scheduler PDF
7 Steps To Writing A Simple Cooperative Scheduler PDF
Scheduler
Jacob Beningo - September 10, 2014
Real-Time Operating Systems (RTOS) have been extremely popular in recent years. Most engineers
will select an RTOS very early on in the design cycle, sometimes even before requirements have
been defined. One of the interesting things about RTOS is that for many MCU-based applications an
RTOS is overkill. The magic of an RTOS really comes into its own when the application requires task
preemption (temporarily suspending a task to switch to a higher priority task and later resuming)
and has hard real-time requirements. There are many instances where a much simpler, cooperative
scheduler will fit the requirements just as easily.
A cooperative scheduler still allows tasks to be scheduled through the use of a background periodic
timer that creates a system tick just like in an RTOS. The difference is that rather than having
priorities and preemption, the cooperative scheduler only executes tasks that occur at a time
periodic interval. If two tasks are due to run at the same time, the task higher up in the task list runs
first followed by the second and so on. The cooperative scheduler allows for soft real-time behavior
but through the use of interrupts and other mechanisms can also meet hard real-time needs as well.
One of the great advantages of using a cooperative scheduler is that they are fairly simple and
straight forward compared to an RTOS. Debugging an RTOS can be extremely complicated and is
usually very painful. A cooperative scheduler on the other hand has very few pieces and is much
easier to debug. In fact, a cooperative scheduler can be designed and implemented in just a few easy
steps. They also use very little flash and RAM. The cooperative scheduler that is presented in this
example can be downloaded from http://bit.ly/1oh8sV5
● The scheduler shall use a single interrupt driven timer to keep track of system time
● Scheduler shall be written so that it can be reused from one project to the next
● The scheduler shall be capable of scheduling periodic and background tasks
● The scheduler shall be easily configured through the use of a configuration table
The definition of this structure is pretty straightforward. The only potentially complex component to
the definition is the use of a function pointer to call the task code. In this example all tasks return
void and take no parameters. To learn more about function pointers you can visit Embedded.com.
In this example, things are kept simple and only the scope of the variable is set. This example
consists of three different tasks. The first, is a background task. This task is executed when there are
no other tasks that need to be executed. It is defined by setting the interval to 0, ensuring that each
loop through the scheduler results in it being ran. This is a task where perhaps polling code (gasp!)
might be placed.
The other two tasks in the table define periodic tasks of 10 and 100 milliseconds. The
INTEVAL_xxMS definitions are #define statements that specify the number of system timer ticks
necessary for the interval to be reached. For example, if the system tick is only 10 milliseconds, then
INTERVAL_10MS would be 1. Then again if the system tick is 1 millisecond, then INTERVAL_10MS
would instead be 10. These could also be defined in an enumeration.
With these two pieces of information, the main loop will start by retrieving the current system tick.
In a 32-bit system this is a trivial endeavor since the reading and writing of a 32 bit tick variable is
atomic. Next, each task entry that exists in the task configuration table is looped through and
examined. If the interval of the task is set to 0 (a constantly running background task), then it is
executed. If on the other hand the interval is nonzero then some math is performed to determine if
the difference between the last time the task ran and the current time is greater than or equal to the
task interval. If it is then the task will be executed.
Conclusions
As can be seen the implementation of a cooperative scheduler is pretty simple and straight forward.
There aren’t many moving pieces and once the scheduler is built, if done properly it can be reused
from one project to the next. The only piece that needs to be changed is the system tick timer and
then the task configuration table. While such a simple scheduler doesn’t come with all the bells and
whistles of today’s RTOS, it is truly amazing how many applications this simple scheduler actually
does apply to.
Jacob Beningo is an embedded systems consultant and lecturer who specializes in the design of
resource constrained and low energy devices. He works with companies to decrease costs and time
to market while maintaining a quality and robust product. He is an avid tweeter, a tip and trick guru,
a homebrew connoisseur and a fan of pineapple! Feel free to contact him at [email protected] or
at his website www.beningo.com.
Related articles: