Contact KO
Tech Notes

Embedded Software: From Concept to Production

Embedded software isn't finished when the code runs. It has to run on fixed hardware, within fixed time limits, for ten years or more — and be built in thousands of units at the same quality. Here is what to decide, and when.

About 7 min

1What makes embedded software different

Embedded software lives inside one device and exists only for that device. Compared with PC software, the assumptions change:

PC softwareEmbedded software
HardwareUnknown PCsOne specific board
TimeLate but correct is fineMust respond within a deadline (real-time)
ResourcesPlenty of memoryOften tens to hundreds of KB of RAM
LifetimeReinstalled every few yearsOften in service for 10+ years
When it failsThe user restarts itThere may be nobody to restart it

Real-time doesn't mean fast. If a motor stops one second after the stop signal, the result is correct but the behavior is wrong. In embedded systems, timing is part of correctness.

In practice

Design as if nobody will ever be there to power-cycle the device. That one assumption puts a watchdog (a circuit that restarts a stalled program) and power-failure recovery into the design from day one.

2Why an OS?

Small devices often run without an OS, using a super loop: an endless loop in main checks each job in turn, and urgent events are handled by interrupts. It is simple, small and predictable.

It breaks down as jobs multiply. One long job delays all the others — the button feels sluggish while data is being processed. Splitting long jobs into slices adds state variables and scatters timing logic across the code.

An RTOS (real-time operating system) solves this structurally:

  • Separation — each function becomes its own task.
  • Priority — a high-priority task preempts a lower one that is running.
  • Timing — periodic execution, timed waits, and safe data exchange between tasks (queues, semaphores).

The cost: stack memory for every task, careful handling of shared resources, and new failure modes such as priority inversion, where a low-priority task holding a resource blocks a high-priority one.

In practice

With two or three simple periodic jobs, or a battery device that sleeps most of the time, stay without an OS. If the answer to "must other functions keep their response time while communication is being processed?" is yes, use an RTOS.

Figure 1. A super loop runs jobs in turn, so one long job delays everything. An RTOS runs the most urgent task first, and tasks exchange data through queues.

3Free operating systems

OSCharacterChoose it when
FreeRTOSSmall, simple kernel; supported on more MCUs than almost any otherSmall MCUs, or adding tasks to existing code
ZephyrIntegrated RTOS with kernel, drivers, networking and wireless stacks, and its own build systemNetwork-heavy products supporting several boards from one codebase; steeper learning curve
RT-ThreadKernel plus selectable components such as file systems, networking and USBMid-sized devices that need file systems or USB
NuttXRTOS following POSIX interfacesYou want Linux-style programming on an MCU
Eclipse ThreadXA real-time operating system for small MCUs, now available as open sourceYour chip vendor's development tools already include it
Embedded LinuxGeneral-purpose OS needing an MMU and tens of MB of memory or moreDisplays, complex networking, heavy file handling — at a cost in boot time, real-time behavior and power

The five RTOSes use business-friendly licenses (MIT or Apache 2.0). The Linux kernel is GPL, which carries source-disclosure obligations when you ship.

In practice

Before comparing features, check whether the chip vendor officially supports the OS and whether drivers for your peripherals already exist. Writing drivers usually costs far more time than any feature gap.

4Verification after development

Working features are not the end of verification. Field failures are usually "occasional", "after long use" or "only under certain conditions".

  1. Unit tests — modules tested in isolation; with hardware access separated (section 7), many run on a PC.
  2. Hardware integration tests — peripherals, communication and power on the real board.
  3. Long-run tests — days to weeks of continuous operation expose memory leaks, counter overflows and rare timing collisions. A 32-bit millisecond counter wraps after about 49.7 days; code that mishandles it never fails in a short test.
  4. Boundary and fault tests — power dropouts, unplugged cables, malformed data, temperature extremes. The goal is not "never fails" but "fails safely and recovers on its own".
  5. Static analysis — tools find uninitialized variables, out-of-bounds access and risky casts without running the code.

In practice

The latest-found and most expensive bugs come from long-run and fault tests. The tighter the schedule, the earlier these two go into the plan.

5Designing hardware for production

A few prototypes can be built by hand. Thousands of identical units need production built into the design — and most of those decisions are made at the schematic and PCB stage.

  • Programming pads placed where fixture pins can reach them, so many boards are programmed at once without connectors.
  • Test points for supply voltages and key signals, so failures can be traced.
  • Unique values — serial numbers, addresses, calibration data: when, where and how they are written and logged.
  • Supply and obsolescence — long-life parts and parts with second sources. End-of-life notices arrive mid-production.
  • Test time and unit cost — saving one minute per unit saves about 167 hours over 10,000 units. Test commands built into the firmware let the fixture check functions quickly.

In practice

Adding test pads when moving from prototype to production board means another board revision. Having built production test equipment ourselves, we put them in the very first prototype — it is the cheapest point.

6Bootloaders and field updates

To fix and extend a product after shipping, memory is split into a bootloader (a small program that runs first, checks the application and starts it) and the application.

  • Update path — serial, USB, network or wireless, as the product requires.
  • Survive interruption — power can fail mid-update. Receive the new image into a separate area and verify before switching, or fall back to the previous image.
  • Integrity — check the image with a CRC and, where needed, a digital signature.
  • Version tracking — know which version each unit runs.

In practice

Assume the bootloader can never be changed after shipping. Keep it minimal, and test it the most.

7Layers against component obsolescence

Over a long product life, the MCU or a peripheral chip will be discontinued. To avoid rewriting everything, separate hardware-dependent code from application logic from the start.

  • Hardware abstraction (drivers) — registers, pins, clocks. Only this layer changes with the chip.
  • Services — protocol handling, storage, updates.
  • Application — what the product does, calling only the layers below.

With function interfaces between layers, a chip change or a move from super loop to RTOS touches little code — and PC-based unit testing becomes possible.

In practice

Register names appearing in application code are an early sign that porting costs are rising. Across many MCU generations, a well-layered first product lets us build the next one in about half the time.

Figure 2. The application and services never touch the hardware directly, so a chip change only affects the hardware abstraction layer.

8Debugging tools

ToolWhat it doesUse it for
JTAG/SWD debuggerHalts execution to inspect variables, memory and registers; SWD needs only two pinsLogic errors, locating exceptions
LoggingRecords flow and values with timestamps over serial or similarBehavior that must not be halted, field reproduction
Logic analyzerShows many digital signals on one timeline and decodes protocolsCommunication timing and ordering
OscilloscopeShows voltage waveformsSupply ripple, noise, signal quality

Halting in a debugger changes timing and can make a bug disappear. For communication or motor control, observe with logs and measurements instead — and remember that heavy logging changes timing too.

In practice

The rarer the symptom, the more it pays to leave logging and a logic analyzer attached and wait for it to recur. One record of the moment it happened beats any amount of guessing.