We’ve discussed recently the importance of firmware engineering, especially in light of the coming deluge of Internet of Things (IoT) devices.
Today we go into a bit more detail about firmware development: How we got where we are in the evolution of firmware development, some of the main differences between firmware development and PC or mobile software development, and how those differences drive the execution of a firmware project.
A Little History
When digital integrated circuits (ICs) first became practical for use in mass-produced devices in the 1970s, they tended to be simple in design: A few logic gates arranged in what digital circuit designers call a state machine. State machines are good for running the same simple process over and over again (think “washing machine”), but they are limited in their ability to make decisions on the basis of calculations. Demand for increased capabilities from these control circuits spurred the development of specialized ICs called microcontrollers.
Microcontrollers are generally more sophisticated than the earlier state-machine ICs and require software to operate the processes and communicate with the other device components, such as switches, buttons, and displays. This software is called firmware, and the self-contained combination of the firmware and the device hardware is commonly called an embedded system.
As devices evolved from standalone gadgets to networks of devices working together, the firmware was called upon not only to operate each device itself but to use one or more common communication protocols (such as WiFi and Bluetooth) to interoperate. This adds another layer of complexity that device developers have to tackle.
Challenges in Firmware Development
Unlike other types of software, firmware comes with some special challenges because it comes into direct contact with hardware devices. If you’re writing software for a PC, and something goes wrong, the worst-case scenario is that the PC crashes; it’s unlikely to cause permanent damage.
With firmware, however, you are directly causing an electric current to flow within the control circuit, and if you make it flow the wrong way, or to the wrong place at the wrong time, you can cause physical damage to the device. Microcontrollers can be expensive (especially ones designed for space or other harsh environments), so you won’t burn up too many of them before you find you’re looking for another job.
So, firmware developers have to be mindful of a number of potential issues that the PC developer doesn’t need to contend with:
- Power budget. Especially in the case of modern wireless sensor networks, each device has a limited power budget to work with, often dictated by the power output of a small battery or a solar cell. The firmware code needs to be ultra-efficient and not force the microcontroller to spend a lot of time at full power just waiting for something to happen.
- Timing. Real devices operate in real time. One would like to think that when a user presses a button on the device, the signal reaches the microcontroller instantaneously, but if the signal has to traverse multiple logic gates and other components before it arrives at the microcontroller, this assumption might be off by a few nanoseconds. It doesn’t sound like much, but it can be enough to cause real-world failures and headaches for the development team.
- Resource limitations. Small devices often have limited (or no) data storage space and only a small amount of random-access memory (RAM) to work with, so memory management becomes crucial. Memory should be strictly allocated only as long as needed, and the same data should not be copied from one place in memory to another.
- Code level. In some cases, using a high-level programming language, such as C or Java, simply involves too much resource overhead for certain functions, and using assembly language for these cases should be considered instead. Assembly-language coding is not for the faint of heart, so someone with expertise is needed to handle these tasks.
All of this, of course, is on top of recommended best practices for any software development, such as documenting the code, avoiding spaghetti code, and making code readable, understandable, and (most important!) updateable by the developer who has to work on it for Version 2.
One of the most important considerations for firmware development is that for many devices, the firmware has a long lifecycle, often measured in years instead of the months or weeks seen with other types of software. Some devices remain deployed in the field for long periods, inaccessible by humans, and thus can’t be accessed to perform routine maintenance such as firmware upgrades. Other devices have no firmware upgrade capability at all, so the firmware has to work reliably for the entire service life of the device.
The three keys to success are the firmware architecture, program design, and testing.
Architecture: The name of the game here is “future-proofing.” If the device is expected to have functionality added to it, the firmware architecture should be designed to accommodate future features—even if those features are not completely known at the time the architecture is designed.
Another important consideration is firmware reuse. If a manufacturer has a line of products that do essentially the same thing—sewing machines, for instance—the same firmware might be used in all of them, with some variations for the different models. Designing the architecture so that these variations are easily accommodated will ensure that new models can be introduced without having to re-design the firmware.
Program design: This activity happens after the high-level architecture is defined but before any coding takes place. This is where functions and variables are defined and where the program flow is spelled out. This part needs to be conducted and reviewed in some detail by the entire development team because any conflicts or misunderstandings by the developers can have disastrous results. If one developer is expecting the reading of a pressure transducer to be expressed in pounds per square inch, but another developer responsible for the transducer output expresses it in kilopascals instead, there could be serious trouble.
Testing: Unlike PC or mobile software testing, which essentially takes a set of inputs and evaluates whether the outputs are as expected, firmware testing must address various “normal” and “extreme” environmental factors, including modes of use not anticipated by the device designers. (What if the microwave user presses the “Popcorn” button at the same time as the “3” button?)
Unit testing (of individual components), integration testing (of a combination of components), as well as system testing (at the finished device level) are all critical activities to ensure the firmware is thoroughly tested. The last thing a device manufacturer needs is to have a massive recall of products because of a firmware error, especially one that affects user safety.
Device Manufacturers: Living and Dying by Firmware
Firmware has become a fundamental part of device design. Device manufacturers ignore (or under-resource) it at their peril. Firmware development may not capture the public’s attention the way GUI software does (the best firmware, after all, is completely transparent to the user), but it can make the difference between a wildly successful product line and a corporate embarrassment.