To simulate concurrent processing on a single processor, tasks are selected for execution, either cooperatively or preemptively. Since the entire machine state, including the stack, must be saved to successfully switch to another task in a preemptive Operating System, a significant amount or SRAM is needed. The 328P has 2,048 BYTEs of SRAM, so the overhead of saving and switching contexts using only the device's native resources really limits what can be accomplished if one wants to do anything else of any use, other than just prove that it can be done.
On the other hand, cooperative multitasking allows multiple tasks to be run sequentially. A "Task List" is configured and each task is called at its appointed time, often called "task scheduling." To determine if it is time for a specific task to run, timers are needed. Only a toy Operating System burns time in a busy-wait loop. Perhaps it's all that's needed for just turn a few LEDs on and off, but for doing anything more ambitious, the microcontroller must be able to do something else while it is waiting for a preset amount of time to pass.
In this Operating System, multiple tasks are configured to run in this cooperative method. Each task is configured using an 8-byte structure: a WORD timer, a WORD starting time, a WORD address pointer, a BYTE of option bits, and an unused BYTE, made available for you to use for any purpose for that task.
The structure of each task in the Task List: +--------+--------+--------+--------+--------+--------+--------+--------+ | Timer update | Time saved at | Service routine | Option | | | interval WORD | the last update | address pointer | bits | unused | |LSByte MSByte|LSByte MSByte|LSByte MSByte|1111#111| | +--------+--------+--------+--------+--------+--------+--------+--------+ +0 +1 +2 +3 +4 +5 +6 +7Each of these structures must be contained within the uVars.B[##] memory area, for which 32 to 256 BYTEs may be allocated. Since each requires 8 BYTEs, it means that there can be, at most, (256 / 8 =) 32 tasks configured using this feature. If all 32 are configured, few other features can be used, with EachMain and Scripts being the exceptions. The BIT_SM_TASKLIST bit in EEbSystemMode
The number of BYTEs added to the minimum uVars.B[##] configuration of 32 bytes is set using EEbConfig_uVars. Its valid values are 0 to 224 (= 0xE0); values higher than 224 are treated as if they were zero. The index of the first uVars.B[##] memory used by the Task List is set using EEbTaskList_UVIndex. Each task in a Task List immediately follows the prior one. There can be only one (1) Task List.
Option BIT | Name | Description |
---|---|---|
0 | BIT_TL_SECONDS | Select timer: 0 = mSec, 1 = Seconds |
1 | BIT_TL_SKIP_ALL | Skip processing entirely (don't even update the timer) |
2 | BIT_TL_SKIP_ICALL | Update the timer, but do not call the service routine |
3 | BIT_TL__spare3__ | (unused, spare, available to be used) |
4 | BIT_TL_DEBUG1 | Display the MCU state before the timer check |
5 | BIT_TL_DEBUG2 | Display it after the (mSec or Sec) timer has been checked |
6 | BIT_TL_DEBUG3 | Display it before the service routine is called (or skipped) |
7 | BIT_TL_DEBUG4 | Display it after the service routine returns (or is skipped) |
> DES EEPROM contents: 0000: 10 21 00 9F 01 00 84 FF-04 00 FF FF 28 3C 50 FF .!..........(.P. 0010: C0 00 3F FF 40 08 03 67-FF 25 74 FF FF FF FF FF ..?.@..g.%t..... 0020: 24 28 05 00 FF 0A FF FF-FF 14 30 20 00 30 FF FF $(........0 .0.. 0030: 80 16 FF FF FF FF FF FF-60 00 B0 00 90 01 FF FF ........`....... 0040: FF FF FF FF FF FF 00 AF-FF FF FF FF FF FF FF FF ................ >
The EEPROM BYTE variables of interest are highlighted above.
EEbSystemMode,
at address 1, shows Task List processing is not enabled.
EEbConfig_uVars,
at address 20 (= 0x14) sets the uVars.B[##] adder to 64 (= 0x40),
for a total of 96 BYTEs.
EEbTaskList_UVIndex,
at address 45 (= 0x2D) sets the first task's starting point as
uVars.B[ 0x30 ] (= 0x2B0.)
This configuration would mean that there could be no more than 6 tasks. The next block displays all of uVars.B[##] contents before starting, confirming that it contains all zeros.
There are a number of example routines which came with the default MIRTOS Operating System. Assuming that they are in place (if not, see the note after the block), the following sequence of commands could be entered to initialize an example with four (4) tasks: three with LEDs (well, DOs, actually) and one with serial output. Note that the "250 M" and "5 S" commands write the present system milliseconds (M) and seconds (S) values into the second WORD of each structures:> DV+ SRAM contents: 0280: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0290: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 02A0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 02B0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 02C0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 02D0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ >
> E 20 = 64 ; Set EEbConfig_uVars - uVars.B[##] has 96 bytes >E 0x2D = 0x30 ; Set EEbTaskList_UVIndex; start at uVars.B[ 48 ] = 0x2B0 >ESW 0x2B0 = 250 M ; Interval: 250 mSec >ESW 0x2B4 = 0x3008 ; Pointer to the subroutine which simply toggles DO 2 >ESW 0x2B8 = 500 M ; Interval: 500 mSec >ESW 0x2BC = 0x300C ; Pointer to the subroutine which toggles DO 3 >ESW 0x2C0 = 1000 M ; Interval: 1000 mSec >ESW 0x2C4 = 0x3010 ; Pointer to the subroutine which toggles DO 4 >ESW 0x2C8 = 5 S ; Interval: 5 Sec >ESW 0x2CC = 0x3040 ; Subroutine which displays the VIn value in Eng Units >ES 0x2CE |= 1 ; Change the timer from mSec to Seconds >E 1 |= 1 ; Make sure automatic AtoD conversions are enabled >DV+ ; Display the uVars.B[##] data before starting: SRAM contents: 0280: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0290: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 02A0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 02B0: FA 00 DD 38 08 30 00 00-F4 01 60 3B 0C 30 00 00 ...8.0....`;.0.. 02C0: E8 03 F1 3D 10 30 00 00-05 00 10 00 40 30 01 00 ...=.0......@0.. 02D0: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ >E 32 += 0x80 ; Turn off the Login Status (was using DO/LED #4) >E 1 |= 0x80 ; Enable the Task List processing feature >5.02 Volts 5.02 Volts 5.01 Volts 5.02 VoltsE 1 ^= 128 ; Disable Task List processing (also in LEDs) E 32 += 0x80 ; Reenable the Login Status on LED #4 >
A script could also have been used above to run all of the commands above one right after another.
The ICALL_IfValid_PGM System Function is used by the Task List Processing routine. If the WORD pointer to (i.e., which has the address of) the service routine is either zero or points to a FLASH address which evaluates to 0xFFFF, the ICALL is not performed. An 0xFFFF value is most likely an uninitialized PROGRAM location or is pointing up into FLASH used by the Operating System. For example:
> DF+ 0x3000 144 FLASH (program memory) contents: 3000: 80 E2 09 C0 81 E2 07 C0-82 E2 05 C0 83 E2 03 C0 ................ 3010: 84 E2 01 C0 85 E2 28 2F-E0 E7 0E 94 00 00 EA E7 ......(/........ 3020: 0E 94 00 00 68 2F 61 50-82 2F EA E7 01 D0 E1 E7 ....h/aP./...... 3030: 0C 94 00 00 FF FF FF FF-FF FF FF FF FF FF FF FF ................ 3040: 88 E0 EA E0 0E 94 00 00-EA E7 0E 94 00 00 9C 01 ................ 3050: 40 E0 50 E0 90 E0 81 E0-78 EB 60 E0 EA E7 10 D0 @.P.....x.`..... 3060: E8 E6 0E D0 EA E7 0C D0-42 E0 E7 E5 09 D0 9C E3 ........B....... 3070: 8E E3 BC 01 E9 E5 04 D0-CB 01 E9 E4 01 D0 E8 E5 ................ 3080: 0C 94 00 00 FF FF FF FF-FF FF FF FF FF FF FF FF ................ >DF+H 0x3000 144 FLASH (program memory) contents: :1030000080E209C081E207C082E205C083E203C01A :1030100084E201C085E2282FE0E70E940000EAE791 :103020000E940000682F6150822FEAE701D0E1E79B :103030000C940000FFFFFFFFFFFFFFFFFFFFFFFFFC :1030400088E0EAE00E940000EAE70E9400009C019C :1030500040E050E090E081E078EB60E0EAE710D0FB :10306000E8E60ED0EAE70CD042E0E7E509D09CE3C1 :103070008EE3BC01E9E504D0CB01E9E401D0E8E549 :103080000C940000FFFFFFFFFFFFFFFFFFFFFFFFAC :00000001FF >; Login using '$' as the first character on the command line m>E 1 ^= 0x80 ; Reenable processing of the Task List 5.02 Volts 5.02 Volts 5.01 Volts 5.02 Volts X 0x3020 m>df+ 0x3000 0x90 FLASH (program memory) contents: 3000: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 3010: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 3020: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 3030: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 3040: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 3050: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 3060: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 3070: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 3080: 0C 94 00 00 FF FF FF FF-FF FF FF FF FF FF FF FF ................ m>; Nothing is output, but no crash after clearing FLASH; reload it: m>:1030000080E209C081E207C082E205C083E203C01A m>:1030100084E201C085E2282FE0E70E940000EAE791 m>:103020000E940000682F6150822FEAE701D0E1E79B m>:103030000C940000FFFFFFFFFFFFFFFFFFFFFFFFFC m>:1030400088E0EAE00E940000EAE70E9400009C019C m>:1030500040E050E090E081E078EB60E0EAE710D0FB m>:10306000E8E60ED0EAE70CD042E0E7E509D09CE3C1 m>:103070008EE3BC01E9E504D0CB01E9E401D0E8E549 m>; The next command writes that entire 128-byte block to FLASH m>:00000001FF m>5.01 Volts 5.02 Volts 5.02 Volts 5.02 Volts 5.01 Volts 5.02 VoltsE 1 ^= 0x80 ; Toggle Task List processing back OFF >
MIRTOS was designed to be somewhat forgiving, realizing that people need to be given a little grace when working with a live system. Although not encouraged to do what was demonstrated to be possible, it shows that this O.S. is more robust than perhaps imagined.
Each service routine is called with these Register values: | |||
R1 | = | 0 (preserve, which means that it can be used, but restore it with this same value before returning) | |
R3:R2 | = | incremented on each loop through main; reset at the end of each second | |
R5:R4 | = | starting SRAM address for this task's config (in uVars.B[##] space) | |
R7:R6 | = | last available starting uVars.B[##] address (preserve it) | |
R8 | = | EEbFlags_OS (EEPROM address 8) read once each second (preserve it) | |
R9 | = | the BIT_TL_* bOptionBits (i.e., structure's 7th) BYTE (can change debug bits) | |
R15 | = | uVars.B[##] global adder (preserve it) | |
R23:R22 | = | the timer update interval (first WORD of the structure) | |
R27:R26 | = | starting time saved when the time period which just expired began; may be zero | |
R29:R28 | = | uVars.B[##] global base address (preserve it) | |
R31:R30 | = | WORD address of this service routine's FLASH memory location |
See also: | |
The editing, erase FLASH block and iHex System Commands as well as the Examples code, specifically, the source code for the ToggleDIOs.Asm and ShowVcc.Asm routines, which was used above. |