Get started

Taking an assessment rather than buying one? This page is written for employers. Here is the page for candidates.

Software engineering · Mid level

How to assess a Embedded Software Engineer

Embedded engineers fail in production for reasons that are structurally unobservable in every part of that screen. The defining constraint of the role is that the code runs where you cannot watch it — no attached debugger, often no log output, sometimes no way to retrieve the device — so the competence being hired is the ability to reason about correctness in advance and to build in the observability and recovery you will need later. A pointer-arithmetic trivia round tests recall of exactly the material an assistant reproduces flawlessly, while leaving unmeasured whether the candidate thinks about what happens when the flash write is interrupted by a brownout. The second failure is resource reasoning. Embedded correctness is quantitative — this much RAM, this many cycles, this interrupt latency, this power budget — and a take-home run on a workstation removes every one of those numbers, which is to say it removes the problem. The third is that embedded bugs are often timing and concurrency bugs at the boundary with hardware, and those are invisible in code review and in a passing unit test alike.

Embedded software is the part of this family where the code outlives the opportunity to fix it. A web service is a living thing you edit daily; firmware in a shipped product may be edited twice in its life, or never, and the second edit may require a technician to visit. That single asymmetry produces a distinct professional temperament, and it is the temperament rather than the syntax that a hiring process should be trying to see.

Day to day the work is a negotiation with constraints that other software engineers never meet. There is a fixed amount of RAM and it is not negotiable, so memory is accounted for statically and dynamic allocation in a long-running path is a design smell rather than a convenience. There is a real-time obligation, so the question "how long does this take in the worst case" has an actual answer that matters. There is hardware that sometimes does not respond, returns nonsense, or responds late, and the firmware is expected to keep the product usable anyway. And there is the update path — whether one exists, whether it is atomic, and what happens if power fails halfway through — which is the single most consequential architectural decision in many embedded products and the one most often deferred.

The top quartile is recognisable by how they handle the invisible. They add a way to know what happened before they need it: a fault log in non-volatile memory, a boot counter, a watchdog whose reset reason is recorded rather than discarded. They write the failure branch for the sensor that returns zero forever, because sensors do. They treat every external input as hostile, not out of security theatre but because a stuck bus line is a normal Tuesday. A weaker engineer writes the code that works when everything works, tests it on a bench where everything works, and discovers the rest in the field.

The other separator is honesty about what has been proven. Embedded work attracts a particular failure of reasoning where a system is declared correct because it ran for a weekend. A strong candidate distinguishes "I tested it" from "I reasoned about it" from "I have not covered this case", and volunteers the third category unprompted.

A necessary caveat, stated plainly because the alternative is selling something that does not exist: this is the role in this hub where a remote simulation covers the least of the job. Savvanta runs a monitored sandbox, written artefacts and a live spoken interview. It does not run hardware in the loop. There is no oscilloscope, no logic analyser, no target board, no way to induce a brownout mid-write. A meaningful part of embedded competence — bring-up, instrumentation, reading a datasheet against an actual signal — is therefore outside what any remote assessment can observe, and a team hiring for firmware should treat this design as a strong filter on reasoning rather than as a complete evaluation.

What it does cover well is the reasoning layer, and that is worth having because the reasoning layer is where the recalls come from. The sandbox presents existing firmware source for a device with a plausible defect class — an ISR doing too much, a buffer whose bound is wrong under one input, a state machine with an unhandled transition, a flash write with no interruption safety — and asks the candidate to find and fix it against a simulated target rather than real hardware. The follow-up conversation then does the work the sandbox cannot: what is the worst-case execution time of the handler you just wrote, and how would you find out for certain? Power fails during this write — what does the device do on next boot? How much RAM does your change cost, and where did you get that number? This device is in a customer's wall and reports a fault; what did you build in six months ago that lets you find out why? Those are the questions embedded teams live by, and no assistant can answer them about someone else's code.

What the job actually needs

How people fail in this seat

What most employers do instead

CV screen for years of C and a named toolchain, a trivia interview on volatile, pointers and bit manipulation, and occasionally a take-home in plain C.

Embedded engineers fail in production for reasons that are structurally unobservable in every part of that screen. The defining constraint of the role is that the code runs where you cannot watch it — no attached debugger, often no log output, sometimes no way to retrieve the device — so the competence being hired is the ability to reason about correctness in advance and to build in the observability and recovery you will need later. A pointer-arithmetic trivia round tests recall of exactly the material an assistant reproduces flawlessly, while leaving unmeasured whether the candidate thinks about what happens when the flash write is interrupted by a brownout. The second failure is resource reasoning. Embedded correctness is quantitative — this much RAM, this many cycles, this interrupt latency, this power budget — and a take-home run on a workstation removes every one of those numbers, which is to say it removes the problem. The third is that embedded bugs are often timing and concurrency bugs at the boundary with hardware, and those are invisible in code review and in a passing unit test alike.

The assessment

About 90 minutes end to end.

The systems it runs in

C firmware for an ARM Cortex-M target running FreeRTOS, built with the GNU Arm Embedded toolchain and executed against an emulated target rather than hardware, with GDB attached and a serial console. The RAM figure in t2 comes from the linker map file and the toolchain's own size output rather than from an assertion, and the worst-case execution time question in t4 is answerable only by naming a real instrument — a cycle counter, a GPIO toggle on a scope, or a trace probe — which is why the task asks how the candidate would establish it rather than what it is.

Zephyr, ThreadX, or bare-metal with no scheduler; ESP-IDF for teams on Espressif parts; an embedded Linux fixture for teams whose product is a board rather than a microcontroller. The Embedded Markets Study published by AspenCore puts embedded Linux and FreeRTOS at the head of the operating-system list and C and C++ well ahead of other languages, which is what this default is chosen against. One thing is deliberately not asserted here: there is no dominant embedded IDE. The vendor toolchains — STM32CubeIDE, MPLAB X, Code Composer Studio, IAR Embedded Workbench, Keil MDK — are fragmented along silicon vendor lines, so the fixture is built to a command-line toolchain and the buyer's IDE is never assumed.

Working speed is not scored. The cheap path in t1 is finding the buffer bug quickly and stopping, because the reported symptom looks explained once it is fixed. The correct path keeps reading after the obvious defect is gone, which takes longer and produces less visible progress. A speed criterion would rank the candidate who found one of three defects above the one who found all three, and would also penalise the third column of t2's accounting — the list of what has not been covered — which takes time to write and is the single most reliable indicator in the design.

What the candidate actually does

TaskWhat happens
The defect you cannot watch
coding_sandbox · 40 min
Existing firmware source for a plausible device — a battery-powered sensor node that samples, buffers and writes readings to flash, with a serial command interface. It is C on an ARM Cortex-M part running FreeRTOS, and it builds and runs against an emulated target in the sandbox, not against hardware. Three defects are present and none is pointed at. An interrupt handler does unbounded work, including a formatted print, while holding off a time-critical path. A ring buffer's bound is off by one for exactly one input length. And the flash write sequence erases before it has anywhere to recover from, so an interruption between erase and write loses the record and leaves the device in a state it does not check on boot. The candidate is told the device is returning occasional corrupted readings in the field and has no debugger attached. The fork is what counts as done: the cheap path finds the buffer bug, which is the one a model finds instantly from the symptom, fixes it, and stops. The correct path keeps reading, because the reported symptom does not account for all three. AI assistance is permitted and logged.
The accounting
written_artifact · 15 min
A short written statement covering the candidate's own change: how much RAM it costs and where that number came from, the linker map and the toolchain's size output or an estimate labelled as one, the worst-case execution time of the interrupt path after their fix and how they would establish it on real hardware, and an explicit three-way split of everything they did into what they proved, what they tested, and what they have not covered. There is no template and no target numbers. The cheap version asserts that the change is small and was tested. The strong version puts real items in the third column, unprompted, which is the single most reliable indicator in this design.
The device in a customer's wall
judgment_scenario · 12 min
A structured scenario with no code. Two hundred units are installed in commercial buildings. Eleven have stopped reporting. There is no field update path that has ever been exercised, the units are behind ceilings, and a technician visit costs more than the unit. The candidate is asked what they would do now, and then — separately — what they would have built into the firmware six months ago that would make this answerable today. A new fact arrives midway: one returned unit boots and runs correctly on the bench. What is scored is whether the answers name specific instruments — fault log in non-volatile memory, boot counter, recorded watchdog reset reason, a staged rollout, a recovery bootloader — and whether the bench-works fact moves them towards environment and timing rather than towards code they can read.
Interview on your own firmware
live_call · 23 min
A spoken conversation over the candidate's own diff. What is the worst-case execution time of the handler you just wrote, and how would you find out for certain rather than by argument? Power fails during this write — what does the device do on the next boot, and which line makes that true? How much RAM did your change cost, and where did that number come from? You allocated here; what is this heap like after a year of uptime? Then the live constraint change: this part is being replaced by one with half the RAM and no floating point unit — walk me through what in your change stops fitting. That final turn is the separator, because it removes the resource assumption the generated code was written against, and only somebody who accounted for resources can say what breaks.

The mark scheme

Each criterion is scored 1 to 5 against written anchors, and every score is reported with the excerpt that earned it. A criterion marked floored is reported as a finding rather than averaged into the total. The first is open; open any other to read its anchors in full.

Quantitative account of their own changeweight 0.3States a static RAM figure and where it was derived, names a concrete method for establishing worst-case timing on the real part, and under the halved…
1 Cannot say what the change costs in RAM or cycles; answers in qualitative terms — small, fast, efficient — and has no method for finding out. Under the halved-RAM change, answers about optimisation generally.
3 Gives numbers for the obvious static costs, with a method for the timing that is plausible but not specific to this target.
5 States a static RAM figure and where it was derived, names a concrete method for establishing worst-case timing on the real part, and under the halved-RAM constraint identifies the specific structures and paths that stop fitting.
Interrupt and concurrency disciplineweight 0.2Reduces the handler to bounded work, names the shared state explicitly, says what makes access to it safe on this architecture, and can say what the l…
1 Leaves the unbounded work in the handler, or adds more; shares state between interrupt and main context with no barrier, volatile or critical-section reasoning, and does not raise it.
3 Moves the work out of the handler correctly but cannot explain what protects the shared state, or explains it by convention.
5 Reduces the handler to bounded work, names the shared state explicitly, says what makes access to it safe on this architecture, and can say what the latency cost of their choice is.
Assumes the hardware and the power will misbehaveweight 0.2Makes the interruption case recoverable and detectable at boot, and applies the same posture elsewhere — treats the sensor that returns a stuck value …
1 Fixes the buffer bug and stops; the erase-before-write sequence is left as found and the boot path still does not check for a partial record.
3 Makes the write sequence safer but does not add the boot-time detection that would let the device know it happened.
5 Makes the interruption case recoverable and detectable at boot, and applies the same posture elsewhere — treats the sensor that returns a stuck value as a case to handle rather than an impossibility.
Honesty about what has been provenweight 0.2Volunteers the not-covered column unprompted with specific items in it, and separates "I reasoned about this" from "I observed this" without being ask…
1 Declares the change correct because it built and ran; the written statement has nothing in the not-covered column; asserts timing figures with no source.
3 Distinguishes tested from untested when asked directly.
5 Volunteers the not-covered column unprompted with specific items in it, and separates "I reasoned about this" from "I observed this" without being asked to.
Builds the means to find out laterweight 0.1Names specific retrospective instruments — persisted fault record, boot counter, recorded reset reason, staged rollout, recovery path — and moves towa…
1 In the field scenario, proposes only to inspect returned units; names no instrument that could have been built in advance.
3 Names logging or a watchdog in general terms.
5 Names specific retrospective instruments — persisted fault record, boot counter, recorded reset reason, staged rollout, recovery path — and moves towards environment and timing when told the returned unit works on the bench.

How it is scored

Weighted mean of five criteria, 1-5 against the anchors, each reported with the code excerpt, the written statement, or the transcript line behind it. Finding all three defects is not itself a criterion; the third criterion rewards the posture that leads to finding the flash one, and a candidate who found two and correctly identified the third as unexplained scores above one who found three by chance and cannot say why they matter.

Integrity

The log describes what happened. It does not produce a cheating verdict — the follow-up conversation is the control, because a statistical accusation is not something we would ask a reviewer to defend.

What you receive

Who decides

Required, with a reviewer who has shipped firmware. More than the other roles in this hub, the anchors here need someone who can tell a correct architecture-specific answer from a fluent generic one — several of the strongest possible answers to the concurrency criterion depend on the target and cannot be pattern-matched. Given the coverage limits below, the reviewer should also be told explicitly that this score is an input to a decision that needs a second, hardware-facing stage.

What this does not measure

State this plainly rather than selling coverage that does not exist. This is the weakest genuine fit in the software engineering hub, and a firmware team that buys it expecting a complete evaluation will be disappointed. Savvanta runs a monitored sandbox, written artefacts, judgment scenarios and a live spoken interview. It does not run hardware in the loop. There is no target board, no oscilloscope, no logic analyser, no JTAG probe, no way to induce a brownout mid-write or to run the part at temperature. Board bring-up is not observed. Instrumentation of real hardware is not observed. Reading a datasheet against an actual signal — arguably the defining embedded skill — is not observed at all, and no amount of simulated fixture substitutes for it. Toolchain and debugger fluency, board files, linker scripts, and the ability to get a dead board talking are outside this design entirely. What it does observe is the reasoning layer: resource accounting, interrupt discipline, interruption and recovery reasoning, and intellectual honesty about what has been proven. That layer is worth assessing because it is where recalls originate, and it is the layer a CV filter for years-of-C and a pointer-arithmetic trivia round leave completely untouched. Use it as a strong filter before a hardware stage, never as a substitute for one. Two fairness notes: the fixture is one architecture and one C dialect, and the concurrency anchors must not be marked against a single architecture's idioms, since a candidate reasoning correctly about a different part should score identically; and the honesty criterion rewards admitting uncertainty, which some candidates have been trained by previous employers to suppress — reviewers should read a populated not-covered column as strength, and say so to candidates in advance so the incentive is not hidden.

There is a version of this page that overclaims, and it would be the most commercially damaging page in the hub. Firmware teams know exactly what a remote assessment cannot see, and a design that implied otherwise would be dismissed in the first paragraph by the person it is written for. So the coverage limit is stated at the top of the adverse-impact note rather than buried: no hardware in the loop, no bring-up, no signal, no brownout. What follows is a design for the part that remains, which is larger and more predictive than it first appears.

The part that remains is the reasoning layer, and it is where recalls come from. Embedded correctness is quantitative in a way that other software is not — this much RAM, this many cycles, this interrupt latency, this power budget — and the standard screen removes every one of those numbers. A pointer-arithmetic trivia round tests recall of exactly the material an assistant reproduces flawlessly. A take-home compiled on a workstation removes the constraint that constitutes the problem. Neither observes whether the candidate thinks about what happens when the flash write is interrupted by a brownout, which is the thought that separates firmware that survives a field deployment from firmware that does not.

The three-defect fixture is built around a specific and testable behaviour: knowing when a symptom has stopped being explained. Corrupted readings in the field is a symptom that the ring-buffer bug accounts for, partially. A model handed that symptom and that source finds the off-by-one quickly and convincingly, and a candidate who accepts it has a green build and a plausible story and has left two defects in a device that goes into a wall. A candidate who keeps reading is exhibiting the actual professional temperament of the role, which is a refusal to declare a system correct because the visible problem went away. The rubric deliberately does not score defect count, because counting would reward luck; it scores whether the posture that leads to the flash defect was present.

The written accounting in t2 does something no other file in this hub does, which is to make the candidate publish their own confidence. The three columns — proved, tested, not covered — are the embedded engineer's honest inventory, and the third column is the one that predicts. Embedded work attracts a particular failure of reasoning where a system is declared correct because it ran for a weekend, and that failure is invisible in code and obvious in a sentence. A candidate who writes "I have not established the worst-case timing; here is how I would on the real part" is telling a hiring manager something more valuable than any defect they found.

The field scenario in t3 is included because the most consequential embedded decisions are made months before the incident that needs them. Asking what the candidate would do about eleven silent units is a reasonable question with a limited answer. Asking what they would have built six months ago is the question that reveals whether they add a way to know what happened before they need it: a fault record in non-volatile memory, a boot counter, a watchdog whose reset reason is stored rather than discarded, a rollout that would have caught this at twenty units instead of two hundred. The bench-works fact is then injected to see whether the candidate follows it towards environment and timing — where the answer actually is — or keeps re-reading code that demonstrably works.

The interview closes by halving the RAM and removing the floating point unit, which is not a harder version of the task but a removal of the assumption the code was written against. Generated firmware is written against whatever resources the fixture appears to have, silently. Someone who accounted for resources can name the structures and the paths that stop fitting within a minute, using their own identifiers. Someone who did not will answer about optimisation in general, correctly and uselessly, and that is the measurement this design exists to take.

Sources

Every figure on this page is traceable. Where a claim could not be sourced it is stated qualitatively instead.

  1. Stack Overflow, 2025 Developer Survey, Developers section, roughly 49,000 respondents worldwide, developer-type question answered by 43,560, https://survey.stackoverflow.co/2025/developers

See what the employer actually receives. A full report for one role, with every score shown beside the excerpt that earned it, conduct findings reported rather than averaged, and a reviewer sign-off required before any decision. No form.

Read a sample reportOr talk to us about this role