Developing Reusable Firmware – A Practical Guide to API’s, HAL’s and Drivers

Developing firmware that can be reused is an important and critical skill. The majority of engineers and teams that I interact with are stuck constantly reinventing the wheel on every project that they work on. In order to help developers understand how they can create not just reusable application code but reusable firmware, down to the drivers themselves, I wrote a book entitled “Developing Reusable Firmware – A Practical Approach to API’s, HAL’s and Drivers”. After several years, the book is now officially ready! An excerpt can be found below or the entire first chapter with the table of contents can be read here.

Why Code Reuse Matters

Over the past several decades, embedded systems have steadily increased in complexity. The internet’s birth has only accelerated the process as our society has been in a race to connect nearly every device imaginable. Systems that were once simple and stand-alone must now connect through the internet in a secure and fail-safe manner in order to stream critical information up into the cloud. Complexity and features are increasing at an exponential rate with each device generation forcing engineers to reevaluate how to successfully develop embedded software within the allotted time frame and budget.

The increased demand for product features along with the need to connect systems to the internet has dramatically increased the amount of software that needs to be developed to launch a product. While software complexity and features have been increasing, the time available to develop a product has for the most part remained constant with a negligible increase in development time (2 weeks in 5 years) as can be seen in Figure 1. In order to meet project timelines, developers are forced to either purchase commercial off-the-shelf (COTS) software that can decrease their development time or they need to reuse as much code as possible from previous projects.

Firmware for microcontrollers has conventionally been developed for a specific application using functional design methodologies (if any methodology has been used at all) that typically tie the low-level hardware directly into the application code, making the software difficult if not impossible to reuse and port on the same hardware architectures let alone reuse on a different architecture. The primary driving factor behind developing throw-away firmware has been the resource constrained nature many embedded products exhibit. Microcontrollers with RAM greater than a few kilobytes and flash sizes greater than 16 kB were once expensive and could not be designed into a product without destroying any hope for making a profit. Embedded software developers did not have large memories or powerful processors to work with which prevented modern software design techniques from being used in application development.

Modern microcontrollers are beginning to change the game. A typical low end ARM Cortex-M microcontroller now costs just a few U.S. dollars and offers at a minimum 16 kB of RAM and 64 kB of flash. The dramatic cost decreases in memory, larger memory availability and more efficient CPU architectures is removing the resource constrained nature that firmware developers have been stuck with. The result is developers can now start utilizing design methods that decouple the application code from the hardware and allow a radical increase in code reuse.

Figure 1 – Average Firmware Project Development Time (in months)1

Portable Firmware

Firmware developed today is written in a rather archaic manner. Each product development cycle results in limited to no code reuse with reinvention being a major theme amongst development teams. A simple example is when development teams refuse to use an available real-time operating system (RTOS) and instead, develop their own in-house scheduler. Beyond wanting to build their own custom scheduler, there are two primary examples that demonstrate the issue with reinvention.

First, nearly every development team writes their own drivers because microcontroller vendors provide only example code and not production ready drivers. Examples provide a great jump-start to understanding the microcontroller peripherals but still requires a significant time investment to get a production intent system. There could be a hundred companies using the exact same microcontroller and each and every one will waste as much as thirty percent or more development time getting their microcontroller drivers written and integrated with their middleware! I have seen this happen repeatedly amongst my client base and heard numerous corroborating stories from the hundreds of engineers I interact with on a yearly basis.

Second, there are so many features that need to be packed into a product and with a typical design cycle being twelve months1, developers don’t take the time to properly architect their systems for reuse. High-level application code becomes tightly coupled to low-level microcontroller code which makes separating, reusing or porting the application code costly, time consuming and buggy. The end result, developers just start from scratch every time.

In order to keep up with the rapid development pace in today’s design cycles, developers need to be highly skilled in developing portable firmware. Portable firmware is embedded software that is designed to run on more than one microcontroller or processor architecture with little to no modification. Writing firmware that can be ported from one microcontroller architecture to the next has many direct advantages such as:
• Decreasing time-to-market by not having to reinvent the wheel (which can be time consuming)
• Decreasing project costs by leveraging existing components and libraries
• Improved product quality through using proven and continuously tested software

Portable firmware also has several indirect advantages that many teams overlook but can far outweigh the direct benefits such as:
• More time in the development cycle to focus on product innovation and differentiation
• Decreased team stress levels due to limiting how much total code needs to be developed (Happy, relaxed engineers are more innovative and efficient)
• Organized and well documented code that can make porting and maintenance easier and more cost effective

Using portable and reusable code can result in some very fast and amazing results as seen in the case study, “Firmware Development for a Smart Solar Panel”, but there are also a few disadvantages. The disadvantages are related to upfront time and effort such as:
• The software architecture needing to be well thought through
• Understanding potential architectural differences between microcontrollers
• Developing regression tests to ensure porting is successful
• Selecting real-time languages and understanding their interoperability or lack thereof
• Experienced and high-skilled engineers being available to develop a portable and scalable architecture

For development teams to successfully enjoy the benefits of portable code use, extra time and money needs to be spent up front. However, after the initial investment, development cycles have a jump start to potentially decrease development time by months versus the traditional embedded software design cycle. The long-term benefits and cost savings usually overshadow the upfront design costs along with the potential to speed up the development schedule.

Developing firmware with the intent to reuse also means that developers may be stuck with a single programming language. How does one choose a language for software that may stick around for a decade or longer? Using a single programming language is not a major concern in embedded software development as one might initially think. The most popular embedded language, ANSI-C, was developed in 1972 and has proven to be nearly impossible to usurp. Figure 2 shows the popularity of programming languages, for all uses and applications, dating back to 2002. Despite advances in computer science and the development of object oriented programming languages, C has remained very popular as a general language and is heavily entrenched in embedded software.

To read the entire first chapter and view the table of contents, click here.

Leave a Reply

Your email address will not be published. Required fields are marked *