Holon 11 Multi Tasking
A task (or thread) is a part of the program that is running in parallel with other parts of the program. At any moment in time only one part is in control, but control passes rapidly from one task to the next and this gives the illusion that the tasks are all executing at the same time.The price for this magic is a little more complexity in the application. The real time kernel of Holon 11 has been carefully designed to provide the important features of a multi tasking system, yet to make the mechanism clear and easy to use. The real time kernel is included with the developer's version of Holon 11. The following examples are provided as an introduction and an illustration of using tasks in Holon.
Here is a simple task routine, which keeps incrementing the memory location $100. You can use the code view of Holon 11 to see the task running.
: TaskRoutine
begin 1 $100 +! Pause again ;
The word Pause is the task switcher, which passes control to the next task. Tasks pass control deliberately. In practice this simple scheduling is highly effective.
20 30 Task myTask TaskRoutine
This defines the task myTask, gives it 20 byte of return stack and 30 byte of data stack area, and makes myTask control the program word TaskRoutine.A task only makes sense if there is at least one more task in the program. Otherwise the task is the program. Holon 11 also treats the main word as a task. The main word is the word that you call from the monitor or activate at cold start in the EPROM. The main word uses the main data and return stacks, and if it is the only "task" in the program, there is no task switching and you can forget about the tasking mechanism. But now we have a task and therefore we implement the main word as a task routine too.
: MainRoutine
begin 1 $102 +! Pause again ;
We are ready to start the tasking machine.
: RunProgram
InitTasking init myTask MainRoutine ;
When you execute RunProgram and let the tasks run, the host shows a small square at the lower right corner and waits for the program to return control to the monitor. But the program remains in the task loops. Therefore, press the <Esc> key to regain control of the host. The host is still online because the monitor (PMON or EMON) is controlled by interrupt, and the interrupt routine runs in parallel with the program tasks.
Now you can look into the running program, press <F6>. You should see heavy traffic in $100 and $102.
Tasks need to exchange data and to signal events. For example, one task may wait for a signal from another task. The simple solution is to define a global variable and set and read the variable from the tasks. One task could read the variable and call Pause as long as the variable contains zero. The other task would write a non-zero value to the variable in order to signal the event. Holon 11 packs this mechanism in the object type Channel and offers you a clearer syntax. The following example describes the use of channels.
Channel Message
: Receiver
begin waitfor Message $100 ! again ;: Sender
begin $100 @ send Message 1 $100 +! again ;20 20 Task RTask Receiver
: RunCTasks
InitTasking init RTask Sender ;
20 20 Task STask Sender
: Main
begin Pause again ;: RunCTasks
InitTasking init RTask init STask Main ;
Tasks are fine for creating timed delays in a program. Without tasking the program is blocked for the delay time. Task delays let you create pulses, say for PWM, controlling step motors and much more. Only the delayed task is blocked while waiting. I assume here that there is a LED attached to PORTA bit 0 in the target.
: LED-on
1 PORTA c! ;: LED-off
0 PORTA c! ;: InitLED
1 DDRA c! ;
The following example makes the LED blink.
: Blinking
InitLED
begin LED-on 400 msec
LED-off 800 msec
again ;20 20 Task BTask Blinking
: BMain
begin 1 $102 +! Pause again ;: RunBlinker
InitTasking init BTask StartTimer BMain ;
Execute RunBlinker and let the tasks run. Watch location $102 to see the main task running while the word Blinking is delayed.
The timing is based on the real time interrupt (RTI) of the 68HC11. The RTI generates an interrupt every 4.1 ms, which is the granularity (tick) of our task timing. The word StartTimer enables the RTI. The timer keeps running until you call StopTimer or reset the target system.The timing mechanism is activated by the word msec. The task is delayed by the given number of milliseconds.
msec calculates the number of ticks and calls wait, which makes the current task sleep for this amount of ticks. The timer interrupt routine decrements the tick number in all waiting tasks. When the tick number is zero, the task is active and runs as soon as the scheduler calls it again.
The task sleeps for the delay period. The word Pause is not needed. The word wait calls Pause and the scheduler skips the sleeping task.
A task switch takes 40 µs (2 MHz system clock).
You have everything under control. The real time kernel is fully defined in the target. Step through the task routines and also through the sequence of the task switch. The steps are displayed in the source text.