Device Updates: Cut Down Time and Data Usage

Updating your hardware in the field

Is it time to modernize your approach to device updates?

Have you ever suspected that the way updates are handled on your embedded devices wastes electricity, drives up customer cellular data bills, or takes longer than really needed? Let’s look at how device updates have traditionally been done, and some improvements that could be made.

The state of things

Some high-end embedded devices have an operating system, scripting run-time, file system, or package manager that allows updating individual parts of its software. Most embedded devices don’t have these features, and even when they do, they may not be well suited for a use case that places high value on predictability and reliability.

Updates to a device in the field are traditionally handled by writing a new binary image to a fixed memory location. This is a natural extension of how the device memory is initially programmed during manufacturing. If the update interface is fast and cheap to use for device updates (e.g. WiFi), this approach may not be a problem.

However, if the update interface is slow or requires someone to physically connect and disconnect the update interface, sending large images becomes impractical. If updates are done over a cellular connection, replacing the entire image to make a small change on many devices costs end users far more than is necessary. Let’s look at what we can do to minimize the amount of data that needs to be sent to update a device.

Book a Call with Dojo Five Embedded Experts

A basic robust update scheme

Before we discuss techniques for minimizing the size of the update for any given code change, let’s quickly summarize a couple of basic options for performing a reliable and secure device update.

Option 1: A/B Seamless Updates

One approach is to have enough memory to hold redundant copies of the device image.

Data Updates: Redundency example image

Procedure:

  1. Remote updater informs the device that an update is coming, and provides some meta data (image size, version number, checksum, signature)
  2. Device receives the image in chunks and writes them to the memory reserved for the inactive image
  3. Device logs the image transfer progress, in case the update is interrupted and needs to be resumed
  4. When the image transfer has completed, the device can be rebooted
  5. Bootloader runs the newest image that passes an integrity check (using the checksum) and authenticates that it was created by a trusted source (using the signature)

Option 2: Intelligent Bootloader Updates

If memory is limited, and taking the application offline while receiving the update is not a problem, a bootloader can also be used to perform the update. In this case, the bootloader must be able to communicate with the remote updater.

Data Updates: Boot loader example

The procedure is nearly identical to the A/B Seamless Updates, but the device jumps back into the bootloader to handle the update and will wait for an update until a valid image is available to run.

For both of these options, chunks of the image may be sent to the device with a command like this:

Data Updates: Chunk image send example

Improve the update scheme

Don’t resend

Major portions of the image may not change from one version to the other, so we can skip sending that data, and simply copy what we already have on the device.

Perform a DIFF to find sufficiently large matching segments of the new binary that exist in the old binary. Any non-matching segments in the new image must still be transferred with the Chunk command from the last section. Any matching segments can be instructed to be copied with a command like this:

Data Updates: Matching segments image

Copying from the old image to the new image should be straightforward for A/B Seamless Updates.

If there is only one memory region available for an image, it is possible that some of the old data could be lost during the update, so take extra care to ensure your remote updater does not instruct it to copy something that isn’t there.

Skip the filler

Rather than sending every byte of a repeating sequence of data, use short-hand. Use this command as a crude form of data compression on any repeated data that is smaller when expressed this way:

Data Updates: Compression example image

Avoid Transfer Overhead

Finding the right chunk size is vital for minimizing the frequency of failures during a firmware update. The chunk size refers to the size of the data blocks that are downloaded and applied in sequence during the update process. 

To minimize the overall data sent over the data link, try to find a sweet spot for minimizing dropped frames, while also avoiding the overhead of frames that are too small.

A smaller chunk size can enhance reliability by reducing the risk of interruptions or failures during the update, especially in environments with unstable network connections. However, too small a chunk size can result in increased overhead, as more frequent communication is required to manage the transfer.

The Chunk, DIFF, and Fill commands can be aggregated into larger messages, to avoid sending a lot of small frames.

Avoid unnecessary changes

Have you ever made a small change and an unexpectedly large number of changes appeared in the binary image? Have you ever generated binary images from the same commit, but got different results on different machines, or even different results on the same machine at different times?

If you answered yes, there are some things you can do to get more deterministic builds. We’ll use gcc as our example tool.

File paths: Avoid including file paths in your release build, by excluding macros like __FILE__. If this isn’t acceptable, you can set up your build to enforce the release build to be run from a certain directory, or modify environment variables to make the present working directory a constant on any machine

Time stamps: Avoid embedding timestamps in your release build, by excluding macros like __TIMESTAMP__, __TIME__, and __DATE__.Random seed values: Avoid randomly changing seed values. For each file that uses a random seed value, you can create another file with a predefined seed value, and compile the file with the frandom-seed=<input-file-name> option.

Existing Solutions

Whenever possible, try to use a proven, off-the-shelf solution that is efficient, reliable, and secure. Here are a few offerings:

FreeRTOS:

AWS IoT Over the Air (OTA) Library

Embedded Linux:

Mender

SWUpdate

Note that there are many more options than what is on this list!

If you do decide to roll your own solution, see Memfault’s article on creating a reliable device firmware update solution.

Summary

To save time, energy, or cellular data costs, you can use the tips above to reduce the size of your embedded device updates. Dojo Five brings modern tools, techniques, and best practices from the web and mobile development environments, paired with leading-edge innovations in firmware to our customers to help them build successful products and successful clients.
We have talented engineers on hand ready to help you with all aspects of your EmbedOps journey. You can Book a Call with us to discuss your embedded project, or sign up for free for our EmbedOps CI and build management product.

Sign up to get our content updates!

Unlock the full potential of your embedded projects with our expert insights! Dive into our comprehensive resources to stay ahead in firmware development. Subscribe now to get the latest best practices and guides delivered straight to your inbox.

Sign Up for Updates

Discover why Dojo Five EmbedOps is the embedded enterprise choice for build tool and test management.

Sign up to receive a free account to the EmbedOps platform and start building with confidence..

  • Connect a repo
  • Use Dev Containers with your Continuous Integration (CI) provider
  • Analyze memory usage
  • Integrate and visualize static analysis results
  • Perform Hardware-in-the-Loop (HIL) tests
  • Install the Command Line Interface for a developer-friendly experience

Subscribe to our Monthly Newsletter

Subscribe to our monthly newsletter for development insights delivered straight to your inbox.

Interested in learning more?

Best-in-class embedded firmware content, resources and best practices

Modern Embedded Firmware Development Practices in the Warehouse Automation Industry

In the fast-paced world of warehouse automation, the development of embedded firmware is a critical aspect that underpins the efficiency and functionality of automated systems. This blog explores the multifaceted realm of modern embedded firmware development, as well as the innovative testing practices that help identify and mitigate bugs early in the process, leading to cost savings and more robust systems. Modern Embedded Firmware Development in the Warehouse Automation Industry Embedded firmware development is the unsung hero of the warehouse

Read More »
The Hidden Cost of Legacy Firmware

The Hidden Costs of Legacy Firmware (and Why Modernization Can’t Wait)

Legacy firmware influences more than performance. It slows an organization’s ability to adapt. It shapes productivity, impacts security posture, and affects compliance readiness. In markets where firmware project management or embedded software project management can determine commercial success, failure to adapt means carrying a constant competitive handicap. The Price of Standing Still In older development environments, everyday work takes longer than it should. Engineers waste time untangling mismatched build environments, resolving bugs that resurface, and decoding design choices buried in

Read More »