← All Series
RA8 Custom Binary Formats
7 parts · ~378 min total
July 13, 2026 · 44 min read
RA8D2RenesasEmbeddedBinary FormatsBare-MetalCFile FormatsReverse Engineering
I have been building bare-metal firmware for a Renesas RA8D2 – a 1 GHz Cortex-M85 with 1.6 MB of SRAM – and turning it into an e-reader. Along the way the project grew six binary formats of its own, for books, comics, images, neural-network models and signed firmware.
Read more →
July 14, 2026 · 119 min read
RA8D2RenesasEmbeddedBinary FormatsBare-MetalCImage FormatsDEFLATEPNG
This is the format the whole e-reader rests on, and the one I would point at if somebody asked what is actually hard about rendering on a microcontroller.
The short version of the problem: the images this thing has to display are far larger than the RAM it has to display them with, and the formats they arrive in are built in a way that makes partial decoding impossible. Something has to give. This post is the longest in the series, and it sets up the vocabulary – index, seek, working set, edge clamp – that the rest reuse.
Read more →
July 15, 2026 · 52 min read
RA8D2RenesasEmbeddedBinary FormatsBare-MetalCEPUBzlibDemand Paging
Books are the reason this project exists, so this is where the e-reader stops being a graphics demo and starts being a reader.
The interesting tension here is that solving one problem creates another. Moving all the EPUB parsing to a host tool makes the device’s job trivial, but it produces a single flat object that is bigger than RAM – so now you need a way to read a piece of it without holding the whole thing. This post is also a useful comparison with the previous one: the two formats put their index at opposite ends of the file, for reasons that are entirely about the producer.
Read more →
July 16, 2026 · 47 min read
RA8D2RenesasEmbeddedBinary FormatsBare-MetalCCBZComicszlib
Comics turned out to be a different problem from books, and I nearly got it wrong by assuming they were the same problem.
The instinct is to reach for the container you already built. That instinct is wrong here, and the post spends a while on why: the unit you index by is a design decision, not an implementation detail, and picking the wrong one costs you several reads and several inflates for every single page turn. There is also a nice security result at the end – the device ends up never running an image decoder at all.
Read more →
July 17, 2026 · 44 min read
RA8D2RenesasEmbeddedBinary FormatsBare-MetalCSecure BootECDSACryptographyTrustZone
This is the only format in the series with a real adversary.
Everything else here is built to survive accidents: a file truncated by a yanked SD card, a corrupt index, a decompression bomb. Those threat models all stop politely short of somebody who actually means it. Firmware signing does not get that luxury, and the post works through what that changes – including why a checksum is not a weaker version of a signature but a different thing entirely, and why the rollback counter has to sit inside the signed material. Every byte in the worked example comes from a throwaway key generated into a temp directory; no real signing key appears anywhere in this post.
Read more →
July 18, 2026 · 30 min read
RA8D2RenesasEmbeddedBinary FormatsBare-MetalCTrustZoneSecure BootLinker ScriptsArmv8-M
Eight bytes. Two fields. This is the smallest thing in the series by a wide margin, and it is here because of a question that has no good answer until you write one down.
Read more →
July 19, 2026 · 44 min read
RA8D2RenesasEmbeddedBinary FormatsBare-MetalCMachine LearningEthos-U55NPUTensorFlow Lite
The last post in the series takes the idea behind all the others – do the expensive, unbounded work on a host that can afford it – and points it at a neural network.
Read more →