HEX File Documentation


Summary

A .hex file is usually an Intel HEX file: compiled firmware for a microcontroller (Arduino, AVR, PIC, ARM) stored as plain-text ASCII records, each line starting with a colon. It is not run on a PC; you flash it onto the chip with a programmer such as the Arduino IDE or avrdude. Because it is text (MIME text/plain), any editor opens it, but the two hex digits per byte make it larger than the raw binary it carries.

Technical details

FeatureValue
Full nameIntel HEX (hexadecimal object record format)
File extension.hex, .ihex, .ihx
MIME typetext/plain
Format typePlain-text ASCII record format carrying binary firmware
DeveloperIntel
Introduced1973 (for Intel 8-bit microprocessors)
SpecificationIntel Hexadecimal Object File Format, Revision A (1988)
Open standardYes — publicly documented, royalty-free
BinaryNo — printable 7-bit ASCII only
Record startColon : (0x3A) begins every line
Record types00 data, 01 EOF, 02/04 extended address, 03/05 start address
Address field16-bit, big-endian, per record
Max data per record255 bytes (byte-count field is one byte)
Integrity checkOne two’s-complement checksum byte per record
End markerThe record :00000001FF
Typical contentCompiled firmware for AVR, PIC, ARM, 8051 microcontrollers
Byte overhead~2–3× the raw binary (two ASCII chars per byte plus framing)
Related formats.srec, .s19, .mot (Motorola S-record), .eep, .bin, .elf
Key conversionHEX → BIN via avr-objcopy -I ihex -O binary
Specification URLen.wikipedia.org/wiki/Intel_HEX
Structure at a glance (Intel HEX record)
:10010000214601360121470136007EFE09D2190140

Intel HEX is plain text, so there is no binary magic number; every line instead begins with a colon : (0x3A). Reading the fields of the line above: : start code, 10 byte count (16 data bytes), 0100 load address, 00 record type (data), then the 16 data bytes 21 46 01 36…01, and a final 40 checksum. The checksum is the two’s complement of the sum of every preceding byte in the record (low byte only). A file always ends with the end-of-file record :00000001FF.

What is a HEX file?

Most files named .hex are Intel HEX files: compiled firmware for a microcontroller, written out as lines of printable text rather than raw binary. Intel defined the format in 1973 to carry 8-bit machine code across the serial links, paper tape, and PROM programmers of the era, where a channel could only be trusted with printable characters. The format outlived that hardware because it is simple, self-checking, and survives email and copy-paste intact. When you compile an Arduino sketch, or build a project in Microchip Studio for an AVR or PIC, the toolchain’s final output is a .hex file that a programmer then writes into the chip’s flash memory.

The word “hex” here refers to the hexadecimal digits the file is written in, not to a hex editor. A separate, unrelated meaning exists (a generic hex dump of some other file’s bytes), covered near the end. Everything in between is about the Intel HEX record format: what each line contains, how the checksum is computed, and how addresses beyond 64 KB are encoded.

The record line: colon, byte count, address, type, data, checksum

An Intel HEX file is a list of records, one per line, and nothing else. Every record is pure ASCII and follows the same fixed layout. A colon opens the line, then each subsequent byte is written as two hexadecimal characters.

:  BB  AAAA  TT  DD DD DD ... DD  CC
|  |   |     |   |                |
|  |   |     |   |                +-- checksum      (1 byte, 2 hex chars)
|  |   |     |   +------------------- data          (BB bytes)
|  |   |     +----------------------- record type   (1 byte)
|  |   +----------------------------- address       (2 bytes, big-endian)
|  +--------------------------------- byte count BB  (1 byte: number of DATA bytes)
+------------------------------------ start code ':' (0x3A)

The byte count (BB) is a single byte, so a record carries at most 255 data bytes; in practice tools emit 16 or 32 per line for readability. The address is a 16-bit big-endian value giving the memory location of the first data byte in the record. The record type selects what the line means, and the data is the actual payload. The final byte is a checksum over everything from the byte count onward. Because each byte occupies two hex characters, the ASCII file is roughly twice the size of the binary it represents, plus the colon, address, type, and checksum framing on every line.

Record types 00 through 05

The single record-type byte is what lets a flat list of lines describe a whole memory image, including gaps and address spaces larger than 64 KB. Six types are defined.

TypeNameMeaning
00DataThe address field plus these data bytes place code/constants at that offset.
01End of fileAlways the last record; byte count 0, address 0000. Encoded as :00000001FF.
02Extended segment addressSets bits 4–19 of the address (multiply by 16), the old 8086 segment scheme.
03Start segment addressInitial CS:IP for x86; ignored by most microcontroller flashers.
04Extended linear addressSets the upper 16 bits of a 32-bit address; the modern way to exceed 64 KB.
05Start linear addressThe 32-bit program entry point (EIP), informational for most flashers.

The 16-bit address inside a data record can only span 64 KB. To place code higher in memory, a type 04 extended-linear-address record appears first and supplies the top 16 bits; every following data record’s 16-bit address is then combined with that base until the next 04 record changes it. The older type 02 does the same job with a 4-bit shift instead, a legacy of segmented x86 addressing. A well-formed file always closes with the type 01 record, which is why :00000001FF is the universal signature of the last line.

The checksum byte: a two’s-complement guard

The last two hex characters of every record are a checksum that lets a reader reject a corrupted line before it is flashed. The rule is exact: sum all the decoded bytes of the record (the byte count, both address bytes, the type byte, and every data byte), keep the least-significant 8 bits, and take the two’s complement of that. Equivalently, the checksum is the value that makes the 8-bit sum of the entire record (including the checksum itself) equal to zero.

Record:   :10010000214601360121470136007EFE09D2190140
Sum of    10+01+00+00+21+46+01+36+01+21+47+01+36+00+
bytes:    7E+FE+09+D2+19+01                     = 0x0BC0
Low byte: 0xC0
Two's comp of 0xC0 = 0x100 - 0xC0            = 0x40  -> checksum "40"

A verifier can skip the subtraction entirely: add every byte in the line including the trailing checksum and confirm the low 8 bits are 00. This catches single-bit flips and most transmission damage, but it is a checksum, not a cryptographic hash: it will not detect deliberate tampering. That is one reason firmware should come only from a trusted source.

Firmware, EEPROM and the flash workflow

A .hex file describes where bytes go in a device’s program memory, not how to run them on a PC. The addresses in its data records are chip addresses: byte 0 of the microcontroller’s flash, not an offset in RAM on your computer. Flashing is the act of writing those bytes to those addresses. With an AVR and avrdude the command is avrdude -p m328p -c usbasp -U flash:w:firmware.hex; the Arduino IDE wraps the same avrdude underneath. Program memory goes in the main .hex; a microcontroller’s separate EEPROM is often shipped as a second file with the .eep extension in the identical Intel HEX format, flashed to a different memory space.

The most useful conversion is HEX to a flat binary image, which simply strips the ASCII framing and fills the addressed bytes into a raw file: avr-objcopy -I ihex -O binary in.hex out.bin, or the SRecord toolkit. The reverse (BIN to HEX) is equally common when a bootloader or programmer wants records. Turning a .hex back into an .elf with symbols is not possible, because the Intel HEX file only ever held addresses and bytes, never the debug and symbol tables the compiler discarded when it emitted the hex.

Intel HEX is one of a small family of ASCII object-record formats. The main alternative is the Motorola S-record (.srec, .s19, .mot), which uses the same idea with different framing: each line begins with the letter S and a type digit (S0 header, S1/S2/S3 data with 16-, 24-, or 32-bit addresses, S9/S8/S7 termination), and its checksum is a one’s complement rather than two’s complement. Tektronix HEX is a third, rarer variant. All three encode the same thing (bytes placed at addresses, line-checksummed) and tools like SRecord convert freely between them, which is why a build system can usually emit whichever a given programmer expects.

The other meaning: a generic hex dump

A minority of .hex files are not Intel HEX at all but a hex dump: a human-readable transcript of some other file’s raw bytes, produced by a hex editor or a tool like xxd or hexdump. These have a different shape, typically three columns per line: an offset, the bytes in hex, and an ASCII rendering.

00000000  89 50 4e 47 0d 0a 1a 0a  00 00 00 0d 49 48 44 52  |.PNG........IHDR|
00000010  00 00 02 00 00 00 01 80  08 06 00 00 00 f0 7d 3f  |..............}?|

There are no colons, no per-line checksums, and no record types; the leftmost column is an offset into the dumped file, not a target memory address. A dump like this is a view of another file (here a PNG), not firmware to flash. The quick test is the first character of the lines: a colon means Intel HEX firmware; an offset followed by a two-column hex/ASCII layout means a hex dump. If the lines are neither, the file may simply be a raw binary that someone renamed to .hex, in which case a hex editor (HxD, Hex Fiend, GHex) will show its real header bytes.

Frequently asked questions

Why does every Intel HEX line carry its own checksum?

Because the format was built for lossy 1970s serial and paper-tape links, where a single flipped bit could brick a device. A per-record two’s-complement checksum lets a programmer verify each line in isolation and refuse a damaged record before writing it to flash, rather than discovering the corruption only after the chip is bricked.

How does a 16-bit address field cover a chip with more than 64 KB of flash?

It does not on its own. A type 04 extended-linear-address record supplies the upper 16 bits of a 32-bit address, and every following data record’s 16-bit field is added to that base. Each new 04 record moves the window, so the file can address the full 4 GB space in 64 KB pages.

References