The operating system I will describe, called TinyRealTime (TRT) was originally written by Dan Henriksson and Anton Cervin (technical report). (See also Resource−Constrained Embedded Control and Computing Systems,
Dan Henriksson, 2006). I extended it, by adding a realtime trace
ability, flexible soft timers, a mutex construct, a system dump and a
simple command shell. The context switch time is a few hundred cycles on
the 8-bit Atmel Mega1284, compiled using GCC. Full documentation is at http://people.ece.cornell.edu/land/courses/ece4760/TinyRealTime/index.html.
A realtime trace facility was added to TRT to enable following which tasks are executing and which semaphores are signaled. There are also to user defined events available. The trace facility uses one port of the MCU to dump data to an oscilloscope. A simple 3-bit DAC is used to convert task number and semaphore number to two separate voltages for display. Each task number adds about 125 mV to the output, so that when task 2, for example, is executing the voltage output is 250 mV. The semaphore number is specified when you initialize a semaphore. The task number starts at zero for the null task, then each task has a number defined by the order in which the tasks were created. Either of the events may be used as a scope trigger or to display. The image shown is from the realtime trace, which gives the task number as a voltage on the top trace and the semaphore number on the bottom trace.
With 4 tasks running, it takes about 700 cycles to perfrom a context switch by signalling a semaphore (Code to test this). The actual time spent in the scheduler ISR (timer1 compare-match) is 390 cycles, plus 70 cycles to store state, plus 70 cycles to restore state equals 530 cycles to service a timer tick. The scheduling scheme is Earliest Deadline First (EDF). Our student have used the kernel for motor controllers, wireless pedometer (http://people.ece.cornell.edu/land/courses/ece4760/FinalProjects/f2013/esc73_jsw267/esc73_jsw267/esc...), ultrasonic nagigators (http://people.ece.cornell.edu/land/courses/ece4760/FinalProjects/f2013/xs46_ebl43/xs46_ebl43/xs46_eb...) and more.
The API supplied with TRT includes core real time routines:
void trtInitKernel(uint16_t idletask_stack)
|Sets up the kernel data structures. The parameter is the desired starck size of the idle task. For a null idle task, a stack size of 80 should be sufficient.
void trtCreateTask(void (*fun)(void*),
|Identifies a function to the kernel as a thread. The parameters
specify a pointer to the function, the desired stack size, the initial release
time, the initial deadline time, and an abitrary data input
sturcture. The release time and deadline must be updated in each task
trtSleepUntil is called. The task structures are
statically allocated. Be sure to configure
the kernel file to be big enough. When created, each task initializes
35 bytes of storage for registers, but
stacksize minimum is
around 40 bytes. If any task stack is too small, the system will crash!
|Terminates the running task.
|Get the current global time in timer ticks.
void trtSleepUntil(uint32_t release,
|Puts a task to sleep by making it ineligible
to run until the release time. After the release time, it will run when
it has the nearest deadline. Never use this function in an ISR. The
- (release time) should be greater than than the execution time
of the thread between
trtSleepUntil calls so
that the kernel can meet all the deadlines. If you give a slow task a
release time equal to it's deadline, then it has to execute in zero
time to meet deadline, and nothing else can run until the slow task
completes. Experiment with this
test code by changing the difference in the
while watching A.0...