System Function Calls

Many of the System Function built into MIRTOS are exposed for general use. These routines may be accessed in two ways.

The first way is to access them indirectly using the ICALL and/or IJMP microcontroller (or "MCU") instruction, as appropriate, by loading the index into R30 and then calling or jumping to (again, as appropriate) to absolute address 0, which is named SoftVector in the example code.

The second way is to use each one's Addresses###.Def (see the links below) in the 128-entry System Function Jump Table. It is not anticipated that the first 125 will change, but the last three (3) very well might.

For routines that have a MUST use note, using the ICALL when the IJMP is specified (or vice versa) will very likely cause a system crash and certainly cause data corruption. For routines that do not have that note, either an ICALL or IJMP may be used, depending on stack usage at that point, of course. Note, however, that using any form of a JMP instruction when trying to use a routine which returns a value is really not that useful.

The general Register usage rules for subroutines, (unless otherwise noted):
* R0 is a temporary "scratch" Register; assume any called routine may have changed it,
* R1 should always contain the value zero (0), but may be used and restored, if needed,
* R2 through R17, R28 and R29 contain system variables; although they may also be used, they MUST restored to their prior system value on exit,
* R18 through R27, R30 and R31, like R0, may all be used without saving and restoring them.

Arguments are passed in Registers R25 to R18, with BYTE values occuping WORD Register pairs. Refer to the examples and documentation of each to understand the idea of how each of these work. Each function's documentation lists which Register(s) can possibly be altered by that function. Most routines preserve some or all of Registers R0, R18 to R27, R30, and R31 in order to ease the burden of repeated Register save/restore requirements for their callers.

These rules may seem somewhat familiar. They are the same as those used by the AVR compiler and the Arduino IDE and its GCC compiler. Since there is nothing objectionable with those rules, and they may already be familiar, they were simply reimplemented for MIRTOS. It also allows Assembly code generated by those compilers to be more easily incorporated into a MIRTOS-based device.

Index  System Function Name Description Routine aliases and notes
0 PushAll Push Registers R31 through R0, in that order PushAllRegisters; MUST use CALL or ICALL
1 PopAll Pop Registers R0 through R31, in that order PopAllRegisters; MUST use JMP or IJMP
2 StackAlloc50 Allocate 50 BYTEs on the stack MUST use CALL or ICALL
3 StackFree50 Free the 50 BYTEs previously allocated by StackAlloc50 MUST use CALL or ICALL
4 StackAlloc250 Allocate 250 BYTEs on the stack MUST use CALL or ICALL
5 StackFree250 Free the 250 BYTEs previously allocated by StackAlloc250 MUST use CALL or ICALL
6 Calculate_UBRR Given the data rate, calculate the USART Baud Rate Register (UBRR) WORD value
7 Check_BG_Task See if there is any Background task (printing, specifically) to process
8 ICALL_IfValid_EEPROM Call a subroutine if the EEPROM WORD passed points to an initialized WORD Initialized here means any value except 0xFFFF
9 ICALL_IfValid_PGM Call a subroutine if the FLASH pointer passed points to an initialized WORD Initialized here means any value except 0xFFFF
10 ReadAtoDValue Read one of the eleven Analog Input values GetAtoDValue
11 ReadFuseBYTE Read one of the MCU Fuse BYTEs or the MCU Lock BYTE
12 ReadSignatureBYTE Read one of the MCU Signature BYTEs or the MCU Oscillator Calibration BYTE
13 millisLowBYTE Read the low order BYTE (0 to 255) of the milliseconds rollover counter
14 millisLowWORD Read the low order WORD (0 to 65,530) of the milliseconds rollover counter
15 millis Read the unsigned LONG (0 to 4,294,967,295) milliseconds rollover counter
16 SystemSecondsLowBYTE Read the low order BYTE (0 to 255) of the seconds rollover counter
17 SystemSecondsLowWORD Read the low order WORD (0 to 65,535) of the seconds rollover counter
18 SystemSeconds Read the unsigned LONG (0 to 4,294,967,295) seconds rollover counter
19 msTimerBYTE Determine if a 0 to 250 millisecond timer has completed its time
20 msTimerWORD Determine if a 0 to 65,535 millisecond timer has completed its time
21 msTimerULONG Determine if a 0 to 4,294,967,290 millisecond timer has completed its time
22 SecTimerBYTE Determine if a 0 to 250 Seconds timer has completed its time
23 SecTimerWORD Determine if a 0 to 65,530 Seconds timer has completed its time
24 CheckIndexAndTimer Check both for a valid uVars.B[##] index and a related timer has completed its time
25 CRC Generate a 16-bit CRC over a range of SRAM
26 RunningCRC Add another BYTE into a CRC calculation already in progress
27 meminit Initialize a range of SRAM btyes to some constant value memset
28 memcpy Copy a range of SRAM to another SRAM location Handles any range overlapping correctly
28 strchr Search for a specific character in an SRAM ASCIIz string
30 strcmp Case-sensitive comparison of one SRAM ASCIIz string with another
31 strcpy Copy an ASCIIz character string from one SRAM location to another Handles any range overlapping correctly
32 strlen Determine the number of BYTEs in an ASCIIz string in SRAM
33 ReadEEPROM_BYTE Read a single BYTE from EEPROM ReadEEPROM_1BYTE or ReadEEPROM
34 ReadEEPROM_WORD Read 2 successive BYTEs from EEPROM, low order BYTE first ReadEEPROM_2BYTEs
35 ReadEEPROM_ULONG Read 4 successive BYTES from EEPROM, low order first to high order last ReadEEPROM_4BYTEs
36 WriteEEPROM_BYTE Write a single BYTE to EEPROM WriteEEPROM_1BYTE or WriteEEPROM
37 WriteEEPROM_WORD Write 2 successive BYTEs to EEPROM, low order BYTE first WriteEEPROM_2BYTEs
38 WriteEEPROM_ULONG Write 4 successive BYTEs from EEPROM, low order first to high order last WriteEEPROM_4BYTEs
39 meminitEEPROM Initialize a range of EEPROM BYTEs to some constant value memsetEEPROM
40 memcpyEEPROM Copy a range of EEPROM into an SRAM buffer Because SRAM is the default copy destination
41 memcpySRAMtoEEPROM Copy a range from SRAM to EEPROM memcpyRAMtoEEPROM
42 memcpyEEPROMtoEEPROM Copy a range of EEPROM to another EEPROM location Handles any range overlapping correctly
43 strlenEEPROM Determine the number of BYTEs in an ASCIIz string in EEPROM
44 ReadPGM_BYTE Read a single BYTE from the FLASH, or PROGRAM memory which MIRTOS exposes ReadPGM_1BYTE or ReadPGM
45 ReadPGM_WORD Read 2 successive BYTEs from FLASH memory, low order BYTE first ReadPGM_2BYTEs
46 ReadPGM_ULONG Read 4 successive BYTEs from FLASH memory, low order to high order BYTE ReadPGM_4BYTEs
47 memcpyPGM Copy a range of FLASH memory to an SRAM buffer Because SRAM is the default copy destination
48 strcmpPGM Case-sensitive comparison of a ASCIIz string in FLASH with one in SRAM
49 strcpyPGM Copy an ASCIIz string from FLASH memory to an SRAM buffer
50 strlenPGM Determine the number of BYTEs in an ASCIIz string in FLASH memory
51 EraseFLASHPage Reset all (128 or 256) BYTEs of a PROGRAM memory page to 0xFF Only when logged on in either Manager or Admin mode
52 FindFirstNumericDigit Search a range of SRAM for a numeric (0 through 9) ASCII character
53 FormatULONGHex Format an UNSIGNED LONG INTEGER (32-bit) value as an ASCIIz hexadecimal string
54 FormatULONG Format an UNSIGNED LONG (32-bit) value as an ASCIIz decimal string
55 FormatWORD Format a WORD (16-bit or UNSIGNED INTEGER) value as an ASCIIz decimal string
56 FormatCopyAndPrint Designed for the three (3) subroutines above to copy and/or print the resulting string
57 High4BitsToPORT Convert the 4 high bits of R24 to the SRAM address of the MCU Port 1 = PORTB, 2 = PORTC, 3 = PORTD
58 Low4BitsToPORT Same as above, but uses the 4 low order bits of R24 as the index
59 Low3BitsToBitmask Convert the binary value in the 3 low order bits of R24 to 1, 2, 4, 8, 16, 32, 64, or 128
60 COM1_GetRxCount Determine the number of BYTEs that are in the serial receive buffer
61 COM1_GetRxFree Determine the number of BYTEs left in the serial receive buffer before it overflows
62 COM1_RxPeekHead Get, but do not remove, the next BYTE from the serial port receive buffer
63 COM1_RxPeekTail Get, but do not alter, the last BYTE that is in the serial port receive buffer
64 COM1_Read1CHAR Read and remove a BYTE from the serial port receive buffer
65 COM1_GetTxCount Determine the number of buffered BYTEs awaiting transmission out the serial port
66 COM1_GetTxFree Determine how many BYTEs can be written to the serial port buffer without blocking
67 COM1_TxPeekHead Get the next enbuffered BYTE that will be sent out the serial port
68 COM1_TxPeekTail Get the last character that was sent to the serial port for transmission
69 COM1_WaitForTxEmpty Hold (block), waiting for the serial output buffer to be completely empty
70 COM1_Write1CHAR Output a single character out the serial port; block if necessary
71 COM1_Write Output a specific number of BYTEs out the serial port; block if needed
    "Print" in the lines below means "buffer and emit output to the COM1 serial port"
72 PrintEEPROMASCIIz Print an ASCIIz (NULL terminated) string from EEPROM
73 PrintFLASHASCIIz Print an ASCIIz string from FLASH (or PROGRAM) memory PrintPGMASCIIz
74 PrintSRAMASCIIz Print an ASCIIz string from SRAM PrintRAMASCIIz
75 PrintEEPROMString Print a specific number of BYTEs from an EEPROM location
76 PrintFLASHString Print a specific number of BYTEs from FLASH memory PrintPGMString
77 PrintSRAMString Print a specific number of BYTEs from an SRAM location PrintRAMString
78 Print0xPrefix Print the string "0x"
79 PrintBINARY Print a 9-BYTE string representing a BYTE in BINARY format
80 PrintCHAR Print a single ASCII character
81 PrintBYTE Print a BYTE value in decimal format
82 PrintHexBYTE Print a 2-BYTE string then a BYTE value in hexadecimal format
83 Print0xHexBYTE Call Print0xPrefix() then PrintHexBYTE (BYTE)
84 PrintWORD Print a WORD value in decimal format
85 PrintHexWORD Print a 4-BYTE string then a WORD value in hexadecimal format
86 Print0xHexWORD Call Print0xPrefix() then PrintHexWORD (WORD)
87 PrintScaledULONG Print an UNSIGNED LONG value as a REAL, scaled by a post-decimal digit count
88 PrintNewLine Print the ASCII Carriage Return and Line Feed characters
89 PrintSpace Print a single ASCII space character
90 PrintSpaces Print a series of ASCII space characters
91 Print1SpaceAnd1CHAR Print one ASCII space character then one other ASCII character
92 Print1CHARAnd1Space Print one ASCII character then an ASCII space
93 PrintDescAndHexBYTE Print an ASCIIz string then the numeric value in a BYTE
94 PrintDescAndHexWORD Print an ASCIIz string then the numeric value in a WORD
95 PrintEqualDecWORD Print an ASCII equal sign, a space then call FormatWORD (WORD)
96 PrintAllAINs Print the hexadecimal value of all eleven Analog Inputs
97 PrintMainProgramHz Print the number of times the main loop executed during the prior second
98 PrintScriptProgramHz Print the number of script instructions executed during the prior second PrintUserProgramHz
99 ASCIIToHex Parse two ASCII BYTEs into the hexadecimal value which they represent
100 HexToASCII Convert the low order nybble of R24 to the ASCII character representing it
101 UpperCase Convert any BYTE from ASCII 'a' to 'z' to its equivalent 'A' to 'Z' value
102 NegateLONG Form the negative value of a LONG (4-BYTE) variable
103 Divide2LONGs Divide one SIGNED LONG INTEGER (32-bit) value with another one
104 Divide2ULONGs Divide one UNSIGNED LONG (32-bit positive) value with another one
105 Multiply2ULONGs Multiply one UNSIGNED LONG value with another one
106 MultiplyULONGbyBYTE Multiply an UNSIGNED LONG with a BYTE (unsigned 8-bit) value
107 ParseValue Convert a string to its signed or unsigned LONG INTEGER numeric equivalent
108 ParseValueAfter Search for a specific character and if found, call ParseValue (SZPtr+1)
109 PseudoRandom Generate a pseudo-random UNSIGNED LONG value
110 RandomBYTE Generate a scaled pseudo-random BYTE value
111 RandomULONG Generate a scaled pseudo-random UNSIGNED LONG value
112 DiscreteInput Read the value of a specific Discrete Input or Output
113 DiscreteOutput Turn one of the Discrete Outputs either ON or OFF
114 ProcessCommand Request that the system command processor execute a text command
115 nRF_CommandHandler Handle all nRF24L01+ commands (those that begin with 'N') from MCU logic
116 nRF_Initialize Power the nRF24L01+ down, load all default values, and it power back up
117 nRF_Read1Register Read one of the nRF24L01+ (1-BYTE or 5-BYTE) Registers
118 nRF_SPI_Command Send a command BYTE and up to 32 data BYTEs to the nRF24L01+
119 nRF_Write1Register Write one of the nRF24L01+ (1-BYTE or 5-BYTE) Registers
120 WS2812_Command Output a series of BYTEs to a port or ports using the WS2812 protocol
121 WS2812_Cmd_PortSet Same as WS2812_Command above, but skips over the Port checking and setting logic
122 DumpMemory Format and print a range of SRAM, EEPROM or FLASH
123 DumpRegisters Conditionally format and print all MCU Register values
124 DumpRegs_Begin Unconditionally format and print the MCU Registers
125 DumpStack Format and print the contents of the MCU stack
126   Unused in 328P       Spare (presently just a "RET" in the 328P)
" PrintFLASH_Seg0 Print a string located in the first 64K of FLASH (1284P and 2560)
127   Unused in 328P       Spare (presently just a "RET" in the 328P)
" PrintFLASH_Seg1 Print a string located in the second 64K of FLASH (1284P only)
" PrintFLASH_Seg3 Print a string located in the third 64K of FLASH (2560 only)

The two greyed-out System Function names above indicate presently unused indices in the 328P. Each simply returns at this time, although it could be used for something in the future. Each does perform a function in the 1284P and 2560 versions of MIRTOS, though the last one differs between the two microcontrollers (MCUs.)

There is a second jump table in MIRTOS for both the 1284P and 2560 MCUs that is not available in the 328P.

There are a number of constant definition files to include at the beginning of your assembly language source code files. If not specified by numeric MCU in the name, each file below is for all three (3) supported MCUs. Consider including this block (some depend on the .INCLUDE order):

; All INCLUDE files should be in the same directory as this .ASM source code (or)
;  use the "-I" parameter to set the AVR-AS "Include" directory where they are located:
.INCLUDE "CommonDefs.Def"        ; TRUE, FALSE, YES, NO, BIT_PV_*, et.al.
.INCLUDE "BinDefs.Def"           ; The B0 to B11111111 definitions
.INCLUDE "Indices.Def"           ; All 128 indirectly-accessed system jump indices
.IF PROCESSOR == 328
   .INCLUDE "IOM328P.Def"        ; Register definitions for the ATmega328P
   .INCLUDE "Addresses328.Def"   ; All 128 328P system routines' Jump Table addresses
   .INCLUDE "SystemSRAM328.Def"  ; Names and addresses of 328P system SRAM variables
.ENDIF
.IF PROCESSOR == 1284
   .INCLUDE "IOM1284P.Def"       ; Register definitions for the ATmega1284P
   .INCLUDE "Addresses1284.Def"  ; All 128 1284P system routines' Jump Table addresses
   .INCLUDE "SystemSRAM1284.Def" ; Names and addresses of 1284P system SRAM variables
.ENDIF
.IF PROCESSOR == 2560
   .INCLUDE "IOM2560.Def"        ; Register definitions for the ATmega2560
   .INCLUDE "Addresses2560.Def"  ; All 128 2560 system routines' Jump Table addresses
   .INCLUDE "SystemSRAM2560.Def" ; Names and addresses of 2560 system SRAM variables
.ENDIF
.IFNDEF APushAllRegisters
   .ERROR "Exiting: definition files not pulled in."
.ENDIF
.INCLUDE "SystemEEPROM.Def"      ; Names and addresses of system EEPROM variables
.INCLUDE "SystemFLASH.Def"       ; Names and addresses of system FLASH constants
.INCLUDE "nRF24L01.Def"          ; Register and variable names for nRF radio use
Since Addresses###.Def and Indices.Def contain similar information, selecting which to include depends on how you want to access the Operating System routines. For example, these three blocks of code do the very same thing:
SetSameColor:
.INCLUDE "Indices.Def"
   LDI     R30, I_PushAll      ; Load the index of the PushAll routine
   JMP     ASoftVector         ; Call into the System Call table
   RCALL   ASharedSetup        ; Call the local shared setup routine
        ...
   LDI     R30, I_PopAll       ; Load the PopAll index
   JMP     ASoftVector         ; Exit, restoring all registers used
The code above would require 14 BYTEs of FLASH memory. It can be recoded to require fewer BYTEs, expecially if more system calls are required by the code within the section contracted to "..." below. This first block of code below would require 12 BYTEs of FLASH memory to implement:
SetSameColor:
.INCLUDE "Indices.Def"
   LDI     R30, I_PushAll      ; Load the index of the PushAll routine
   RCALL   ALocal_SoftVector   ; Call into the System Call table
   RCALL   ASharedSetup        ; Call the local shared setup routine
        ...
   LDI     R30, I_PopAll       ; Load the PopAll index to restore and exit
Local_SoftVector:
   JMP     ASoftVector
When using Addresses###.Def, there is no need to load R30, but each system function is called using an ABSOLUTE address (i.e., a LONG or FAR CALL), and this code would require 10 BYTEs of FLASH:
SetSameColor:
.INCLUDE "Addresses328.Def"
   CALL    APushAll            ; Call the PushAll routine
   RCALL   ASharedSetup        ; Call the local shared setup routine
        ...
   JMP     APopAll
Of course, it wouldn't hurt anything to include both an Addresses###.Def and the Indices.Def files, since they don't conflict with one another. Either system routine access method may then be used as desired.

There is also a way to extend the system jump table to 256 entries, using the FAR (i.e., 4-BYTE) vector at addresses 0x3EFC in the 328P, or 0x1ADFC in the 1284P, or 0x3ABFC in the 2560.