INTERRUPT MULTITASKING EXPLAINED
Before considering in detail the multitasking scheme which #ROBIN.TDS provides, we first review the method already built into the Forth ROM. It is included here because for many applications it is a better choice, but is easily forgotten. Although it is a different multitasking method there is compatibility with even Pre-emptive Multitasking and both can be used in the same program.
One pass around the loop of a background task is performed at regular intervals with the precise time defined by the user. This scheme is particularly useful when there are a number of events occurring at pre-set intervals. The background task can handle all of them leaving the foreground task free for asynchronous work. For example a set of timers can be decremented each second to emulate those in PLCs (Programmable Logic Controllers), see file #PLC.TDS.
Using Interrupt Multitasking there is only one parameter stack and user-variables, number formatting area and PAD are common to both tasks. However a second return stack is maintained (above the old one) for the background task. It is particularly economical with memory.
PERIOD LESS THAN 53ms
A separate high-level Forth task can be assigned to any or all of the four external and 39 internal interrupts. The task-switching scheme shown in INTERRUPTS, page 169, executes immediately an event happens-this is often what is needed in real-time systems. Using the Timer 3 Output Compare Interrupt B we can arrange for a regular interrupt to occur at whatever interval is desired up to a maximum of 53.3ms. Now the background program is running 'all' the time and can be considered to be in an infinite loop, just like the foreground program.
This is achieved with the word LATER , which determines the interval between successive runs of the background task. LATER takes a number n from the stack, which is then added to the Output Compare Register B. After a period of time (n times 0.8138�s) the free running counter Timer 3 will again match the Output Compare Register B and we will get another 'loop' of the background program.
The example is in the file #RING.TDS which you can try and modify:
DECIMAL VARIABLE COUNTER
: RINGER ( - ) \ Background task,
\ ring bell every second
COUNTER @ 19 > \ true every 20 passes through
IF \ counter reached its limit
7 EMIT \ ring bell over serial link
COUNTER OFF \ restart counter
THEN 1 COUNTER +! \ count off this pass
61440 LATER RETURN; \ each unit is 814ns, 50ms
\ total, i.e. 1/20 sec
: RING ( - ) \ Start background task RINGER
$FFB0 6 ONE EIS START ; \ enable the OCI B
\ of timer 3
-27 +ORIGIN ASSIGN RINGER \ associate task RINGER
\ with output compare interrupt B of timer 3
Type SET RING return (or RING return if using RAM) to start the background task ( DIS will stop it). A further example is given in the file #MT.TDS.
In a real program you can use the Output Compare Interrupt B Enable (bit 6 of address $FFB0) to turn the background task on and off.
You can pass data from one task to another by means of variables or arrays provided one task writes and the other reads. You might want to disable the interrupt or set a semaphore while this 'mailbox' is being written if an interrupt half way through the write would result in bad data being read by the other task. See RESOURCE LOCKS, page 201.
LONG PERIOD MULTIPLE REGULAR INTERRUPTS
Execution of many background programs at defined time intervals can be achieved using the library program #EVERY.TDS. It is an extension to the above scheme. For example run routine AAAA every 100ms, BBBB every second and CCCC each minute. See the file for a working example but this shows how the multiple regular tasks are defined. Any time period up to 1638.2 seconds (27 minutes) can be used.
: INTWORK \ Interrupt. One pass is made every 1/20
\ second. As many programs as needed can
\ be added but total execution time (should
\ all be called) must be less than 50ms
0.1 EVERY AAAA \ do AAAA every 0.1 sec
1.0 EVERY BBBB \ do BBBB every second
60.0 EVERY CCCC \ do CCCC every minute
50MS RETURN; \ return to foreground program
Another file, #PLC.TDS, shows EVERY in use emulating 8 separate timers of a Programmable Logic Controller.