Reader small image

You're reading from  Embedded Systems Architecture - Second Edition

Product typeBook
Published inJan 2023
PublisherPackt
ISBN-139781803239545
Edition2nd Edition
Right arrow
Author (1)
Daniele Lacamera
Daniele Lacamera
author image
Daniele Lacamera

Daniele Lacamera is a software technologist and researcher with vast experience in software design and development on embedded systems for different industries, currently working as freelance software developer and trainer. He is a worldwide expert in TCP/IP and transport protocol design and optimization, with more than 20 academic publications on the topic. He supports free software by contributing to several projects, including the Linux kernel, and his involvement within a number of communities and organizations that promote the use of free and open source software in the IoT.
Read more about Daniele Lacamera

Right arrow

The Boot-Up Procedure

Now that the mechanisms, tools, and methodologies are in place, it is finally time to start looking at the procedures required to run the software on the target. Booting up an embedded system is a process that often requires knowledge of the specific system and the mechanisms in play. Depending on the target, there are a few indications we need to look for in the manual to find out what the system expects from the developer to successfully boot executables from the flash memory. This chapter will focus on the description of the boot process, with emphasis on the case of the Cortex-M microcontroller, which we decided to use as a reference platform. In particular, we will cover the following topics:

  • The interrupt vector table
  • Memory layout
  • Building and running the boot code
  • Multiple boot stages

By the end of this chapter, you will have an overview of main-loop embedded development.

Technical requirements

The interrupt vector table

The interrupt vector table, often abbreviated to IVT or simply IV, is an array of pointers to functions associated by the CPU to handle specific exceptions, such as faults, system service requests from the application, and interrupt requests from peripherals. The IVT is usually located at the beginning of the binary image and thus is stored starting from the lowest address in the flash memory.

An interrupt request from a hardware component or peripheral will force the CPU to abruptly suspend the execution and execute the function at the associated position in the vector. For this reason, these functions are called interrupt service routines (or simply ISRs). Runtime exceptions and faults can be handled in the same way as hardware interrupts, so special service routines are associated with internal CPU triggers through the same table.

The order of the ISRs enumerated in the vector, and their exact positions depend on the CPU architecture, the microcontroller...

Memory layout

The linker script, as we already know, contains the instructions for the linker on how to assemble the components of an embedded system. More specifically, it describes the sections mapped in memory and how they are deployed into the flash and the RAM of the target, as in the example provided in Chapter 2, Work Environment and Workflow Optimization.

In most embedded devices, and in particular our reference platform, the .text output section in the linker script, which contains all the executable code, should also include the special input section dedicated to storing the IV at the very beginning of the executable image.

We integrate the linker script by adding the .isr_vector section at the beginning of the .text output section before the rest of the code:

.text :
{
  *(.isr_vector)
  *(.text*)
  *(.rodata*)
} > FLASH

Defining a read-only area in flash, which is dedicated to the vector table, is the only strict requirement...

Building and running the boot code

The example provided here is one of the simplest executable images that can be run on the target. To assemble, compile, and link everything together, we can use a simple makefile that automates all the steps and allows us to focus on our software life cycle.

When the image is ready, we can transfer it to the real target or alternatively, run it using an emulator.

The makefile

A very basic makefile to build our startup application describes the final target (image.bin) and the intermediate steps required to build it. Makefile syntax is, in general, very vast, and covering all the functions provided by Make is outside the scope of this book. However, the few concepts explained here should be sufficient to get up and running on automating the build process.

Defining the targets for our makefile, in this case, is quite simple. The startup.c source file, containing the IV, some exception handlers, and the main and the global variables we used...

Multiple boot stages

Booting a target through a bootloader is useful in several cases. In a real-life scenario, being able to update the running software on devices in a remote location means that developers are able to fix bugs and introduce new features after the first version of the embedded system has been deployed.

This represents a huge advantage for maintenance when a bug is discovered in the field, or when the software has to be re-engineered to adapt to changes in requirements. Bootloaders may implement automatic remote upgrades and other useful features, such as the following:

  • Loading of the application image from an external storage
  • Verification of the integrity of the application image before boot
  • Failover mechanisms in case of a corrupted application

Multiple bootloaders can be chained to perform a multiple-stage boot sequence. This allows you to have separate software images for the multiple boot stages, which can be uploaded to the flash independently...

Summary

Understanding the boot procedure is a key step toward the development of an embedded system. We have seen how to boot straight into the bare-metal application, and we have examined the structures involved in a multi-stage system boot, such as separate linker scripts with different entry points, the relocation of IVs via CPU registers, and shared code sections across stages.

In the next chapter, we will explore mechanisms and approaches for memory management that represent the most important factor to take into account while developing safe and reliable embedded systems.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Embedded Systems Architecture - Second Edition
Published in: Jan 2023Publisher: PacktISBN-13: 9781803239545
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.
undefined
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 $15.99/month. Cancel anytime

Author (1)

author image
Daniele Lacamera

Daniele Lacamera is a software technologist and researcher with vast experience in software design and development on embedded systems for different industries, currently working as freelance software developer and trainer. He is a worldwide expert in TCP/IP and transport protocol design and optimization, with more than 20 academic publications on the topic. He supports free software by contributing to several projects, including the Linux kernel, and his involvement within a number of communities and organizations that promote the use of free and open source software in the IoT.
Read more about Daniele Lacamera