Calling a subroutine each loop through main()

There are instances when tasks are 1) so brief, or 2) need to be called more often than once each millisecond, or 3) contain their own timers. There is a way to execute these types of tasks, but they need to be done with MUCH care, since they can defeat the multitasking functionality of the MIRTOS Operating System and/or hang the microcontroller.

The first thing to do is to code and test the task. Here is an example of a task which is so brief that it can be done without using a timer. It requires only twelve (12) BYTEs of FLASH memory and ten (10) clock cycles, plus the system calling overhead. It simply toggles Discrete Output #2:

ToggleDIO2:
   IN      R25, PORTC          ; Read and freeze the present DIO #2 value
   SBRC    R25, PORTC2         ; If DIO #2 was OFF, skip turning it OFF again
   CBI     PORTC, PORTC2       ; Clear the bit directly to turn DIO #2 OFF
   SBRS    R25, PORTC2         ; If it was ON, skip the next instruction
   SBI     PORTC, PORTC2       ; Set the bit directly to turn DIO#2 ON
   RET
After assembling it to address 0x0FF0, for example, the resulting code can be inserted into the running device. First verify that there are no other routines already at that location or in the vicinity:
>D+P 0xFE0 32
FLASH (program memory) contents:
0FE0:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
0FF0:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
1000:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
>  ; Login with '$' as the first character on this line and send the block
m>:100FF00098B192FD429892FF429A08950000000035
m>:00000001FF
m>:00000001FF
m>D+P 0xFE0 48
FLASH (program memory) contents:
0FE0:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
0FF0:  98 B1 92 FD 42 98 92 FF-42 9A 08 95 00 00 00 00  ....B...B.......
1000:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
m>@ 0xFF0    ; Test - call the subroutine to turn LED #2 ON
m>@ 0xFF0    ; Test - call the subroutine to turn LED #2 OFF
m>                                                                              
There are two steps to cause it to be called each main() cycle. The first is to initialize EEfptrEachMain to point to that address. The second is to enable that system feature by turning BIT_SM_EACHMAIN in EEbSystemMode ON. The example below also shows what impact it has on the device's processing:
>DES
EEPROM contents:
0000:  10 21 00 9F 01 00 84 FF-04 00 FF FF 28 3C 50 FF  .!..........(<..
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 FF 2A FF-FF 14 30 20 00 30 FF FF  $(....*...0 .0..
0030:  80 16 FF FF FF FF FF FF-60 00 B0 00 80 01 FF FF  ........`.......
0040:  FF FF FF FF FF FF 00 2F-FF FF FF FF FF FF FF FF  ......./........
>DES
>EW 0x42 = 0xFF0   ; Set its address in EEfptrEachMain
EEPROM contents:
0000:  10 21 00 9F 01 00 84 FF-04 00 FF FF 28 3C 50 FF  .!..........(<..
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 FF 2A FF-FF 14 30 20 00 30 FF FF  $(....*...0 .0..
0030:  80 16 FF FF FF FF FF FF-60 00 B0 00 80 01 FF FF  ........`.......
0040:  FF FF F0 0F FF FF 00 2F-FF FF FF FF FF FF FF FF  ......./........
>E 4 ^= 16   ; Toggle BIT_RTC_SEC_PRG_HZ in EEbFlags_RTC
>Main program Hz: 2,372
Main program Hz: 2,388
Main program Hz: 2,383
Main program Hz: 2,384
Main program Hz: 2,383
Main program Hz: 2,389
E 1 ^= 4     ; Toggle BIT_SM_EACHMAIN in EEbSystemMode
>Main program Hz: 2,374
Main program Hz: 2,261
Main program Hz: 2,266
Main program Hz: 2,261
Main program Hz: 2,261
Main program Hz: 2,265
Main program Hz: 2,261
E 1 ^= 4
>Main program Hz: 2,248
Main program Hz: 2,384
Main program Hz: 2,388
Main program Hz: 2,384
>                                                                               
The difference seems to be about 1,200 cycles through the main() loop each second, or about 5% of the processing time. With the little subroutine still being called each loop through main, what happens when the FLASH memory which contains that subroutine is reset? The "X 0xFF0" command below will only work in one of the privileged modes.
>   ; Log back in
m>DF+ 0xFE0 48
FLASH (program memory) contents:
0FE0:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
0FF0:  98 B1 92 FD 42 98 92 FF-42 9A 08 95 00 00 00 00  ....B...B.......
1000:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
m>E 4 ^= 16
m>Main program Hz: 2,255
Main program Hz: 2,261
Main program Hz: 2,261
Main program Hz: 2,261
Main program Hz: 2,266
X 0xFF0     ; Reset the block from 0x0F80 through 0x0FFF to all 0xFFs
m>Main program Hz: 2,252
Main program Hz: 2,270
Main program Hz: 2,274
Main program Hz: 2,269
Main program Hz: 2,272
Main program Hz: 2,270
DF+ 0xFE0 48
FLASH (program memory) contents:
0FE0:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
0FF0:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
1000:  FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF  ................
m>Main program Hz: 2,201
Main program Hz: 2,270
Main program Hz: 2,272
m>                                                                              
What happened was that the EachMain() system routine stopped calling the subroutine at 0x0FF0. It uses the ICALL_IfValid_EEPROM System Function and will not call a subroutine when the WORD at its target address is 0xFFFF. That feature is to help prevent system crashes.

A good thing to remember to do at this stage is to both reset the EEfptrEachMain subroutine pointer (to 0xFFFF) and clear BIT_RTC_SEC_PRG_HZ in EEbFlags_RTC. If they remain in their present state and the a different routine is loaded using that location, EachMain() may jump into the middle of that routine. That will create a bug that is very difficult to find or one that requires using the lockout recovery procedure to reset the EEbFlags_RTC variable using jumpers. Those commands are:

>DES
EEPROM contents:
0000:  10 25 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 FF 2A FF-FF 14 30 20 00 30 FF FF  $(....*...0 .0..
0030:  80 16 FF FF FF FF FF FF-60 00 B0 00 80 01 FF FF  ........`.......
0040:  FF FF F0 0F FF FF 00 2F-FF FF FF FF FF FF FF FF  ......./........
>EW 0x42 = -1  ; Reset EEfptrEachMain
>E 1 != 4      ; Clear BIT_RTC_SEC_PRG_HZ
>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 FF 2A FF-FF 14 30 20 00 30 FF FF  $(....*...0 .0..
0030:  80 16 FF FF FF FF FF FF-60 00 B0 00 80 01 FF FF  ........`.......
0040:  FF FF FF FF FF FF 00 2F-FF FF FF FF FF FF FF FF  ......./........
>                                                                              

See also:
    The iHex and erase FLASH block System Commands as well as the longer embedded timers example.