-
Notifications
You must be signed in to change notification settings - Fork 66
STM8 eForth Background Task
TG9541/STM8EF supports a background task, a very simple to use feature for simple INPUT-PROCESS-OUTPUT
control tasks that can be developed, and tested, interactively. It is sufficient for most "Ladder Logic" or Arduino-style embedded control applications. A "task word" is called in a 5ms cycle (it shouldn't exceed 4ms runtime else the interactive console gets slowed down or stalls). It provides a complete context switch for the Forth virtual machine. As the design goal never was full multitasking the background task doesn't provide multitasking features like semaphores. Resource sharing with the foreground task (usually the console) must be managed on the application layer (usually through exclusive access). There is a trade-off: no interpreter and parser words that influence the console are allowed in a background task.
The background task feature has the following properties:
- the variable
BG
holds the address of a background task word - fast preemptive context switch of eForth VM with dedicated data stack and pad
- the background task's own
BASE
andHLD
get initialized with every run -
?KEY
andEMIT
use configurable I/O words (e.g. W1209 uses 7S-LED display and pushbuttons) - cyclic increment of 16 bit timer ticker variable
TIM
Control tasks are often non-interactive and use analog or digital I/O. Developing and testing the background task can be done interactively. With the Forth command line the task operation can be inspected, and parameters can be altered.
The following code demonstrates non-interactive use of the Background Task:
\ blinky using the background task timer to flash all board outputs
VARIABLE timemask ;
$40 timemask !
: blinky timemask TIM OVER AND = OUT! ;
' blinky BG ! \ set background word, start flashing
$80 timemask ! \ interactive: slower flashing
Due to dedicated character I/O support background tasks can also be used for implementing a simple user interface (like a parameter settings menu).
The following code is example for an interactive background task: a very simple RAM monitor for the W1209 board:
( W1209 memory monitor - key mapping set:'A', +:'B' , -:'D' )
VARIABLE monaddr
: inc ( -- ) 1 monaddr +! ; \ increment monaddr
: dec ( -- ) -1 monaddr +! ; \ decrement monaddr
: cadr ( -- ) DUP 66 = IF inc THEN 68 = IF dec THEN ; \ react on keys "+" and "-"
: disp ( -- ) monaddr BKEY IF ? ELSE @ C@ . THEN ; \ show monaddr while key pressed
: ledmon ( -- ) HEX ?KEY IF cadr ELSE disp THEN ; \ react on key
128 monaddr ! \ set address
' ledmon BG ! \ start in background
The task will then be executed by the 5ms ticker interrupt. It can be stopped by changing the execution word address to null, e.g. 0 BG !
.
The startup routine is vectored, and using 'BOOT
an initialization word can be started to set the background vector BG.
Note: the following technical details about the background task from the PoC are outdated. However, some of the details of the final design are explained here
The Background task PoC does a context switch, where the essential data of the Forth virtual CPU is retained. There is a small dedicated data stack, which gets reset with every tick. In theory, the data stack could be shared, but in practice determining the SP in an interrupt routine is somewhat tricky (it may be in X, or in XTEMP).
Using the background task is simple:
- write a word that doesn't require input from the stack
- write the address of the word to the address provided by
BG
Example:
VARIABLE timer
: tSet TIM 300 + timer ! ;
: tTest TIM timer @ - 0 < ;
: delay KEY@ IF tSet THEN tTest IF 1 ELSE 0 THEN OUT! ;
' delay BG !
Press a key on the W1209 (or run tSet
from the Forth command line) to activate the relay for about 1.5 s.
There is problem with this lightweight approach: the state of the Forth system is stored in the USR
area (0x60 .. 0x7F). As we won't use the outer interpreter, or the compiler in the background task, not all data in USR
is relevant. However, formatted output uses some USR
variables, and memory in PAD!
With the option HAS_BACKGROUND
active, the RAM memory has the following layout:
-----------------+
0000h .. 004Fh : Free for user variables
-----------------+
0050h .. 005Fh : Module variables
-----------------+
0060h .. 007Fh : USR area (and some core storage, e.g. XTEMP)
-----------------+
0080h .. HERE-1 : user dictionary
-----------------+
HERE .. HERE+79 : gap for new word definitions
PAD .. SPP-DEPTH : scratchpad memory, e.g for text output
-----------------+
SPP-DEPTH..032Fh : SSP (data stack, growing down)
0330h .. 034Fh : BSSP (background data stack, growing DOWN)
-----------------+
0350h .. 039Fh : TIB (Terminal Input Buffer)
-----------------+
03A0h .. 03FFh : RPP (return stack)
-----------------+
When no background process is running, a memory dump of the area with SPP, BSSP, TIB, and RPP can look like this:
HEX 300 F0 DUMP
300 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________
310 0 0 0 0 0 0 0 0 0 0 0 0 0 70 0 70 _____________p_p
320 0 0 0 20 0 30 3 27 3 29 0 10 3 20 3 FF ___!_!___)_+_0__ <- SPP
330 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________
340 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________ <- BSPP 16 words
350 33 30 30 20 46 30 20 44 55 4D 50 6A 6A 6A 6A 6A 300 F0 DUMPjjjjj - TIB start 80 bytes
360 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A jjjjjjjjjjjjjjjj
370 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A jjjjjjjjjjjjjjjj
380 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A jjjjjjjjjjjjjjjj
390 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A jjjjjjjjjjjjjjjj <- TIB end
3A0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________ -> RPP
3B0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________
3C0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________
3D0 0 0 0 0 0 0 B 0 A 0 3 81 B 0 3 81 _______________
3E0 0 21 C1 23 33 3 24 0 CF 0 82 6F 8C A7 0 0 A! #0_A%__(_:__o
3F0 95 30 0 C 95 6D 0 0 0 10 89 78 91 8B 91 CD _____|_____x___M <- RPP 96 bytes
Note that the TIB was filled with j
for better visibility.
On the W1209, the following code brings the background task ticker counter TIM
on the 7S-LED display:
: show BASE @ HEX TIM 7S . BASE ! ;
' show BG !
Note that the current PoC doesn't have a dedicated USR
area for the background task. As a consequence, when the output formatting routines are used in the background for the 7S-LED display, the output of DUMP will be mangled.
The following code stops the background routine, and dumps the RAM contents:
0 BG !
HEX 300 F0 DUMP
300 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________
310 0 0 0 0 0 0 0 0 0 0 0 0 0 70 0 70 _____________p_p
320 0 0 0 20 0 30 3 27 3 29 0 10 3 20 3 FF ___!_!___)_+_0__
330 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________
340 0 0 0 0 0 70 0 EE 97 6C 0 39 0 60 0 A _____p_n_l_9_`__ <- BSPP used in background
350 48 45 58 20 33 30 30 20 46 30 20 44 55 4D 50 45 HEX 300 F0 DUMPE
360 58 20 54 49 4D 20 37 53 20 2E 20 42 41 53 45 20 X TIM 7S . BASE
370 21 20 3B 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A ! ;jjjjjjjjjjjjj
380 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A jjjjjjjjjjjjjjjj
390 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A 6A jjjjjjjjjjjjjjjj
3A0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________
3B0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________
3C0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ________________
3D0 0 0 0 0 0 0 0 89 9 23 3 24 9 1 3 81 _________#_$___
3E0 0 81 38 23 33 3 24 0 F1 0 82 6F 8C A7 0 0 A! #0_A%__(_:__o
3F0 95 30 0 C 95 6D 0 0 0 10 89 78 91 8B 91 CD _____|_____x___M
Conclusions:
- for simple background code the BSPP area with 16 cells (32 bytes) is sufficient
- working without a dedicated
USR
area works for simple tasks - at least the output routines must have a different set of
USR
variables