-
Best Practices for Monitoring Device Connectivity
by Eric JohnsonThis post will cover why device connectivity is complex and what methods we have available to diagnose and solve connectivity problems, both in the office and remotely in production. The tool at the core of our strategy is metrics, but we’ll briefly survey other tools like logging and protocol analysis. We’ll look in-depth at the utility of metrics and wrap up with some practical metric examples to use in your device.
-
Counting Crashes to Improve Device Reliability
This post will cover the most common reliability metrics that hardware manufacturers use. It will explore which are best for IoT devices, including a novel measurement, Crash Free Hours. We’ll cover exactly what you’ll need to collect on your devices within firmware to measure device reliability and ensure your devices are working as expected.
-
Pocket article: Debug vs. Release Builds Considered Harmful
Separate “debug” and “release” builds are very common in embedded development. Typically the notion is improved debug capabilities (less aggressive compiler optimizations, more debugging information like logs) vs. highly optimized and hardened production release builds. I’m here to describe disadvantages to this practice, and why it might make sense to consolidate to a single build!
-
C Structure Padding Initialization
This article takes a look at a few different aspects of C structure initialization. In particular, we’ll look at when it matters, the current state of things in Clang and GCC, recommendations, and the ✨ future ✨.
-
Automatically format and lint code with pre-commit
This article provides some background and guidelines for using
pre-commit
to automatically format and lint C-language firmware codebases. We’ll cover general guidelines and go over an example set of checks that can be helpful when working on firmware code. -
Profiling newlib-nano's memcpy
This article takes a look at one of the commonly used functions provided by the Newlib C library:
memcpy
. We’ll examine the default nano implementation and the performance implications, comparing it against the faster non-default implementation. -
Better Firmware with LLVM/Clang
In this article, I hope I can convince you that adding a Clang build target to your project can be a relatively simple and useful endeavor. We will cover how to take advantage of some of the rich features shipped with the toolchain and identify some memory leaks and mutex deadlocks in an example project at compile time! We will also walk through a step-by-step example of updating a GCC based ARM Cortex-M project to cross-compile with LLVM/Clang.
-
Embedded C/C++ Unit Testing with Mocks
In this article, we do a deep-dive into unit testing with mocks. We’ll go over where they fit into your unit testing infrastructure, how to write them in C/C++, and finally run through some real-world examples. At the end, we’ll briefly talk about integration tests.
-
GNU Binutils: the ELF Swiss Army Knife
In this article, we will explore some of my favorite binary introspection tools, such as GNU Binutils. The material is geared toward the embedded software crowd that typically writes C and C++, but many of the ideas, tools, and lessons learned can be applied to a variety of low-level software. We will walk through practical examples of how the tools can be leveraged to aid in the development process irrespective of the compiler you are using (e.g. GCC, Clang, IAR, ARMCC, etc).
-
A Guide to Watchdog Timers for Embedded Systems
In this article we will discuss the last line of defense in embedded systems – watchdogs. We will walk through a step-by-step example of how to implement a watchdog subsystem, incorporating a “hardware” and “software” watchdog, and examine effective strategies for root causing the underlying problems leading to these hangs.
-
Improving Compilation Time of C/C++ Projects
Build times don’t have to be long, even yours! However, many factors play a role. In this post, we’ll dive into which factors contribute to slower builds, compare and contrast options, and also go over some easy wins which you can immediately contribute to your project and share with your teammates. The techniques discussed apply to most C/C++ compilers and projects, and there are a couple extra tips for those using the GNU GCC compiler.
-
Managing Developer Environments with Conda
This post gives an introduction to what Conda is, explains why you should care about keeping your developer environments in sync, and finally provides a walk-through on getting started with Conda to set up a GCC based developer environment.
-
Using Asserts in Embedded Systems
By using asserts proactively in embedded systems on debug and production builds, developers can both prevent more bugs before shipping and quickly surface and fix them after shipping. Proper assert handling is also the safest way to handle issues and undefined behavior that occur in production. In this post, we’ll go over best practices with asserts, when to use asserts, and then come up with a production ready custom assert implementation for an ARM Cortex-M device, all while keeping the code size usage to a minimum.
-
Embedded C/C++ Unit Testing Basics
In this post, we go into detail on how to properly build abstractions to stub, fake, and mock out implementations of low level embedded software and provide a full real-world example of a unit test using the CppUTest 3.8 unit test framework.
-
Building Better Firmware with Continuous Integration
In this post, we introduce Continuous Integration as a modern technique to allow larger teams to move fast without breaking things. We’ll explain what Continuous Integration is, why you may want to use it, and walk you through setting up CircleCI on a firmware project step by step.