Embedded software is specialized programming on a chip, such as a microcontroller (MCU), or in firmware in an embedded MCU, to control its functions. Unlike general computer applications, designed to be installed on various computer systems or modified to provide varying levels of functionality, embedded software is generally purpose-built for a single hardware environment and application. Embedded software is written to work within the processing, memory, input/output (I/O) constraints, and peripheral device restrictions of a specific MCU or family of MCUs.
Embedded application software sits atop multiple software layers, as seen in Figure 1. Below the application software—but also within the application layer—is the application programming interface (API) that defines the available routines, protocols, and tools for creating an application. An API defines the high-level interface of the behavior and capabilities of the MCU and its inputs and outputs, enabling the use of the API in multiple applications with changes only to the implementation of the API and not the general interface or behavior.

Middleware provides services to software applications beyond those available from the operating environment. It has been described as “software glue.” Middleware includes libraries that provide services such as data storage, connectivity such as Wi-Fi, CAN, USB, Bluetooth and Zigbee, and device-specific functions. Middleware libraries can execute quickly when they are compiled in machine language.
Device drivers directly interface with and control specific hardware functions within the MCU, such as bus initialization and transaction drivers and I/O initialization, memory and memory management drivers, and control drivers. Device drivers can be generic or device-specific. A generic device driver manages hardware located on the board and not integrated into the MCU, such as I2C, PCI, and other communications buses, off-chip memory, etc. An architecture-specific device driver manages hardware integrated into the MCU, such as various types of memory and I/Os.
The device drivers work with the MCU’s operating environment (OE). There is a range of OEs, including:
- Bare metal OEs are the simplest and consist of firmware running directly on the processor’s hardware without the benefit of a conventional operating system (OS). In a bare-metal implementation, firmware is co-developed with the hardware to optimize the operation and perform many of the functions of a conventional OS.
- Embedded OS that is purpose-built for the MCU environment. These are sometimes called real-time operating systems (RTOS) and developed for even simple 8-bit MCUs. RTOS can outperform bare metal implementations but typically requires more memory.
- Full-featured OS on larger MCUs with even more memory; an OS like Linux can be used.
Using an embedded or full-featured OS enables developers to write code at a higher level than bare-metal implementations. Two different software layers have emerged to enable MCU developers to write code similar to an application developer for a PC: hardware abstraction layers (HALs) and APIs.
APIs and HALs are closely related concepts but serve two different functions within the software stack shown in Figure 2. The HAL provides a common RTOS or middleware components interface with hardware drivers. The HAL can operate at the driver interface or be used as a wrapper to provide a common interface between existing drivers and higher-level code. APIs provide a common interface for controlling the system’s real-time behavior and accessing common components such as serial communication and file accesses. APIs provide developers with a toolkit to speed up application code generation.

Using a layered embedded software architecture with APIs and HALs can significantly increase software reusability. For example, if there is a major hardware upgrade, instead of rewriting the HAL, it could be implemented by simply replacing the existing drivers. Or, updating/changing the HAL and using the same underlying hardware and drivers could result in new application implementation. Similar flexibility is provided at the application layer by the use of APIs. In both cases, there are faster development cycles, increased ability to reuse code, and improved code stability and security due to fewer changes.
C and Embedded C
C is a widely used, general-purpose programming language that requires an operating system (OS) to function. It’s often used on desktop computers and other environments where a microprocessor (MPU) and an OS are found. Compilers for C generate OS-dependent executables.
Embedded C is a set of language extensions for C designed to address the needs of embedded systems where there may not be an OS. Embedded C is designed to work with the limited RAM, ROM, and I/O on an embedded MCU. It provides some enhanced features for embedded control, including the in_port and out_port I/O functions, fixed-point arithmetic, and multiple distinct memory banks. Embedded C also gives developers more opportunities for memory management aimed at MCU environments that must deal with memory and power constraints.
Automotive-embedded software can be different
In automotive advanced driver assistance systems (ADAS), real-time interactions are required across multiple embedded sensing and control systems, such as braking, steering, suspension, powertrain, and more. An embedded electronic control unit (ECU) is at the heart of these systems. Multiple ECUs are typically interconnected to form various distributed control systems in an automotive system. These complex control systems must ensure correct functional implementation and data security.
By communicating with each other, the ECUs that make up a vehicle’s distributed system can execute various functions like automatic emergency braking, adaptive cruise control, stability control, adaptive headlights, and much more. A single function might need interactions across 20 or more embedded software applications spread across numerous ECUs connected by multiple networking protocols. Complex control algorithms deployed with the embedded software ensure the proper timing of functions, needed inputs and outputs, and data security.
A traditional ECU consists of a single MCU with associated hardware and an embedded software stack. There is a current trend in the design of ECUs with complex systems on chip (SoC) devices containing multiple MCUs and other computing devices. These SoCs are designed to contain multiple ECU abstractions to consolidate hardware. That can result in even more complex embedded software implementations. More comprehensive development tools are needed as embedded software grows in complexity and sophistication.
Software Development Kits
A software development kit (SDK) can be handy in embedded MCU systems based on an OS or RTOS. An SDK is a collection of tools, usually in a single package. SDKs are generally specific to a given MCU platform, programming language(s), and OS combination, speeding the application development process shown in Figure 3. Development tools can include integrated development environments (IDEs), compilers, and debugging tools for the creation and/or evaluation of application code. SDKs are more comprehensive and consider OSs, peripheral drivers, HALs, libraries, protocols, and other software factors to create a complete software solution.

A full-featured IDE will include numerous tools, such as:
- An editor creates a code in a high-level language such as C, C++, or Python.
- A compiler transforms a high-level programming language code into machine code.
- When the programming code is written in assembly language, the assembler does the same work as a compiler.
- A debugger identifies and helps correct bugs and mistakes.
- A linker combines code pieces and modules and gets an executable program.
- An emulator enables running the program to simulate the real environment accurately for fine-tuning.
Embedded software is critical to operating automotive systems, industrial processes, and IoT devices. As a result, developers need to be concerned with safety, stability, and security in addition to developing an efficient program. Safety and stability are related; embedded systems must ensure safe operation under all conditions, making stability important since unexpected behavior cannot be tolerated. Embedded systems are increasingly connected to other devices, whether on a common platform such as a single automobile or geographically dispersed. As with all digital devices, data security in embedded devices is paramount and increasingly challenging to ensure.
Summary
Embedded software is critical in many modern systems, from industrial controls to automotive ADAS systems, IoT devices, and more. Unlike general-purpose computing applications, embedded software is developed for a specific hardware environment and application. It is designed to work within the constraints of the processing, memory, I/O, and peripheral device restrictions of a specific MCU or family of MCUs. The embedded software stack architecture can be implemented with no OS, limited embedded OS, or full-featured OS such as Linux. Specific extensions of the C programming language have been developed to support embedded environments. Safety, security, and stability are particular concerns of embedded software developers.
References
A Layered View of Software for Embedded Microcontrollers, NXP
Embedded Basics – APIs vs HALs, Beningo Embedded Group
Embedded Software, Siemens
Embedded Development Software, Texas Instruments
Embedded software system developer, Sierra Software Ltd
How to choose the right firmware architecture for your IoT device, LocoLabs
Leave a Reply