Software Architecture for Embedded Systems
Software architecture for embedded systems describes how the software of an embedded system is structured, organized, and connected to the hardware. PICKPLACE works in this field on architecture definitions, classifying existing software structures, and refactoring projects,...

Content
The Essentials of Software Architecture for Embedded Systems

Software architecture in embedded systems refers to the high-level structure of the software, including its organization, components, and their relationships. In embedded systems, this often involves balancing resource constraints (like memory and processing power) with requirements for real-time performance, reliability, and safety. Key considerations include choosing appropriate operating systems (or no OS), designing modular and reusable components, managing inter-process communication, and ensuring deterministic behavior.
Software architecture in embedded systems describes the fundamental structure of the software of an embedded system. This includes the division into modules, the responsibilities of these modules, the communication paths between software parts, and the boundaries with the hardware. While a single function describes what the system is supposed to do, the architecture describes where this function lies within the software structure, what data it needs, which interfaces it uses, and what dependencies arise from this.
In an embedded system, software is rarely considered in isolation from the electronics. Sensors, actuators, communication interfaces, memory, real-time requirements, and operating system mechanisms influence the software's structure. Therefore, an architecture must clarify which tasks are handled close to the hardware, what logic resides in drivers, which functions belong to the application, and how states, errors, and data flows are managed. This separation does not automatically prevent errors, but it makes it visible where a change or analysis needs to start.
Typical architectural layers include hardware abstraction, drivers, operating system or scheduler-adjacent functions, middleware, communication layers, and application logic. Depending on the system, the structure can be simpler or more layered. In small microcontroller applications, the separation between driver access, state logic, and the user interface or communication interface may be sufficient. For larger control units, additional questions arise regarding task structures, bus communication, diagnostics, bootloaders, memory layout, update mechanisms, or variant management.
PICKPLACE views software architecture for embedded systems as the basis for development and further enhancement. An architectural definition describes not only boxes and arrows but also assigns technical decisions. These include, for example, which modules are allowed to possess data, which functions are only accessible via interfaces, how error states are propagated, and which software components work directly with registers, peripherals, or operating system services. These specifications help to connect discussions about individual implementations with the overall system in the project.
With existing systems, architectural work often doesn't start from scratch. The existing codebase, previous project decisions, and established dependencies define the framework. Then, it's about capturing the real architecture: Which modules actually exist? Which interfaces are used? Where do application functions directly access hardware? Where are responsibilities mixed? Documented insight into the current state creates the foundation for targeted change planning and assessing the risks of code modifications.
Why does a control unit or a machine need a software architecture?
A control unit or machine requires a software architecture because many functions must be implemented simultaneously with limited resources and fixed technical dependencies. Inputs must be captured, outputs controlled, communication protocols handled, errors detected, operating states managed, and timing requirements met. Without a discernible structure, dependencies arise that can cause new side effects with every change.
In embedded projects, requirements from various areas converge. Mechanics, electronics, firmware, application software, user interface concepts, communication, and manufacturing can each bring their own specifications. The architecture connects these specifications with the software structure. For example, if a sensor value is captured, filtered, evaluated, and passed on to a communication interface, it must be traceable which software components are involved in this chain. Only then can it be checked whether a change in capture also has implications for diagnostics, control, or output.
Architecture also supports implementation planning. When modules and interfaces are described, tasks can be better delineated. One developer can work on a driver while another extends the state logic, as long as the interfaces are clear. Tests also benefit from this separation because individual functions or modules can be tested more precisely. With unclear structures, it is often necessary to first determine which parts of the system are affected before making a change.
For control units and machines, the interplay between real-time behavior and software structure must also be considered. Some functions must be executed at fixed time intervals, while others react to events or communication requests. The architecture determines which tasks are executed in which tasks, interrupts, or state machines. This results in specifications for data access, synchronization, and error handling. An unclear distribution can lead to functions that work individually but are difficult to analyze in conjunction with each other.
When evolving existing systems, the architecture serves as a guide for changes. New features, modified hardware, additional communication channels, or product variants should not be added arbitrarily in the code. The architecture describes where extensions fit into the existing structure and which interfaces need to be adapted. This prevents every extension from becoming a scavenger hunt for hidden dependencies.
PICKPLACE also uses architectural work to clarify project boundaries. Not every software needs to be completely restructured when a specific problem arises. In some projects, targeted documentation of existing dependencies is sufficient to prepare for error analysis or expansion. In other cases, the analysis shows that refactoring is necessary before new functions can be meaningfully added. Architecture provides a technical basis for this without automatically prescribing a specific technical solution.
Good architecture ensures that software remains extensible later by implementing principles like modularity, loose coupling, and high cohesion. Modularity breaks down the software into smaller, independent components, each with a specific function. This isolation means changes or additions can be made to one module without affecting others. Loose coupling minimizes dependencies between modules, so modifications to one component have minimal impact on the rest of the system. High cohesion within a module means that its elements are strongly related and focused on a single task, making it easier to understand, maintain, and extend. Additionally, using design patterns such as Abstract Factory, Strategy, or Observer can provide built-in flexibility for future modifications. Clear separation of concerns also plays a vital role, ensuring that different aspects of the software (e.g., presentation, business logic, data access) are handled by distinct layers, which simplifies the process of altering or adding new functionalities. Finally, adhering to SOLID principles (Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion) guides developers in creating software that is easier to understand, maintain, and extend.
Good architecture ensures future extensibility not by anticipating as many future functions as possible. It remains extensible when responsibilities are clearly separated, interfaces are understandably described, and dependencies remain limited. For embedded systems, this means that hardware-near parts, control logic, communication, and application functions are not unnecessarily mixed together.
A typical example is hardware access. If application logic directly accesses registers or specific peripherals, a later change of hardware or a driver becomes complex. If, on the other hand, the access is within a defined layer, the application can work with more abstract functions. This does not replace checking the specific boundary conditions, but it reduces the places where a change needs to intervene.
Data flows also influence extensibility. If many modules modify the same global data, it becomes difficult to track which state is valid when. An architecture can define which modules generate data, which ones read it, and through which interfaces changes occur. This makes it clear, with state machines, regulations, or communication sequences, which states are permitted and where transitions take place.
Interfaces are another key point. An interface describes not only function names but also expectations: valid value ranges, error cases, timing behavior, initialization order, and side effects. For embedded software, it can also be relevant whether a function is allowed to be called from an interrupt context, whether it blocks, whether it allocates memory, or whether it accesses shared resources. If such properties are not documented, assumptions often arise during extensions, which later lead to hard-to-find errors.
Scalability also depends on the documentation of the architecture. Documentation does not need to explain every line of code. It should describe the structure in such a way that developers, testers, and technical project managers can understand the fundamental decisions. This includes module overviews, interface descriptions, data and control flows, state models, and indications of technical limitations. For existing systems, even reduced architectural documentation can be sufficient to plan further steps.
Refactoring is often the transition from a grown structure to a more clearly described architecture. This does not necessarily change the visible behavior of the software. The goal is to separate responsibilities, remove duplicate logic, reduce dependencies, or clarify interfaces. However, in embedded projects, refactoring must be carefully planned because timing, memory consumption, hardware access, and existing tests must be considered. An architecture provides the framework to carry out refactoring not as a collection of individual code changes, but as comprehensible structural work.
PICKPLACE ensures that proposed changes fit into the existing system during architecture and refactoring work. An architecture should not just be described as a theoretical target model when hardware, available storage, the operating system, or existing delivery statuses impose tight limitations. Therefore, architectural decisions are considered in the context of specific project conditions: Which parts can be changed? Which interfaces are dictated by other systems? Which software areas are particularly prone to errors? What documentation is needed for handover to development or maintenance?
Typical tools and methods
- Modeling tool Sparx Systems Enterprise Architect
- Requirements Tool Siemens Polarion
- RTOS FreeRTOS
- Modeling tool IBM Engineering Systems Design Rhapsody
- UML and SysML
Our Services
PICKPLACE supports projects related to software architecture and embedded systems, primarily in three areas: architecture definition, refactoring, and documentation of existing architectures. The specific implementation depends on the state of the software, the product's development stage, and planned changes.
In architecture definition, we structure requirements, hardware references, operating system components, drivers, application logic, and interfaces into an implementable software concept. This includes the division into modules, the description of responsibilities, and the definition of communication between the software parts. Depending on the project, task structures, state models, data flows, or dependencies on peripherals and communication interfaces are also considered.
For existing systems, we analyze the current architecture using code, documentation, and known project requirements. The goal is to visualize the actual setup and identify dependencies that are relevant for further development, troubleshooting, or migration. This can result in architectural overviews, module descriptions, or interface clarifications.
In refactoring, we support the targeted revision of established software structures. Typical tasks include separating mixed responsibilities, decoupling hardware-close accesses from application logic, clarifying interfaces, or preparing for an extension. We also consider that embedded software is often limited by memory, runtime, hardware access, and available testing options.
For the documentation of existing architectures, we create comprehensible descriptions of the software structure. This documentation can record development decisions, facilitate onboarding into a codebase, or serve as a basis for further implementation steps. The focus is on the information needed in the project: module structure, interfaces, data flows, states, technical dependencies, and known limitations of the existing structure.