# Intel HEX Converter

> Convert Intel HEX, Motorola S-record, UF2 and raw BIN in any direction, with a segment map, per-line checksum results and multi-file merging. Local only.

- URL: https://bytescope.dev/en/intel-hex-converter/
- Locale: en · Also: [ja](https://bytescope.dev/ja/intel-hex-converter.md) · [zh-Hant](https://bytescope.dev/zh-Hant/intel-hex-converter.md)
- Runs: Your firmware never leaves your browser — every file is parsed and rewritten locally.
- Requires: Any modern browser (Chrome, Edge, Firefox, Safari), desktop and mobile.
- Updated: 2026-09-08

## What it does

### Four containers, one pile of addressed bytes

Intel HEX, Motorola S-record and UF2 all say the same thing in three different accents: *these bytes go at this address*. A raw `.bin` says only the first half — it is the bytes with the addresses thrown away, which is why a BIN alone can never tell you where it belongs. Drop any of the four here and the format is worked out from the file itself: `UF2` plus a newline in the first four bytes, a leading `:`, or an `S` followed by a digit. Nothing is guessed from the extension, because half the world names an S-record `.hex` and the other half names it `.s19`, `.s28`, `.srec` or `.mot`. If the detection is wrong for your file — a truncated header, a stripped first line — you can override it per file and the page will tell you what it thought it was looking at.

### A bad checksum has two numbers, not one

Every tool that reads Intel HEX will tell you a line is broken. Very few tell you *how* broken. This one reports both bytes: the checksum written on the line, and the checksum the record's own contents produce. When those differ by a single bit you are looking at a transfer that flipped one, and when they differ by the byte count you are usually looking at a file somebody edited by hand and forgot to recompute. A malformed line also does not swallow the lines after it — line 5 failing has no effect on line 6, so one damaged record in a 200,000-line image costs you one record, not the rest of the file. Everything else that is structurally wrong is named too: data after the end-of-file record, an address record with the wrong length, a record type nobody defined.

### Segments, gaps, and the bytes two files both claim

Once the records are read they collapse into segments — contiguous runs with a start address and a length — and the holes between them are shown as gaps, with the size of each. That is the picture you want before flashing anything: a bootloader at `0x0000`, an application at `0x8000`, and 30 KB of nothing in between that a flat BIN would have to fill with something. When one file writes the same byte twice the range is listed rather than quietly resolved. When *two* files do, the merge is refused outright and every colliding range is shown with the two file names — because the alternative, letting whichever file loaded last win, is how a bootloader disappears without anybody noticing until the board stops enumerating.

### Writing it back out

Any input format converts to any output format. Intel HEX takes a `bytesPerLine` and can be written with or without type-04 extended-linear-address records. S-record lets you pin the address width — `S1`/`S9` for 16-bit, `S2`/`S8` for 24-bit, `S3`/`S7` for 32-bit — or leave it on the narrowest form that fits the highest byte actually written. UF2 takes a payload size and a family id, and the id is checked against the published family table so a typo shows up as an unknown id rather than as a board that refuses the drag-and-drop. A flat BIN takes a fill byte for the gaps, defaulting to `0xFF` because that is what erased flash reads as. All of it runs in a Web Worker inside this tab: nothing is uploaded, and the firmware you are reverse-engineering stays your business.

## Limits

Does not flash a device (use esp-flasher or avr-uploader), does not disassemble or edit the code inside an image, and refuses to merge files that write the same address rather than letting one win.

## FAQ

### Why is the BIN much larger than the HEX file it came from?

Because a flat binary has no addresses. If your image writes 4 KB at `0x0000` and 4 KB at `0x0800_0000`, the BIN has to be everything in between as well — that span, not the payload. The segment map shows the gaps and their sizes before you convert, and the page refuses to allocate an enormous file without asking first. If the span surprises you, the usual cause is a stray record placing a few bytes far away from the rest, and the segment table will show it as a tiny segment on its own.

### What address should I give a raw BIN file?

Whatever address your flasher would have written it to, because the file itself does not know. A BIN is loaded at `0` here and you supply the real load address in its offset field — `0x08000000` for STM32 internal flash, `0x10000` for a typical ESP32 application, `0x0` for a bootloader. Getting this wrong is not a subtle failure: convert to Intel HEX afterwards and the addresses on every line will tell you immediately whether it landed where you meant.

### Why will it not merge my bootloader and my application?

Because they both write at least one of the same bytes, and there is no correct way to pick a winner. The conflicting ranges are listed with the two file names and the exact addresses; usually one image was built with the wrong linker script, or an application image still carries a copy of the vector table. Fix the overlap — or shift one file with its offset field — and the merge goes through. Byte-identical overlap is still refused, because two builds of the same thing writing the same bytes is a situation you want to know about rather than to have smoothed over.

### Which UF2 family id do I need?

The one your bootloader expects: `0xE48BFF56` for RP2040, `0x1C5F21B0` for ESP32, `0x68ED2B88` for SAMD21, `0x55114460` for SAMD51, `0x1B57745F` for nRF52, `0x57755A57` for STM32F4. The full published table is matched against whatever you enter, and a UF2 file with no family id at all is also legal — that is what the flags field being zero means. If a board silently ignores a UF2 you dragged onto it, a wrong or missing family id is the first thing to check.

### Is my firmware uploaded anywhere?

No. The files are read with the File API, parsed in a Web Worker in this tab, and dropped when you close it. There is no upload step, no account and no server side to this page — which matters more here than on most tools, because an unreleased firmware image is exactly the kind of file people are told not to paste into online converters.

## Related tools

- [ESP Firmware Flasher](https://bytescope.dev/en/esp-flasher.md) — Write the converted image to an ESP32 or ESP8266 over USB.
- [AVR / Arduino Uploader](https://bytescope.dev/en/avr-uploader.md) — Send an Intel HEX file to an Arduino or AVR board over the serial bootloader.
- [Hex Viewer / Editor](https://bytescope.dev/en/hex-editor.md) — Open the raw bytes, find the field you need, and edit it.
- [CRC Calculator](https://bytescope.dev/en/crc-calculator.md) — Work out which checksum a device expects at the end of an image.
