TrimIHex.Exe  program documentation

TrimIHex reads a text file in Intel© Hex format, commonly called iHex, or IHex, or iHEX format (.HEX) and generates a "trimmed" (.TRM) version of it.  Perhaps without exception, an iHex file contains multiple Data Record rows.  A Data Record row with zeros for all its data values is called a "ZeroData Record row" below.  Here is an example of a trivial iHex file that contains only four ZeroData Record rows and an End-Of-File (EOF) Record row of text:
:1000000000000000000000000000000000000000F0
:1000100000000000000000000000000000000000E0
:1000200000000000000000000000000000000000D0
:1000300000000000000000000000000000000000C0
:00000001FF

The function of TrimIHex is to identify and remove each ZeroData Record row which precedes the first Data Record row which is NOT a ZeroData Record row.  The primary purpose for doing that is so the .TRM file contains only the data block to be written to the device.  The side effect is that it substantially shortens the file.  TrimIHex only reads, but does not modify, the original .HEX file.  It reads the .HEX text file specified, line by line, until it finds the first Data Record row which is not a ZeroData Record row.  It discards all the ZeroData Record rows up to that point and begins copying all iHex records to the .TRM file after it finds that first non ZeroData Record row.

The syntax for the TrimIHex program is:
TrimiHEX iHexFile [WriteFile] [/d[=][nnn]] [/h] [/q] [/s[=]string] [/v[+]] [/8]
iHexFile name of the Intel Hex (.HEX) text file to read
[WriteFile] name of the output file to write; *.Trm if unspecified
/d[=][nnn] enable debug mode; optionally, set its value to nnn (1-255)
/h omit the header lines from the output file
/q suppress the startup version output (quiet mode)
/s[=]string section of the TrimIHex.CFG file to read and utilize
/v[+] validate each line's checksum; '+' enables correction mode
/8 output iHex data lines with 8 data BYTE max widths
Note: If no section option is specified, no configuration file is read.

A single .HEX file is created by the AVR-ObjCopy program during the Assembly process.  It is the format which MIRTOS can accept and use to make changes to its memory.  Code for MIRTOS almost always begins at an address in FLASH memory that is higher than 0 (zero = 0x0000), easily accomplished by using an .ORG statement in the Assembly language source code.  When that is done, the iHex file generated contains Data Records with zeros for all FLASH addresses that it consideres unused, which is where the .ORG statement causes the actual code to start.  Since there is almost certainly code which already occupies those lower FLASH addresses, overwriting them is undesirable and most often very counter productive.  The TrimIHex program eliminates each initial ZeroData Record row from the .HEX data set to be written to the MCU.  Upon encountering the first iHex Data Record text row that does not have all sixteen BYTEs as zeros, it will, by default, then copy that row of text, all subsequent iHex Data Record rows, any Extended Segment Address Records (documented below), and the EOF record row to the .TRM output file.  This allows a much smaller "trimmed" file to be sent to the MCU.

The qualifier "by default" in the paragraph above means that there are two exceptions.  Notice the "/S[=]string" optional command line parameter.  That tells the TrimIHex.Exe program to find and open the TrimIHex.CFG text file, read it, line by line, until it finds the specified string enclosed in brackets.  As examples, a command line paramter of "/S328" would cause TrimIHex to look for "[328]" and "/S=NewRoutine" would look for "[NewRoutine]" in TrimIHex.CFG.  The bracketed text marks the beginning of a configuration block, which ends either at the end of the file, or at another row which begins with bracketed text, itself marking the start of the next configuration block.  So, the first exception is to enable TrimIHex to remove the additional, intermediate, ZeroData rows.

Here is an example SetSingleColor.Asm source code file:
SoftVector:                       ; This is located at FLASH address 0x0000

DESTINATION = 0x200 ; The starting address in SRAM
LOOP_COUNT = 0x120 ; = 288, meaning 288 LEDs
RED_INTENSITY = 0

.ORG 0x0D00 ; Set this subroutine's starting address

SetSameColor:
LDI R31, DESTINATION >> 8 ; Load Z with the starting SRAM address of 0x200
LDI R30, DESTINATION & 0xFF
LDI R27, LOOP_COUNT >> 8 ; Load X with the LED count
LDI R26, LOOP_COUNT & 0xFF
LDI R25, 0x80 ; Set the GREEN component intensity
LDI R24, RED_INTENSITY ; Set the RED component intensity (text constant)
LDI R23, 0 ; Set the BLUE component intensity (numeric constant)
RCALL ASetSameColorLoop ; Call the subroutine below to do the work
RET ; And we're done

SetSameColorLoop:
ST Z+, R25 ; Set one pixel's GREEN intensity in SRAM
ST Z+, R24 ; Set the RED and then the BLUE intensities for
ST Z+, R23 ; that same 3-BYTE pixel
SBIW R26, 1 ; Decrement the R27:R26 pair
BRNE ASetSameColorLoop ; Loop back unless R27:R26 just became zero
RET ; Exit when the register pair reaches zero

.ORG 0x0D70 ; Added to demonstrate an unused FLASH area

ExampleText:
.ASCII "Example text" ; This text in FLASH is not utilized by the code above

.BALIGN 16 ; So a 16-BYTE iHex Data Record is generated

When run in the Online Assembler, that code generates an iHex file with 217 lines of iHex records.  There are 216 rows of iHex Data Records and the final row, which is the iHex End-Of-File (EOF) record.  The first 208 iHex Data Record rows look very similar, are all ZeroData Records, and would cause zeros to be written to every FLASH BYTE with an address less than 0x0D00, which was specified by the .ORG statement.  These are the rows which TrimIHex eliminates using its simple, default command line (that is, without any "/S" parameter.)  A very abbreviatated version of the iHex file is presented below.
:1000000000000000000000000000000000000000F0
:1000100000000000000000000000000000000000E0
:1000200000000000000000000000000000000000D0
:1000300000000000000000000000000000000000C0
(202 ZeroData Record rows not shown)
:100CD0000000000000000000000000000000000014
:100CE0000000000000000000000000000000000004
:100CF00000000000000000000000000000000000F4
:100D0000F2E0E0E0B1E0A0E290E880E070E001D045
:100D100008959193819371931197D9F708950000E5
:100D200000000000000000000000000000000000C3
:100D300000000000000000000000000000000000B3
:100D400000000000000000000000000000000000A3
:100D50000000000000000000000000000000000093
:100D60000000000000000000000000000000000083
:100D70004578616D706C65207465787400000000C2
:00000001FF

Notice that there are only three (3) Data Record rows which are not ZeroData Record rows.  The very last row of iHex text is the EOF record.  Assume that SetSameColor.Hex the input file name.  Executing the command "TrimIHex SetSameColor.Hex" causes the SetSameColor.Trm file to be generated.  It begins with seven (7) copyright and informational comment header rows (omitted here) then these eight (8) iHex Data Record rows and one EOF record row:
:100D0000F2E0E0E0B1E0A0E290E880E070E001D045
:100D100008959193819371931197D9F708950000E5
:100D200000000000000000000000000000000000C3
:100D300000000000000000000000000000000000B3
:100D400000000000000000000000000000000000A3
:100D50000000000000000000000000000000000093
:100D60000000000000000000000000000000000083
:100D70004578616D706C65207465787400000000C2
:00000001FF

To configure TrimIHex to eliminate the five (5) intermediate ZeroData Record rows, this very simple TrimIHex.Cfg file could be used:
[RemoveThese5]
X=0x0D20-0x0D6F ; Exclude this range (the semicolon begins a comment)

The command line would then be changed to "TrimIHex SetSameColor.Hex /SRemoveThese5", generating SetSameColor.Trm with the following file contents:
:100D0000F2E0E0E0B1E0A0E290E880E070E001D045
:100D100008959193819371931197D9F708950000E5
:100D70004578616D706C65207465787400000000C2
:00000001FF

If the specified range to exclude contains any Data Record rows which are NOT ZeroData Record rows, the message "Kept line ###", followed by the Data Record text, is output to the console for each one, and that line is written to the output file.  For example, if the line after [RemoveThese5] in that configuration block were modified to this: "X=0x0D20-0x0DFF      ; Exclude this range", then the following line would be output to the console when TrimIHex was run using the same command line shown above:
Kept line 215 :100D70004578616D706C65207465787400000000C2

The second "by default" qualifier is a little different.  When the /8 command line parameter is specified, each Data Record row which contains more than eight (8) data BYTEs is split and generates two (2) Data Record rows.  The "TrimIHex SetSameColor.Hex /SRemoveThese5 /8" command would emit these iHex records to the output file, and would cause the very same data as the longer version above to be written to the target device:
:080D0000F2E0E0E0B1E0A0E246
:080D080090E880E070E001D0EA
:080D1000089591938193719302
:080D18001197D9F708950000BE
:080D70004578616D706C65208F
:080D78007465787400000000AE
:00000001FF

The reason (or need) for the shorter iHex Data Records is that the radios which MIRTOS supports have a maximum message block length to 32 BYTEs.  This limit is part of the protocol imposed by the radios themselves.  These 27-BYTE Data Records can be transmitted in a single message, making it easier to update the FLASH memory in a remote device which is running MIRTOS.  Note that MIRTOS uses two (2) of the 32 BYTEs of each message (BYTE count and Message Index), so only 30 BYTEs of information can be transmitted in each 32-BYTE (maximum) data message.

Here are a few additional background details.  When the "erase FLASH block ####" command is issued to an ATmega microcontroller, using the MIRTOS "X" command for example, it sets all FLASH BYTEs in that block to 0xFF.  That is, all eight (8) BITs of each erased BYTE become logic 1.  The FLASH block sizes are 128 BYTEs for a 328P microcontroller (MCU) and 256 BYTEs for the 1284P and 2560 MCUs.  Although beyond the scope of this document, this "logic 1 when erased" aspect is due to the way that the simplest transistors gates work.  Although it certainly would have been possible to design MCUs to make them be 0 when erased, it would mean both an additional inverting transistor and its unavoidable propagation delay for each FLASH bit.</bunny trail>  When a FLASH change is made, bits can only be directly changed from logic 1 to logic 0.  So, for example, the change of a FLASH BYTE with contents of 13 decimal (= 0x0D = B00001101), to any value other than 12 (= 0x0C = B00001100), 9 (= 0x9 = B00001001), 8 (= 0x08 = B00001000), 5 (= 0x05 = B00000101), 4 (= 0x04 = B00000100), 1 (B00000100), or 0 (B00000000) requires rewriting all 128 or 256 FLASH BYTEs.  When FLASH is erased, all 128 or 256 BYTEs in the block are reset to 0xFF.  When FLASH is rewritten, all of the BYTEs within the block are erased and then as many BYTEs are written as are needed.  MIRTOS handles all of this in the midst of all its other task processing.

There is a format for each Intel© Hex record.  Here are some examples from those shown above:
:100D0000F2E0E0E0B1E0A0E290E880E070E001D045
:100D100008959193819371931197D9F708950000E5
:080D0000F2E0E0E0B1E0A0E246
:080D080090E880E070E001D0EA
:080D1000089591938193719302
:080D18001197D9F708950000BE
:00000001FF

The first required field for an iHex record is a single character: the colon.  All subsequent fields represent hexadecimal values, so their ASCII characters are limited to '0' through '9' and (uppercase) 'A' through 'F'. The next three fields are the BYTE Count, Target Address, and Record Type fields.  All four (4) of those fields are required, as is the last 2-BYTE field, the Record Checksum.  If there are no Data BYTEs, then the Data field is simply omitted.  The number of ASCII characters in the Data field must be twice the number specified in the BYTE count field, since they are each the ASCII representation of an 8-BIT hexadecimal value.  Each value in an iHex Record is in 2-BYTE hexadecimal format, except the Target Address field, which is a 4-BYTE hexadecimal value since it specifies a 16-BIT address.

Record type 0x00 is a Data Record.  Record type 0x01 is the End-Of-File (EOF) Record.  Record type 0x02 is an Extended Segment Address Record, which MIRTOS uses to specify either 64 KBytes address boundaries (for the 1284 and 2560) or the memory type (for all MPUs.)  Record types 0x03, 0x04, and 0x05 are not used by MIRTOS.  Examples of these Extended Segment Address Records which MIRTOS supports and uses:
; The Data Records which follow have FLASH addresses which begin with 0x10000 (1284 and 2560 only):
:020000021000EC
; The Data Records which follow have FLASH addresses which begin with 0x20000 (2560 only):
:020000022000DC
; The Data Records which follow have FLASH addresses which begin with 0x30000 (2560 only):
:020000023000CC
; The Data Records which follow are for EEPROM instead of FLASH; load at EEPROM addresses:
:02000002E0001C
; The Data Records which follow are for SRAM instead of FLASH; load at SRAM addresses:
:02000002F0000C

It's probably a good idea to use a single memory type in any single .TRM file being output to the MIRTOS-based MCU.  Multiple memory types are not actually illegal in the same file, and can be used if done very carefully.  Start with FLASH, if possible.  It's always a good idea to send one or two (EOF) Records if iHex Records selecting EEPROM or SRAM memory have been sent to MIRTOS and it has not been rebooted.  MIRTOS starts out assuming that all iHex records that it receives will apply to FLASH memory, unless told otherwise.  It will remember what type of memory was last used if a single EOF Record is received and continue to write to that type of memory unless a second EOF is received, or the device is rebooted, of course.

The command line parameters for TrimIHex are not case sensitive.  They can be entered in any order, except that the name of the iHex input file must occur before the output file name, if one is specified.  The TrimIHex command line parameter /D[=][nnn] is bitmapped; its eight (8) bitmapped Debug constant values, which may be combined:
     1    Show file location on startup
     2    Show each iHex line read, with line number and BYTE count
     4    Display the configuration file section name as the file is searched
     8    Display each configuration file line read, with line number and BYTE count
    16   Display the data ranges in the configuration file; up to eighty (80) can be specified
    32   Display the byte count, line count and record count for each file as it is processed
    64   Display the Display the record count and line count as the program exits
   128  Display Data Record line information during conversion to 8-BYTE data widths

The /H command line option causes the 7 header lines to be omitted from the output file.  These are the copyright, source file, and creation date information in a comment block. The /Q command line option omits the copyright, version, and creation date output to the console on startup, if there is no input parameter issue.  This feature is particularly useful when TrimIHex is called from a batch file.  Finally, the /V[+] command line parameter causes the checksum of each iHex line input to be calculated and compared to the one contained on that line.  Its plus (+) suboption causes the calculated value to replace any one found to be incorrect.  The default action is to exit the program in error, unless "+" is selected.  This feature can come in handy when moving a block of code from one FLASH address to another AND there is no need to reassemble it (relative and absolute address instruction issues, among others, must be considered as well.)

Downloads page