First of all, the Assembler can only generate code to FLASH since all code in ATmega MCUs resides in FLASH. A command to override that cannot be placed in the source file, but can be issued to the MIRTOS-based device as a segment address, as shown in the header block below.
To begin, start a file called ScriptImage.Asm with this in it:
/****************************************************************************** * * Create Script Image * * Purpose: Create command scripts. * * Notes: To change the destination from FLASH to EEPROM, place this iHex * line before any other iHex line generated: * :02000002E0001C * This tells MIRTOS that to place the iHex data that follows in the * EEPROM segment (address = E000 above) instead of FLASH. * * .STRING generates an ASCIIz (i.e., NULL-terminated string) * .ASCII generates the string without an ending NULL. * * Command strings should NOT end with Carriage Return or Line Feed. * ******************************************************************************/
While command scripts can certainly be input into the EEPROM using "E ## = '##'" command syntax, there are a couple nice things about creating scripts using the assembler instead. The first is that comments can be added to remind youself what you had in mind. The second is that there is no need to see where each command's NULL terminator ended the string in order to know where the next "E" command should begin.
The following code will recreate the image of the Default Boot Sequence contained in Arduino ProMini devices loaded with MIRTOS:
.ORG 0x0B0 ; Tell the Assembler where to begin DefaultProMiniBootSequence: ;01234567890ABCDEF .STRING "; Bootup Init: " ; This is header, but can be omitted .STRING "E 1 ~= 0xC0" ; Disable both Sequencer and Multitasker ; Sequencer = 0x40 and Multitasker = 0x80 .STRING "ES 0x1DF = 0x3A" ; Set the DumpRegisters output format .STRING "N**" ; Load the nRF24L01+ default configuration .STRING "ND+" ; Enable the nRF debug output; same as: ; "ES 0x206 = 0xD1" in the 328P & 1284P ; "ES 0x306 = 0xD1" in the 2560 ; BIT_NRFDDT_CLRERRS, _RX, _TX, _TX_COPY .STRING "P = 8" ; Configure WS2812B for 8 LEDs (24 BYTEs) .STRING "PG=1 " ; Set all LEDs to lowest intensity green .STRING "VW 4 = 900 M" ; Initialize uVars.B[ 3 to 7 ] - 2 WORDs .STRING "TM2 V 4" ; Run a 2-BYTE timer using 2 WORDs above .STRING "PB=1" ; Set all LEDs to lowest intensity blue .STRING "E 0x19 = 0x15" ; Configure output B5 as heartbeat LED .STRING "E 32 = 0x22" ; Configure output C2 as logon status LED .BYTE -1 ; Make sure to end with either 0 or 0xFF
The Assemble command only needs to be executed once since there are no target labels that need to be resolved. It shouldn't generate any errors. This is the Windows command console:
C:\Testing> Assemble ScriptImage C:\Testing>Type ScriptImage.Trm :1000B0003B20426F6F74757020496E69743A20005E :1000C000452031207E3D203078433000455320309C :1000D00078314446203D2030783341004E2A2A00B2 :1000E0004E442B0050203D20380050473D31200029 :1000F00056572034203D20393030204D00544D32A9 :10010000205620340050423D3100452030783139AE :10011000203D20307831350045203332203D2030DD :0501200078323200FFFF :00000001FF C:\Testing>
The block above is the direct output of the ScriptImage.Trm file just created. First, let's examine what is in the target range of EEPROM, then we'll erase it and reload it with out code block. This is the CommTool terminal window:
> DE+ 0xB0 128 00B0: 3B 20 42 6F 6F 74 75 70-20 49 6E 69 74 3A 20 00 ; Bootup Init: . 00C0: 45 20 31 20 7E 3D 20 30-78 43 30 00 45 53 20 30 E 1 ~= 0xC0.ES 0 00D0: 78 31 44 46 20 3D 20 30-78 33 41 00 4E 2A 2A 00 x1DF = 0x3A.N**. 00E0: 4E 44 2B 00 50 20 3D 20-38 00 50 47 3D 31 20 00 ND+.P = 8.PG=1 . 00F0: 56 57 20 34 20 3D 20 39-30 30 20 4D 00 54 4D 32 VW 4 = 900 M.TM2 0100: 20 56 20 34 00 50 42 3D-31 00 45 20 30 78 31 39 V 4.PB=1.E 0x19 0110: 20 3D 20 30 78 31 35 00-45 20 33 32 20 3D 20 30 = 0x15.E 32 = 0 0120: 78 32 32 00 FF FF FF FF-FF FF FF FF FF FF FF FF x22............. > >EL 0xB0 = -1 -1 -1 -1 -1 -1 -1 -1 ; Sets 32 BYTEs to 0xFFs >EC 0xD0 0xB0 32 >EC 0xF0 0xB0 64 >DE+ 0xB0 128 EEPROM contents: 00B0: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 00C0: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 00D0: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 00E0: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 00F0: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 0100: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 0110: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ 0120: FF FF FF FF FF FF FF FF-FF FF FF FF FF FF FF FF ................ >; Login using the '$' first key m>:02000002E0001C m>:1000B0003B20426F6F74757020496E69743A20005E m>:1000C000452031207E3D203078433000455320309C m>:1000D00078314446203D2030783341004E2A2A00B2 m>:1000E0004E442B0050203D20380050473D31200029 m>:1000F00056572034203D20393030204D00544D32A9 m>:10010000205620340050423D3100452030783139AE m>:10011000203D20307831350045203332203D2030DD m>:0501200078323200FFFF m>:00000001FF m>:00000001FF m>; Logout using the '$' first key again >DE+ 0xB0 128 EEPROM contents: 00B0: 3B 20 42 6F 6F 74 75 70-20 49 6E 69 74 3A 20 00 ; Bootup Init: . 00C0: 45 20 31 20 7E 3D 20 30-78 43 30 00 45 53 20 30 E 1 ~= 0xC0.ES 0 00D0: 78 31 44 46 20 3D 20 30-78 33 41 00 4E 2A 2A 00 x1DF = 0x3A.N**. 00E0: 4E 44 2B 00 50 20 3D 20-38 00 50 47 3D 31 20 00 ND+.P = 8.PG=1 . 00F0: 56 57 20 34 20 3D 20 39-30 30 20 4D 00 54 4D 32 VW 4 = 900 M.TM2 0100: 20 56 20 34 00 50 42 3D-31 00 45 20 30 78 31 39 V 4.PB=1.E 0x19 0110: 20 3D 20 30 78 31 35 00-45 20 33 32 20 3D 20 30 = 0x15.E 32 = 0 0120: 78 32 32 00 FF FF FF FF-FF FF FF FF FF FF FF FF x22............. >DEH+ 0xB0 128 EEPROM contents: :02000002E0001C :1000B0003B20426F6F74757020496E69743A20005E :1000C000452031207E3D203078433000455320309C :1000D00078314446203D2030783341004E2A2A00B2 :1000E0004E442B0050203D20380050473D31200029 :1000F00056572034203D20393030204D00544D32A9 :10010000205620340050423D3100452030783139AE :10011000203D20307831350045203332203D2030DD :1001200078323200FFFFFFFFFFFFFFFFFFFFFFFFFF :00000001FF >
This first example is for a script in FLASH that initializes the first two (2) tasks of some task switching (or multitasking) logic. The two tasks start at 0x2800 and 0x2860 in FLASH. Often script logic is placed after the code, and this one shows that it begins at 0x28C0. The startup script above resides in EEPROM, but appending the command "S = 0x2900 F" to it would cause it these two tasks to automatically be started as well.
.ORG 0x28C0 ; Set the starting address in FLASH .STRING "; Node 1 init: " .STRING "E 1 ~= 0x80" ; Disable timed tasks while changing .STRING "E 20 = 96" ; uVars.B[##] adder; 96 + 32 = 128 .STRING "VW 64 = 100 0 0x2800 0" ; Task 1: update the pixels every 100 mSec .STRING "V 71 = 15" ; bits: use PORTC0, PORTC2, and PORTC4 .STRING "VW 72 = 750 0 0x2860 0" ; Task 2: uVars.B Alarm every 750 mSec .STRING "V 79 = 0x20" ; bits: check uVars.B[2], set LED #1 .STRING "E 0x2D = 64" ; Point EEbTaskList_UVIndex at 0x2C0 .STRING "E 1 |= 0x80" ; Enable timed tasks ("multitasking") .STRING "S = -1 E" ; Park the script pointer .BYTE 0xFF ; Make sure the script ends here .PRINT "Scripts created for Node 1."
The next example ...
To do ...
The last example uses the file HEXtoASCII.Inc to perform the conversion from hexadecimal digits to ASCII BYTEs. The final value of ASharedFinish (i.e., the address of the SharedFinish: label) cannot be zero. If it is, the source needs to be assembled again to resolve the address to its correct value.
These could be used as stand-alone routines. It is probably more likely that some multitasking code monitoring an input calls each of these subroutines when that input changes. In fact, the example routine which monitors and input and transmits changes uses this very technique. The filename used below is ScriptExample3.Asm; don't forget to first create the ScriptExample3.Ptr file containing a single space before Assembling.
.ORG 0x1200 ; Specify where it is to begin .INCLUDE "ScriptExample3.Ptr" .IFNDEF ASharedFinish ASharedFinish = 0 ; Prevent errors during Assembly .PRINT "ASharedFinish is zero; assemble again to resolve it." .ENDIF HexValue = ASharedFinish ; Set the address constant to convert from .INCLUDE "HEXtoASCII.Inc" ; Hexadecimal digits to ASCII BYTEs SendOFF: .STRING "; OFF script: " .STRING "N 0x60" ; Change the nRF24L01 from PRX to PTX mode .STRING "N> 'SNPW:Demo_2###'" ; Send a logon string to the unit in which .STRING "N> 'V 2 ~= 1'" ; to toggle the BIT variable OFF; do it SharedFinish: .STRING "; Logoff: " .STRING "N> 'Logoff'" ; Log out of every device .STRING "V 4 = 50 M" ; Setup a BYTE mSec timer at uVars.B[4] .STRING "TM1 V 4" ; Start the 50 millisecond timer .STRING "N*" ; Reload the default nRF config .STRING "S = -1 E" ; Park the script pointer .BYTE 0xFF ; Terminate the script .BALIGN 16, 0xFF, 15 ; Realign to the start of a "sentence" SendON: .STRING "; ON script: " .STRING "N 0x60" ; Change the nRF24L01 from PRX to PTX mode .STRING "N> 'SNPW:Demo_2###'" ; Log into the device to be changed .STRING "N> 'V 2 |= 1'" ; Toggle the BIT variable ON .STRING "S = 0x" ; Build the address of the shared script .BYTE ASCII_Byte5, ASCII_Byte4, ASCII_Byte3, ASCII_Byte2, ASCII_Byte1 ;x .STRING " P" ; Redundant since this script is in FLASH .BYTE 0xFF ; Terminate at the script boundary
This is the .INCLUDE file HEXtoASCII.Inc that was pulled into the ScriptExample3.Asm file above.
/******************************************************************************* * * .INCLUDE file "HEXtoASCII.Inc" * * Purpose: Convert a hexadecimal value ASCII characters that can be included * as a series of up to 8 .BYTE values. * * Assumes: If HexValue is undefined, warn of the likely oversight. * * Passed: HexValue = an unsigned ULONG value (maybe auto converted) * * Returns: ASCII_Byte1 = ASCII character for the least significant Hex digit * ASCII_Byte2 = ASCII character for next more significant Hex digit * . . . * ASCII_Byte8 = ASCII character for the most significant Hex digit * * Alters: Only the eight (8) ASCII_BYTE# character variables * * Example: HexValue = ASharedFinish ; Set the constant to pass * .INCLUDE "HEXtoASCII.Inc" ; Convert Hex digits to ASCII * * * Notes: All ASCII_BYTE#s returned are one of these: 0123456789ABCDEF * ******************************************************************************/ .IFNDEF HexValue .PRINT "Define HexXValue before using .INCLUDE HEXtoASCII." HexValue = 0 .ENDIF ASCII_Byte1 = (HexValue & 0xF) + '0' ; This is the Least Significant digit, .IF ASCII_Byte1 > '9' ; so, if HexValue = 0xE0000002, this ASCII_Byte1 = ASCII_Byte1 + 7 ; would return 0x32 = ASCII '2' .ENDIF ASCII_Byte2 = ((HexValue >> 4) & 0xF) + '0' .IF ASCII_Byte2 > '9' ASCII_Byte2 = ASCII_Byte2 + 7 .ENDIF ASCII_Byte3 = ((HexValue >> 8) & 0xF) + '0' .IF ASCII_Byte3 > '9' ASCII_Byte3 = ASCII_Byte3 + 7 .ENDIF ASCII_Byte4 = ((HexValue >> 12) & 0xF) + '0' .IF ASCII_Byte4 > '9' ASCII_Byte4 = ASCII_Byte4 + 7 .ENDIF ASCII_Byte5 = ((HexValue >> 16) & 0xF) + '0' .IF ASCII_Byte5 > '9' ASCII_Byte5 = ASCII_Byte5 + 7 .ENDIF ASCII_Byte6 = ((HexValue >> 20) & 0xF) + '0' .IF ASCII_Byte6 > '9' ASCII_Byte6 = ASCII_Byte6 + 7 .ENDIF ASCII_Byte7 = ((HexValue >> 24) & 0xF) + '0' .IF ASCII_Byte7 > '9' ASCII_Byte7 = ASCII_Byte7 + 7 .ENDIF ASCII_Byte8 = ((HexValue >> 28) & 0xF) + '0' .IF ASCII_Byte8 > '9' ; The Most Significant digit, so using ASCII_Byte8 = ASCII_Byte8 + 7 ; the same example, this would return .ENDIF ; the value 0x45 = ASCII 'E'