PIC18F4321 Hex Read-Out: Why a .bin Can Come Back Byte-Swapped

Ask for the hex file, not the binary. A PIC18F4321 reads out as 16-bit instruction words, and every format in the chain — programmer, Intel HEX, the tool that “just converts it” — treats those words as two bytes in a particular order. Get that order wrong and the file programs perfectly and runs garbage.

The device is an 8 KB part: 4,096 instruction words, 512 bytes of SRAM, 256 bytes of data EEPROM, 36 I/O pins, a 10-bit ADC with thirteen channels and both a CCP and an enhanced CCP module. It shares a datasheet with the 4 KB PIC18F4221 — same package, same peripherals, different flash size — which is why the two get confused when a replacement is being sourced.

Word Memory, Byte Files

The CPU fetches a 16-bit word at a time and the program counter counts bytes, stepping by two. Intel HEX, however, is a byte format: each record carries a byte count, a byte address and up to 16 bytes of payload. A programmer writing a PIC18 image therefore splits every instruction word into two bytes, low half first.

An 8 KB image becomes 512 records of 16 bytes. Nothing in that chain is ambiguous — until a tool converts the hex to a raw .bin. Written byte-by-byte, that file is correct. Written word-by-word by a tool that assumes big-endian storage, every instruction comes out with its halves swapped, and the result looks like plausible data.

The tell is at address zero. The reset vector normally holds a GOTO, whose opcode puts 0xEF in the high half of the word — which lands in the *second* byte of a little-endian dump. If 0xEF appears in the first byte instead, the halves were swapped. It takes ten seconds to check and it saves a day of chasing a “dead” blank part.

What a .bin Throws Away

A raw binary covers one contiguous address range. The PIC18F4321’s memory does not fit that model:

Region Address Size Survives a .bin?
Program flash 0x000000 8 KB Yes
Config words 0x300000 14 bytes No
Data EEPROM 0xF00000 256 bytes No
Device ID 0x3FFFFE 2 bytes No (read-only)

Dropping the config words is the expensive part. Oscillator mode, brown-out threshold, watchdog and protection state all live there, and a blank device uses whatever the programmer defaults to. The board then runs at the wrong clock or resets under load, and the fault looks like hardware.

Dropping the 256 bytes of EEPROM is quietly worse on this part. That block has almost no room for calibration, so what it holds is identity and history: serial number, accumulated run hours, a saved threshold. A firmware that reads those values at boot will start and misbehave rather than fail outright.

How the File Is Verified

Three checks catch nearly everything. The reset vector must branch into real code, and the interrupt entries at 0x0008 and 0x0018 must resolve inside the image. A filler scan across 64-byte blocks finds any region the read did not actually retrieve. And two independent reads must produce the same checksum — one read is a sample, two matching reads are evidence.

That work sits in chip extraction analysis, and it is where a bad dump gets caught before it becomes a bad production run.

Asking for the Right Deliverable

If the image is going to be programmed into a blank part, ask for Intel HEX with the config and EEPROM regions included, and state the byte order explicitly if a .bin is required. Reading the program memory should cover all three regions; a supplier who only delivers the flash range has delivered a file that boots and lies.

For boards in production, extract firmware work usually starts from the marking photograph and the ordering suffix — the suffix tracks mask revisions more reliably than the base part number does. Contact us with those and the format question can be settled before any work is quoted.