Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Embedded Systems Architecture

You're reading from   Embedded Systems Architecture Explore architectural concepts, pragmatic design patterns, and best practices to produce robust systems

Arrow left icon
Product type Paperback
Published in May 2018
Publisher Packt
ISBN-13 9781788832502
Length 324 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Daniele Lacamera Daniele Lacamera
Author Profile Icon Daniele Lacamera
Daniele Lacamera
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Embedded Systems – A Pragmatic Approach 2. Work Environment and Workflow Optimization FREE CHAPTER 3. Architectural Patterns 4. The Boot-Up Procedure 5. Memory Management 6. General-Purpose Peripherals 7. Local Bus Interfaces 8. Low-Power Optimizations 9. Distributed Systems and IoT Architecture 10. Parallel Tasks and Scheduling 11. Embedded Operating Systems 12. Other Books You May Enjoy

Domain definition

Embedded systems are computing devices performing specific, dedicated tasks with no direct or continued user interaction. Due to the variety of markets and technologies, these objects have different shapes and sizes, but often all have a small size and a limited amount of resources.

In this book, the concepts and the building blocks of embedded systems are analyzed through the development of the software components that interact with its resources and peripherals. The first step is to define the scope for the validity of the techniques and the architectural patterns explained here, within the broader definition of embedded systems.

Embedded Linux systems

One part of the embedded market relies on devices with enough power and resources to run a variant of the GNU/Linux operating system. These systems, often referred to as embedded Linux, are outside the scope of this book, as their development includes different strategies of design and integration of the components. A typical hardware platform that is capable of running a system based on the Linux kernel is equipped with a reasonably large amount of RAM, up to a few gigabytes, and sufficient storage space on board to store all the software components provided in the GNU/Linux distribution. Additionally, for Linux memory management to provide separate virtual address spaces to each process on the system, the hardware must be equipped with a memory management unit (MMU), a hardware component that assists the OS in translating physical addresses to virtual addresses, and vice versa, at runtime.

This class of devices presents different characteristics that are often overkill for building tailored solutions, which can use a much simpler design and reduce the production costs of the single units. Hardware manufacturers and chip designers have researched new techniques to improve the performance of microcontroller-based systems, providing, in the past decade, a new generation of platforms that would cut hardware costs, firmware complexity, size, and power consumption to provide a set of features that are most interesting for the embedded market.

Due to their specifications, in some real-life scenarios, embedded systems must be able to execute a series of tasks within a short, measurable, and predictable amount of time. These kinds of systems are called real-time systems, and differ from the approach of multi-task computing used in desktops, servers, and mobile phones. Real-time processing is a goal that is extremely hard, if not impossible, to reach on embedded Linux platforms. The Linux kernel is not designed for hard real-time processing, and even if patches are available to modify the kernel scheduler to help meet these requirements, the results are not comparable to bare-metal, constrained systems that are designed with this purpose in mind.

Some other application domains, such as battery-powered and energy-harvesting devices, can benefit from the low power consumption capabilities of smaller embedded devices and the energy efficiency of the wireless communication technologies often integrated in embedded connected devices. The higher amount of resources and the increased hardware complexity of Linux-based systems often does not scale down enough on energy levels, or requires much more effort to meet similar figures in power consumption.

The type of microcontroller-based systems that we'll analyze in this book are 32-bit systems, capable of running software in a single-threaded, bare-metal application as well as integrating minimalist real-time operating systems, which are very popular in the industrial manufacturing of embedded systems that we use on a daily basis to accomplish specific tasks, and are becoming more and more adopted to define more generic, multiple-purpose development platforms.

Low-end 8-bit microcontrollers

In the past, 8-bit microcontrollers have dominated the embedded market. The simplicity of their design allows us to write small applications that can accomplish a set of pre-defined tasks, but are too simple and usually equipped with way too few resources to implement an embedded system, especially since 32-bit microcontrollers have evolved to cover all the use cases for these devices within the same range of price, size, and power consumption.

8-bit microcontrollers nowadays are mostly relegated to the market of educational platform kits, aimed at introducing hobbyists and newcomers to the basics of software development on electronic devices. 8-bit platforms are not covered in this book, because they lack the characteristics that allow advanced system programming, multithreading, and advanced features developed to build professional embedded systems.

In the context of this book, the term embedded systems is used to indicate a class of systems running on microcontroller-based hardware architecture, offering constrained resources but allowing to build real-time systems, through features provided by the hardware architecture to implement system programming.

Hardware architecture

The architecture of an embedded system is centered around its microcontroller, also sometimes referred to as the microcontroller unit (MCU), typically a single integrated circuit containing the processor, RAM, flash memory, serial receivers and transmitters, and other core components. The market offers many different choices among architectures, vendors, price range, features, and integrated resources. These are typically designed to be inexpensive, low-resource, low-energy consuming, self-contained systems on a single integrated circuit, which is the reason why they are often referred to as System-on-Chip (SoC).

Due to the variety of processors, memories, and interfaces that can be integrated, there is no actual reference architecture for microcontrollers. Nevertheless, some architectural elements are common across a wide range of models and brands, and even across different processor architectures.

Some microcontrollers are dedicated to specific applications and exposing a particular set of interfaces to communicate to peripherals and to the outside world. Others are focused on providing solutions with reduced hardware costs, or with very limited energy consumption. Nevertheless, the following set of components is hardcoded into almost every microcontroller:

  • Microprocessor
  • RAM
  • Flash memory
  • Serial transceivers

Additionally, more and more devices are capable of accessing a network, to communicate with other devices and gateways. Some microcontrollers may provide either well-established standards, such as Ethernet or Wi-Fi interfaces, or specific protocols specifically designed to meet the constraints of embedded systems, such as Sub-GHz radio interfaces or Controller Area Network (CAN) bus, being partially or fully implemented within the IC.

All the components must share a bus line with the processor, which is responsible for coordinating the logic. The RAM, flash memory, and control registers of the transceivers are all mapped in the same physical address space:

A simplified block diagram of the components inside a generic microcontroller

The addresses where the RAM and flash are mapped to depend on the specific model, and are usually provided in the datasheet. A microcontroller is able to run code in its own native machine language, a sequence of instructions conveyed into a binary file that is specific for the architecture it is running on. By default, compilers provide a generic executable file as the output of the compilation and assembly operations, which needs to be converted into the format that is executable for the target.

The processor is designed to execute the instructions stored, in its own specific binary format directly from RAM as well as from its internal flash memory, usually mapped starting from position zero in memory, or from another well-known address specified in the microcontroller manual. The CPU can fetch and execute code from RAM faster, but the final firmware is stored in the flash memory, which is usually bigger than the RAM on almost all microcontrollers, and permits it to retain the data across power cycles and reboots.

Compiling a software operating environment for an embedded microcontroller and loading it onto the flash memory requires a host machine, which is a specific set of hardware and software tools. Some knowledge about the target device's characteristics is also needed to instruct the compiler to organize the symbols within the executable image. For many valid reasons, C is the most popular language in embedded software, although not the only available option. Higher-level languages, such as Rust and C++, can produce embedded code when combined with a specific embedded runtime, or even in some cases by entirely removing the runtime support from the language. This book will focus entirely on C code, because it abstracts less than any other high-level language, thus making easier to describe the behavior of the underlying hardware while looking at the code.

All modern embedded systems platforms also have at least one mechanism (such as JTAG) for debugging purposes, and to upload the software to the flash. When the debug interface is accessed from the host machine, a debugger can interact with the breakpoint unit in the processor, interrupting and resuming the execution, and can also read and write from any address in memory.

A significant part of embedded programming is the communication with the peripherals, using the interfaces that the MCU exposes. Embedded software development requires basic knowledge of electronics, the ability to understand schematics and datasheets, and confidence with the measurement tools, such as logic analyzers or oscilloscopes.

Understanding the challenge

Approaching embedded development means keeping the focus on the specifications as well as the hardware restrictions at all times. Embedded software development is a constant challenge to focus on the most efficient way to perform a set of specific tasks, but keeping in strong consideration the limited resources available. There are a number of compromises to deal with, which are uncommon in other environments. Here are some examples:

  • There might be not enough space in the flash to implement a new feature
  • There might not be enough RAM to store complex structures or make copies of large data buffers
  • The processor might be not fast enough to accomplish all the required calculations and data processing in due time
  • Battery-powered and resources-harvesting devices might require lower energy consumption to meet lifetime expectations

Moreover, PC and mobile operating systems make large use of the MMU, a component of the processor that allows runtime translations between physical and virtual addresses. The MMU is a necessary abstraction to implement address space separation among the tasks, and between the tasks and the kernel itself. Embedded microcontrollers do not have an MMU, and usually lack the amount of non-volatile memory required to store kernel, applications, and libraries. For this reason, embedded systems are often running in a single task, with a main loop performing all the data processing and communication in a specific order. Some devices can run embedded operating systems, which are far less complex than their PC counterparts.

Application developers often see the underlying system as a commodity, while embedded development often means that the entire system has to be implemented from scratch, from the boot procedure up to the application logic. In an embedded environment, the various software components are more closely related to each other, because of the lack of more complex abstractions, such as memory separations between the processes and the operating system kernel. A developer approaching embedded systems for the first time might find testing and debugging on some of the systems a bit more intricate than just running the software and reading out the results. This becomes especially true on those systems that have been designed with little or no human interaction interfaces.

A successful approach requires a healthy workflow, which includes well-defined test cases, a list of key performance indicators coming from the analysis of the specifications to identify possibilities of trade-offs, a number of tools and procedures at hand to perform all the needed measurements, and a well-established and efficient prototyping phase.

In this context, security deserves some special consideration. As usual, when writing code at the system level, it is wise to keep in mind the system-wide consequences of possible faults. Most embedded application code run with extended privileges on the hardware, and a single task misbehaving can affect the stability and the integrity of the entire firmware. As we will see, some platforms offer specific memory-protection mechanisms and built-in privilege separation, which are useful for building fail-safe systems even in the absence of a full operating system based on separating process address spaces.

Multithreading

One of the advantages of using microcontrollers designed to build embedded systems is the possibility to run logically separated tasks within separate execution units by time-sharing the resources.

The most popular type of design for embedded software is based on a single loop-based sequential execution model, where modules and components are connected to each other exposing callback interfaces. However, modern microcontrollers offer features and core logic characteristics that can be used by system developers to build a multi-tasking environment to run logically separated applications.

These features are particularly handy in the approach to more complex real-time systems, and interesting to understand the possibilities of the implementation of safety models based on process isolation and memory segmentation.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image