SPECS · CLIENTS · COMMUNICATION · PROCESS

Writing Firmware Specifications That Clients and Engineers Both Actually Use

2026-07-01 · Davide Carrese

Early in my contracting career, I wrote a forty-page firmware specification for an IoT project. The client nodded through the review meeting. The engineering team built something completely different from what the client expected. Both sides blamed the spec.

The problem wasn't the detail — it was that I had written one document trying to serve two entirely different readers. A client reading a spec wants answers about cost, timeline, and risk. An engineer wants register addresses, state machines, and interface contracts. One document cannot do both jobs well.

Over the past six years and a dozen embedded projects, I have settled on a three-layer specification structure that clients read and engineers actually implement. Here is how it works.

The Three-Layer Spec

Instead of one monolithic document, I write three connected artefacts. Each has a clear audience and a specific job to do:

Layer Audience Purpose
Functional Specification Client + PM What the system does, in business language
Technical Design Document Engineering team How it works, at implementation depth
Interface Contract Both (shared reference) APIs, protocols, data structures, signal mappings

The Interface Contract is the only document both sides reference regularly. It becomes the source of truth for integration points and acceptance tests. The other two evolve independently: the client updates the functional spec, the team updates the technical design.

Layer 1: The Functional Specification

This document answers three questions from the client's perspective:

Keep this document under ten pages. Use bullet points and short paragraphs. The client will read it once during the kick-off and never again — make sure that single read is enough to catch misunderstandings.

A trick I use: after writing the functional spec, I delete the word "support" from the entire document (as in "the system shall support X"). Replace it with concrete behaviours. "Support OTA updates" becomes "The system downloads a signed firmware image from the cloud endpoint, verifies the signature against the stored public key, writes it to bank B, and boots from bank B on the next power cycle." The client may not understand every detail, but they will understand what they are paying for.

Layer 2: The Technical Design Document

This is where the engineering detail lives. It is written for the person who will implement the firmware — possibly yourself six months from now. Structure it around the hardware architecture:

The technical design document should also contain a risk register — not project-management fluff, but concrete engineering risks. Examples: "Errata 2.4 on the STM32U5 SPI peripheral: under heavy DMA load, the RX FIFO overflows on back-to-back transfers exceeding 64 bytes. Mitigation: limit burst size or switch to manual byte-by-byte reads for the last 32 bytes." This kind of specific, sourced risk documentation saves weeks when a bug surfaces during integration testing.

I keep the technical design between fifteen and thirty pages. Any longer and nobody updates it; any shorter and it misses the edge cases that come back to bite you.

Layer 3: The Interface Contract

This is the only document that both parties sign off on, and it is the shortest of the three. It defines every boundary between firmware and the outside world:

Every item in the interface contract must be testable with a logic analyser, a serial terminal, or a test fixture. If you cannot verify it with a tool you own today, it does not belong in the contract.

The interface contract also defines the acceptance test suite. Each test maps to one line item in the contract. When the client asks "is it done?", you run the tests. No ambiguity, no negotiation.

Practical checklist

What has worked for me

The three-layer structure emerged organically after a project where the client's "simple button" turned out to mean a multi-gesture capacitive touch interface with haptic feedback — because neither of us had defined what "button" meant in the interface contract.

Since adopting this approach, I have had exactly zero "that is not what I asked for" moments at delivery time. The meetings are shorter, the estimate variance is smaller, and the engineering team spends less time guessing what the client meant. The investment is a few extra days at the start of the project. The return is avoiding a single re-spin, which typically costs four to eight weeks.

Contracts negotiate scope. Specifications negotiate understanding. The two should never be the same document.

📬 Comments / discussion

Prefer email: comments@carrese.eu — include the article URL so I can follow up. For corrections or deeper questions, I typically reply within 48 hours.