IllustrationEmbedded programming for a connected device is organized around a language, usually C with C++ or Rust where the SDK allows it, a chip SDK such as ESP-IDF, nRF Connect SDK or Zephyr, host-side unit tests, hardware-in-the-loop tests on real boards, a debug probe, structured logging and pinned CI builds.
Embedded programming for a connected device is more than writing C. A product team needs a language policy, an SDK, tests that run on a laptop and on boards, a way to debug and log, and builds that anyone can repeat. This guide walks through each part of embedded software development for a battery device with a radio, using the Zephyr, ESP-IDF and nRF Connect SDK documentation and the MISRA and CERT C coding standards. It ends with a decision table and a checklist for EVT firmware freeze.
This is an engineering summary. SDK versions and defaults change, so check the linked pages before you decide. All sources were read on November 13, 2026.
How is embedded programming for a connected device organized?
Most embedded systems programming work follows the same loop. You write code on a host computer, build it with a cross-compiler for the target chip, flash it through a debug probe, and read logs from a serial port or the probe. Tests run in two places: on the host, where they are fast, and on real boards, where timing and peripherals are real. A CI server repeats the build and tests on every change.
The SDK ties these steps together. In Zephyr, the west tool manages a workspace that spans several Git repositories, and Zephyr adds west commands for building, flashing and debugging (Zephyr west, as of November 2026). ESP-IDF uses its own idf.py tool to configure, build and flash test apps (ESP-IDF unit testing, as of November 2026). For the parts the firmware runs on, see what an embedded system is. For where firmware sits next to the app and cloud, see firmware vs software vs hardware.
Which language: C, C++ or Rust?
C is still the base language of embedded development, because chip SDKs, drivers and radio stacks ship in C. The real question is how much C++ or Rust you add on top, and what each SDK supports.
C and C++ in the SDKs
ESP-IDF compiles C as the GNU dialect of ISO C23 by default, and a component can select another standard in its CMakeLists.txt (ESP-IDF C support, as of November 2026). By default for chip targets, it compiles C++ with the C++26 language standard with GNU extensions. C++ exceptions and RTTI are both disabled by default and can be turned on in the configuration (ESP-IDF C++ support, as of November 2026).
Zephyr applications default to C++11, and the oldest standard Zephyr supports and tests is C++98. Zephyr provides only a subset of C++, and its documentation says not to use C++ for kernel, driver or system initialization code (Zephyr C++ support, as of November 2026). A common split is C for drivers and C++ for application logic, with exceptions left off.
Rust
Zephyr supports Rust through the external zephyr-lang-rust module, which is not part of the Zephyr manifest. You enable it with CONFIG_RUST, and the example build needs CMake 3.28.0 or later. The page says only a few targets currently support Rust (Zephyr Rust support, as of November 2026). Check the target list for your chip before you plan a Rust codebase. The vendor drivers and radio stack will still be C, so you will maintain a C boundary either way.
Coding standards: MISRA C and CERT C
A coding standard turns style debates into checks a static analyzer can run. MISRA C:2025 was published in March 2025 as an incremental update, and it keeps support for C11, C18 and earlier versions. MISRA says the guidelines are used across rail, aerospace, military and medical work (MISRA C, as of November 2026).
The SEI CERT C Coding Standard, 2016 Edition, targets C11 and earlier standards including C99. It splits guidelines into rules, which are normative requirements, and recommendations, which are advisory. Topics include integers, memory management, concurrency and error handling (SEI CERT C, as of November 2026). In engineering terms, MISRA leans toward predictable, analyzable code, and CERT leans toward security flaws such as overflows. Many teams pick one as the base and add a short list of house exceptions, each with a reason.
Vendor SDK, Zephyr or ESP-IDF: which toolchain fits?
The chip usually picks the SDK. The table compares the common options for a connected device. Sourced cells link to the page they came from. The "Fits when" column and the last row are engineering reasoning.
| Option | What it is | Release support | Test tools | Fits when |
|---|---|---|---|---|
| ESP-IDF | Espressif's framework for its own chips. The default C standard is the GNU dialect of ISO C23 (ESP-IDF C support, as of November 2026). | Each major and minor release is supported for 30 months after its first stable release: 12 months of service, then 18 months of maintenance (ESP-IDF versions, as of November 2026). | Unit tests run on the chip with Unity (ESP-IDF unit testing, as of November 2026). Host builds for the Linux target are an experimental feature (ESP-IDF host apps, as of November 2026). | Wi-Fi products built on an Espressif chip. |
| nRF Connect SDK | Nordic's SDK. Its manifest pulls in a Nordic fork of Zephyr, plus MCUboot, Trusted Firmware-M and Mbed TLS forks (sdk-nrf west.yml, as of November 2026). | Tied to the Zephyr fork and module revisions pinned in that manifest (sdk-nrf west.yml, as of November 2026). | The Zephyr tools apply, including west, Ztest and Twister. The manifest also lists CMock (sdk-nrf west.yml, as of November 2026). | Bluetooth LE, Thread or cellular products on a Nordic chip. |
| Upstream Zephyr | An RTOS project where west manages a workspace that spans several Git repositories (Zephyr west, as of November 2026). | Pick a release line and record it in the manifest. See the support notes in our RTOS guide. | Chips with good upstream support, or teams that want one tree across vendors. | |
| Other vendor SDK | A chip vendor HAL, often with FreeRTOS, and the vendor IDE. | Set by the vendor. Ask for the policy in writing. | Usually your own choice of test framework and CI scripts. | A chip with no mature Zephyr or ESP-IDF support. |
The nRF Connect SDK repository describes itself as the core of the SDK, with subsystems, libraries, samples and applications, and as the west manifest repository for the whole SDK (sdk-nrf README, as of November 2026). In practice, that means a Nordic project is a Zephyr project with Nordic's additions, so Zephyr skills carry over. For how the two chip families compare on power and Bluetooth, see nRF52840 vs ESP32. For the kernel choice underneath, see what an RTOS is.
How do host-side unit tests fit in?
Host tests run on a laptop or CI server in seconds. They suit code with no direct hardware access: parsers, state machines, data encoding and retry logic.
Zephyr's Ztest framework offers assertion macros and test suites, and it integrates the FFF library for mocks. Its unit_testing pseudo-board builds only the module under test, without the kernel, and Zephyr says running these unit tests is only supported for Linux (Zephyr Ztest, as of November 2026). The native_sim board goes further. It compiles the application with the Zephyr kernel into a Linux executable, runs in simulated time and supports gdb, valgrind and sanitizers. It is not suited to code that depends on specific hardware (Zephyr native_sim, as of November 2026).
ESP-IDF can also build apps for a Linux target, either with CMock mocks or with a FreeRTOS POSIX simulator. Espressif calls this an experimental feature, and only a limited set of components is ready for it (ESP-IDF host apps, as of November 2026). Keep hardware calls behind a thin interface so the logic above it compiles on the host whatever the SDK offers.
What does hardware-in-the-loop testing add?
Hardware-in-the-loop (HIL) testing runs the firmware on real boards, driven by a script. It catches what host tests cannot: interrupt timing, peripheral setup, flash writes, sleep and wake, and radio links.
Zephyr's Twister test runner builds and runs test applications, using an emulator where one exists. With a hardware map file, it builds, flashes and runs tests on several connected boards. The documentation notes the generated map often needs manual fixes, and that only some runners work with hardware maps, such as pyocd, nrfjprog, jlink and openocd (Zephyr Twister, as of November 2026). The --generate-hardware-map option probes connected serial devices to create that file (Twister command line, as of November 2026).
ESP-IDF's main unit test approach runs a test app on the chip with the Unity framework. Some tests span two boards or a reset, and pytest-embedded runs the suites in CI (ESP-IDF unit testing, as of November 2026). A small rig with one board per hardware revision, a USB hub and a controllable power supply covers most needs. For how hardware and firmware meet during bring-up, see hardware/software integration.
Which debug probes and logging do you need?
Debug probes
A debug probe lets the host read and write registers and memory and set breakpoints with GDB. Zephyr's probe page covers J-Link, CMSIS-DAP and ST-LINK probes and host tools such as OpenOCD and pyOCD. It notes many boards carry a second microcontroller as an onboard probe (Zephyr debug probes, as of November 2026). Thread-aware debugging of Zephyr works in pyOCD v0.11.0 and later with CONFIG_DEBUG_THREAD_INFO enabled (Zephyr debugging, as of November 2026).
The ESP32-S3 has built-in USB JTAG, so one USB cable on its D+ and D- pins is enough for OpenOCD and GDB. External adapters must match the 3.3 V JTAG I/O levels, and the ESP32-S3 does not support SWD (ESP-IDF JTAG debugging, as of November 2026). Put the debug pads on the EVT board layout, even if production units leave them unpopulated.
Logging and crash records
Zephyr logging has four severity levels: error, warning, info and debug. Logs can be filtered out at compile time by module and level, and deferred mode moves slow work out of the calling context. Logging supports up to 9 concurrent backends, such as UART, RTT or BLE. Dictionary-based logging sends binary messages that a host tool decodes (Zephyr logging, as of November 2026).
ESP-IDF separates the runtime log level from the maximum level compiled into the image. Its binary log mode reduces flash size by approximately 10% – 35%, depending on the application, and task stacks that log need at least 2 KB (ESP-IDF logging, as of November 2026). ESP-IDF can also save a core dump to a flash partition when a fatal error occurs, and idf.py coredump-info prints the crashed task's call stack (ESP-IDF core dump, as of November 2026). A crash record you can pull from a returned unit is worth more than a long log.
How should CI builds be set up?
CI builds prove the firmware can be rebuilt from source by someone other than its author. Pin the toolchain in a container. Espressif publishes an espressif/idf Docker image for building with a specific ESP-IDF version, with tags for releases and release branches (ESP-IDF Docker image, as of November 2026). For Zephyr and nRF Connect SDK, the west manifest pins every repository revision (sdk-nrf west.yml, as of November 2026).
Twister's integration mode narrows builds to the platforms each test lists for CI, which gives faster feedback (Zephyr Twister, as of November 2026). Its --coverage option generates coverage reports (Twister command line, as of November 2026). A practical split is host tests and static analysis on every pull request, and HIL runs each night. Store each release image, its ELF file and its log dictionary together, so crashes and binary logs from the field can be decoded later.
Signed release builds and the update path belong in CI too. See secure boot and signed firmware and OTA failures that brick devices.
What should be in place before EVT firmware freeze?
EVT is the first build on the real board design. The firmware freeze for EVT units sets what the test team checks, so the workflow should be ready before it. Use this list at the review.
- Is the SDK version pinned in a manifest or lock file, and does CI build from that exact pin?
- Does a clean CI build produce the same image a developer flashes, with the version string set from the commit?
- Do host-side unit tests cover protocol parsing, state machines and data encoding, and do they run on every pull request?
- Does at least one board in a hardware-in-the-loop rig flash and run the test suite each night?
- Is there a debug probe for every firmware engineer, and are debug pads on the EVT board?
- Are log levels set so release builds keep warnings and errors, and can support read the logs?
- Does a crash leave a core dump or fault record that can be pulled from a returned unit?
- Have the coding rules been chosen (MISRA C, CERT C or a house subset), with static analysis running in CI?
- Can the OTA path update the full image, and has a failed update been tested on a real board?
- Is every third-party component and its license listed for the SBOM?
For what each build stage delivers, see EVT, DVT and PVT. For what to receive at handover, see the SBOM and source-file handover checklist. If you are comparing outside teams, the firmware development services guide lists what to ask. For how Duobay organizes this work, see firmware development.
Questions about embedded programming workflow
What is the difference between embedded programming and application software development?
Embedded programming targets a fixed chip with limited RAM and flash, real-time deadlines and its own peripherals. The code is built into one image with an RTOS or bare-metal loop, and it must run for years without a user to restart it. Application code runs on an operating system that hides most of the hardware.
Should a new connected device use Rust for its firmware?
It can, if the SDK supports it. Zephyr offers Rust through the external zephyr-lang-rust module, and its documentation says only a few targets currently support Rust (Zephyr Rust, as of November 2026). Check that your chip is on the list, and plan for C in the vendor drivers and radio stack.
Can all firmware tests run on a laptop?
No. Espressif says testing on real hardware is still needed, because simulation and mocking do not fully represent the target device (ESP-IDF host apps, as of November 2026). Host tests are fast for logic. Timing, power and radio behavior need boards.
How can Duobay help set up a firmware workflow for a device?
Duobay develops custom devices with a Shenzhen engineering team that covers electronics, firmware, enclosure, app and test, and builds samples and small batches. IP and all source files are assigned to you at every paid gate, and the firmware source and an SBOM are delivered. Initial calls are free, and we do not publish prices. Tell us about your device.
If you want help setting up the firmware workflow for a specific device, tell us about your device.
Sources. All pages accessed November 13, 2026. SDK defaults and support periods change, so confirm current values before you decide.
- Zephyr Project, C++ Language Support (link)
- Zephyr Project, Rust Language Support (link)
- Zephyr Project, West (Zephyr's meta-tool) (link)
- Zephyr Project, Test Framework (Ztest) (link)
- Zephyr Project, Native simulator, native_sim (link)
- Zephyr Project, Test Runner (Twister), 4.2.0 docs (link)
- Zephyr Project, Twister command line options (link)
- Zephyr Project, Debug Probes (link)
- Zephyr Project, Debugging (link)
- Zephyr Project, Logging (link)
- Espressif, ESP-IDF C Support, ESP32 stable (link)
- Espressif, ESP-IDF C++ Support, ESP32 stable (link)
- Espressif, ESP-IDF Versions (link)
- Espressif, ESP-IDF Unit Testing in ESP32 (link)
- Espressif, Running ESP-IDF Applications on Host (link)
- Espressif, ESP-IDF JTAG Debugging, ESP32-S3 stable (link)
- Espressif, ESP-IDF Logging library (link)
- Espressif, ESP-IDF Core Dump (link)
- Espressif, IDF Docker Image (link)
- Nordic Semiconductor, nRF Connect SDK repository README (link)
- Nordic Semiconductor, nRF Connect SDK west manifest, west.yml (link)
- MISRA, MISRA C (link)
- Carnegie Mellon University SEI, SEI CERT C Coding Standard (link)
Planning a device like this? Tell us what it needs to do. A Duobay engineer replies within 1 business day. Send a project brief →