Skip to main content

Zephyr OTA Updates Demand Deliberate System Design

·776 words·4 mins

Adding OTA to an embedded application is not just a library integration, it is system integration that requires thinking about your architecture first. On constrained microcontrollers, the A/B partition layout already cuts available flash in half before a single update is downloaded.1 More critically, a secure firmware download requires a concurrent cryptographic network session while the system is still running: sensor sampling, data publishing, and the update process all compete for the same network buffers and volatile memory. That resource contention, not the update process itself, is the real failure mode when there is no design that accounts for it, and regulations like the Cyber Resilience Act make getting it right a compliance requirement, not just an engineering one.2

A solution separates the system into two planes, one that decides when to update and one that carries traffic, and coordinates the handoff so resources are freed before the update starts.

%%{init: {"look": "handDrawn"}}%% flowchart TB subgraph CP["Control Plane"] SUP["Supervisor
(main)"] NET["NetworkMonitor"] OTA["OtaAgent"] end subgraph DP["Data Plane"] SAM["SensorSampler"] FIL["TelemetryFilter"] PUB["TelemetryPublisher"] end NET -- "net_state_chan" --> OTA NET -- "net_state_chan" --> PUB OTA -- "sys_mode_chan" --> SAM OTA -- "sys_mode_chan" --> PUB SAM -- "sensor_chan (k_msgq)" --> FIL FIL -- "telemetry_chan (k_msgq)" --> PUB SUP -. "boots & supervises" .-> NET SUP -. "boots & supervises" .-> OTA

Operating Mode Pattern #

The system is divided into two planes with distinct responsibilities:

Control plane #

NetworkMonitor, OtaAgent, and the Supervisor. These components manage connectivity and decide when an update can proceed. NetworkMonitor also publishes net_state_chan directly to TelemetryPublisher — this allows the publisher to pause independently on a network drop, without waiting for an OTA event. They do not handle sensor data.

Data plane #

SensorSampler, TelemetryFilter, and TelemetryPublisher (MQTT). These components run the application workload. They hold the MQTT connection, allocate message buffers, and maintain the active TLS session to the broker.

Mode transition #

Under normal operation, both planes share the same network stack. When an OTA update is ready, the control plane must signal the data plane to step back: close the MQTT socket, release its buffers, and idle, before the update client opens its own TLS session and begins downloading the artifact. That handoff is the mode transition.

The OtaAgent acts as the mode arbiter. When the update client reports a DOWNLOADING status, the arbiter broadcasts SysMode::OTA, implemented as a zbus channel that any subsystem can subscribe to independently. Data-plane components subscribe to that channel and shut down their network activity. When the update completes or fails, the arbiter broadcasts SysMode::NORMAL and the data plane resumes. This follows the publish/subscribe decoupling model documented in the Zephyr OTA architecture.3

Resource Allocation per Mode #

With the data plane stepped back, the update client gains near-exclusive use of the system’s shared pools. The control plane’s own polling — periodic update checks over a lightweight TLS session — has a small, bounded footprint that does not conflict with the download. The contention is between the data plane’s active MQTT session and the update client’s full artifact download.

Subsystem PoolNORMAL ModeOTA Mode
mbedTLS Heap (40 KB)Lightweight poll sessionFull artifact download TLS
Net Buffers (80 RX/TX)MQTT + OTA pollingArtifact chunk queue
Kernel Heap (192 KB)MQTT message allocationFlash write buffers

Upon completion or failure, OtaAgent publishes SysMode::NORMAL. The data plane restarts itself. On success, MCUboot handles the image swap and the device reboots warm.

Alternative Architectural Approaches #

While logical mode arbitration is a common design pattern for resource isolation, other systems architectures address this bottleneck differently:

  • Physical Isolation (Socket Offloading): Offloading the TCP/IP stack and TLS execution to a dedicated Network Coprocessor (NWP).4 This removes the network buffers and cryptographic heap from the primary MCU entirely, allowing concurrent telemetry and updates.
  • Protocol Optimization (UDP/CoAP): Replacing TCP-based protocols with CoAP/DTLS. This avoids the connection-setup and header overhead of concurrent HTTP and MQTT sessions.5
  • Binary Differencing: Implementing delta updates (such as CPatch)6 to download only the binary differences instead of monolithic images. This drastically cuts the download size and the duration of the cryptographic session.

Enforcing this boundary does more than protect a single download. It defines a contract that holds as the system grows. Heavier workloads, new protocols, or additional sensors can be added to the data plane without threatening the update path, because the architecture keeps them separate by design. It turns OTA reliability into a platform guarantee rather than a fragile, per-application integration.