2

Selecting the Right Software

Arm Cortex-M processors can execute a diverse range of software. The term “software” is so broad in the embedded and Internet of Things (IoT) industries due to the widely varying capabilities of Cortex-M processors. Firmware, middleware, libraries, and components all refer to different parts of the software stack that make up an embedded device. Further complicating matters is a lack of naming consistency, with people often referring to the same software part by different terminology. We try to use the most common software vernacular in this book.

This chapter aims to provide an overview of the different types of software commonly used in microcontroller applications, alongside information about when they should be used. Similar to the previous chapter about understanding which hardware is available in the ecosystem, this chapter presents the same context for software. It is not intended to deeply explain how each software component works with examples; instead, the chapters in Part 2, Sharpen Your Skills, will dive deeper into select software components in key areas.

We start by comparing and contrasting bare-metal software and real-time operating systems (RTOSs) as the foundational software for any microcontroller application. Next, we review a variety of time-saving, reusable middleware and software libraries. This software provides access to hardware in a consistent way and is optimized for performance. Software reuse saves time and provides the best performance when creating applications by providing interfaces to control hardware. We also look at machine learning (ML) frameworks for Cortex-M, a rapidly growing application space.

The chapter then explains how to utilize TrustZone for Cortex-M on processors that support this feature, enabling secure software execution. A number of use cases (the same from Chapter 1, Selecting the Right Hardware) are also presented that map the available software components to an application so that you can see how they fit together to create a complete microcontroller application.

The chapter ends by surveying software development kits (SDKs) from microcontroller vendors to get up and running with many of these software components quickly and easily.

The following questions will be addressed in this chapter, to provide you with a more complete understanding of Cortex-M software offerings and possibilities:

  • What is bare-metal software?
  • What is an RTOS?
  • What are common middleware and libraries for Cortex-M devices?
  • What options exist to implement safe and secure code?
  • What does a reasonable software stack look like for common use cases?
  • Which SDKs can be used for Cortex-M devices?

The first choice for many microcontroller applications is whether to use an RTOS or use bare-metal software as the foundation of the application. In the following section, we will highlight the distinguishing characteristics of bare-metal software and RTOSs. We will also provide an overview of when it is appropriate to use one over the other.

Overview of bare-metal software

The term bare-metal software refers to code with no operating system (OS) or application programming interface (API). It is written directly onto hardware, thus the name of writing software on the “bare-metal” hardware.

If implementing your application is a straightforward task, then bare-metal software makes sense and is a good place to start developing any application. Bare-metal tasks are either polled or triggered by interrupts. More complex scheduling functionality is enabled through an OS. While OSs can be overly complex for simple applications, they introduce a necessary abstraction and management layer needed for most applications. Increasingly, Cortex-M devices perform many tasks (reading sensors, processing sensor data, transmitting data, and more) that can be managed easier by an OS.

Note that you can add functionality to your bare-metal system through middleware stacks—which will be covered later in this chapter—but implementing middleware is typically easier with an OS.

In general, if your application is simple and there are not a lot of tasks, bare-metal software is a good option.

Overview of RTOSs

RTOSs were created as embedded devices matured to simplify software development—like OS-based software—while retaining the reliability and deterministic behavior of bare-metal software. The more sophisticated microcontroller-based products with their variety of peripherals benefit from the multitasking, deterministic behavior and services of an RTOS. RTOSs come with a scheduler that makes it easier to manage a large variety of tasks. The main difference between an OS and an RTOS is that an RTOS responds to external events in deterministic and minimal time—hence the name real time. Middleware stacks are often available with RTOSs and can be easily integrated.

There is a wide variety of RTOSs available in the ecosystem for Arm Cortex-M-based devices. Some of these are available for free and are open sourced, while others are available at cost for commercial use and often packaged with an integrated development environment (IDE) from the vendor. We have listed some of the most popular ones here, along with a link to where you can get them, in alphabetical order:

Step 1 when selecting a software stack for Cortex-M-based devices is to decide between a base of bare metal or an RTOS. Step 2 is to understand your functional requirements, such as connectivity or heavy digital signal processing (DSP), and select software libraries that simplify their implementation. The next section will cover the middleware and libraries to keep in mind in common situations.

Exploring middleware and libraries

To keep up with modern embedded design requirements, microcontrollers offer a wide range of peripherals such as a Universal Serial Bus (USB), Wi-Fi, Bluetooth Low Energy (BLE), and so on.

Developing software from scratch that utilizes these peripherals efficiently presents developers with real challenges. Easy-to-use middleware helps bridge this gap to properly leverage modern communication and interface peripherals.

Most of the RTOSs we listed in the earlier section offer a rich set of modules and middleware to help software developers easily integrate support for these peripherals in their Cortex-M devices. The following diagram shows some examples of common middleware components:

Figure 2.1 – Middleware landscape

Figure 2.1 – Middleware landscape

As there are so many different types of peripherals that do the same thing (Wi-Fi chips, BLE peripherals, and so on), it can feel like an overwhelming task to find the specific middleware or libraries that accomplish what you need. However, there is a common standard used by the Cortex-M ecosystem that substantially simplifies this process.

CMSIS

The Cortex Microcontroller Software Interface Standard (CMSIS) is a collection of API definitions, libraries, utilities, and methods that simplify your software development on Cortex-M devices. It is open sourced and available here for download: https://github.com/ARM-software/CMSIS_5.

There are several components in the CMSIS library and several resources available online that provide details on each of these components. This blog on the Arm community site provides a great overview of CMSIS: https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/which-cmsis-components-should-i-care-about. While we are not going into the details of each software component in CMSIS, we will highlight some components that are widely used and their purposes.

System startup, processor core access, and peripheral definitions are essential for every embedded application. With bare-metal programming, you need to provide startup files to perform hardware initialization, C library initialization, and set up memory stack and heap spaces.

CMSIS-CORE, a component of CMSIS, provides the startup code, system configuration files, and device header files for all Cortex-M processors.

Startup code performs several things before entering the main user application, such as the following:

  • Sets up reset and exception vector handlers
  • Sets up and enables memory protection unit (MPU) (when available in the processor)
  • Prioritizes and enables interrupts

System configuration performs the processor clock setup, and device header files provide access to the processor core and all its peripherals including the nested vector interrupt controller (NVIC) and System Tick Timer or System Time Tick (SysTick), which configures periodic timer interrupts.

Now that we have an understanding of what CMSIS is, let us take a look at some of the specialized components in CMSIS that can be leveraged for developing DSP algorithms and ML applications.

DSP libraries

Applications that rely on DSP are generally time-critical and usually involve complex mathematical operations. Because of this, developing real-time DSP systems is far from trivial.

CMSIS-DSP, another component of CMSIS, is a software library of more than 60 algorithms for common signal-processing functions that can be downloaded here: https://github.com/ARM-software/CMSIS_5/tree/develop/CMSIS/DSP.

This collection of common signal-processing functions is categorized into the following functions:

  • Basic math functions: Mainly consists of optimized functions that streamline vector processing. Vector addition, subtraction, multiplication, and dot product are among the simple math operations. Vector negate, scale, shift, and absolute value allow other types of common data manipulations.
  • Fast math functions: Offers quick approximations of common math functions that are more involved such as sine, cosine, square root, and division.
  • Complex math functions: Provides easy manipulation of numbers with imaginary components with functions such as complex dot product, magnitude, and multiplication.
  • Filtering functions: These are explained in more detail here:
    • Image processing—Basic filters such as convolution and correlation are included that enable simple signal manipulations such as sharpening or blurring.
    • Audio processing—Several biquadratic functions are included that are commonly used to offer audio filters such as low-pass, high-pass, band-pass, low-shelf, high-shelf, peaking/bell, and all-pass.
    • Video processing—Several finite impulse response (FIR) filters are included that are fundamental operations for video (or image) processing. Enables contrast improvement, denoising, sharpening, feature enhancement, and more.
  • Matrix functions: Similar to the basic math functions but specifically for matrix operations. Matrix addition, subtraction, transposing, inverse, initialization, and more make working with matrices simple.
  • Motor control functions: Functions that enable control of physical motors such as for robotics. The proportional integral derivative (PID) motor control function is the most commonly used in this category.
  • Transform functions: Offers optimized real and complex fast Fourier transform (FFT) functions, which are exceptionally common in audio processing applications.
  • Statistical functions: Provides basic functions common to statistical analysis, such as finding the maximum, minimum, mean, root mean square (RMS), standard deviation, and variance from a number set.
  • Support functions: Help in manipulating stored values into the required formats to simplify computation. They enable converting 8-, 16-, and 32-bit numbers (integer or vector) into smaller or larger sizes. Vector fill, copy, and sorting functions enable streamlined vector usage as well.
  • Interpolation functions: Can be used in various DSP applications. Bilinear interpolation is a basic and effective technique for resampling in computer vision and image processing. Other techniques such as linear interpolation upsample an audio signal to a higher sampling rate.
  • Support Vector Machine (SVM) functions: These are a subset of ML algorithms that use supervised learning (SL), commonly used for classification or outlier detection. In this library, the SVM classification is limited to two classes, and examples are provided to simplify implementation.
  • Bayes classification functions: Enable classification and probabilistic estimation. They are based on the powerful naïve Bayes classifiers. Although fairly simple, this technique can work well in complex real-world situations when features are independent of one another.
  • Distance functions: Provide distances between numbers (or arrays of Boolean values) for clustering algorithms. These are key in quickly classifying data or observations into groups.
  • Quaternion functions: These are hypercomplex, multi-dimensional numbers that have more than one complex plane. Among other benefits, they offer a helpful notation to represent spatial orientations in three-dimensional (3D) space. These functions enable common mathematical manipulations to these types of numbers, such as conjugation, normalization, and finding the inverse or product between numbers.

The CMSIS-DSP library of functions is designed to provide the essential blocks needed to create effective DSP algorithms on Cortex-M devices.

ML frameworks and libraries

CMSIS-NN, another component of CMSIS, provides optimized low-level neural network (NN) functions for Arm Cortex-M-based central processing units (CPUs). It optimizes the performance and memory footprint of NNs by offering tailored NN network kernels specifically designed for Arm Cortex-M processors and provides a significant uplift in performance and efficiency for NN functions. You can download the library from here: https://github.com/ARM-software/CMSIS_5/tree/develop/CMSIS/NN.

The library is categorically divided into a number of functions, briefly described next. Note that these descriptions assume a base level of ML knowledge. We will dive into ML in Chapter 6, Leveraging Machine Learning. This list is intended as a quick overview of the CMSIS-NN offerings:

  • Convolution functions: These functions are used to implement customized convolution layers in convolutional NNs (CNNs). Convolution results in the scalar product between an input signal and a set of weights—the single-number result is then fed into an activation function. The CMSIS-NN library supports convolutions of various sizes and requirements.
  • Activation functions: Activation functions simply specify how an input is transformed into an output. This library contains several of the most common types of activation functions used in NNs: sigmoid, tanh, and Rectified Linear Unit (ReLU).
  • Fully connected layer functions: These are used to implement fully connected layers in CNNs. They provide the same mathematical result as a convolution but mandate each input node is fully connected with each output node in the layer.
  • Singular value decomposition filter (SVDF) layer functions: A SVDF is intended to expose the underlying meaning of a matrix, represented as a linear approximation, to simplify computations.
  • Pooling functions: Another key part of a CNN, pooling takes a large set (or pool) of data and summarizes it. These functions are used to identify the presence of features in a particular area and support both max and average pooling.
  • Softmax functions: These functions are why ML probabilistic results add up to 1 (or 100%). Without these, the probability of an input belonging to certain classes could be 90% for one, 45% for another, and 20% for a third, providing useless results.
  • Basic math functions: These offer simple, element-wide add and multiplication.

The CMSIS-NN library is tightly integrated with the TensorFlow Lite for Microcontrollers ML framework to provide optimized versions of TensorFlow Lite kernels. TensorFlow Lite for Microcontrollers is a subset of the TensorFlow ML framework from Google that is designed to run ML models on microcontrollers and constrained embedded devices with just a few kilobytes (KB) of memory. It is an Arm-supported frontend to deploy ML applications on Arm Cortex-M and Ethos-U-based devices. It is open sourced, has been tested extensively with the different Cortex-M processors, and is available for download here: https://github.com/tensorflow/tflite-micro. It can run bare-metal and doesn’t require OS support on the target Cortex-M device.

We have reviewed several different CMSIS libraries that help with software startup, configuring/utilizing hardware properly, and optimizing DSP/ML workloads. The next section zooms in on two areas that warrant special consideration: security and safety software requirements.

Understanding secure software

While Arm Cortex-M processors come equipped with hardware features that provide fundamental protection for secure software, secure software needs to be written precisely to ensure that the whole system is secure. In this section, we will provide an overview of how software can be architected to benefit from the different hardware security features. We will then introduce Platform Security Architecture (PSA), a key security framework, and Trusted Firmware-M (TF-M), an open source reference implementation of PSA.

Many of the Arm Cortex-M processors have an MPU, which enables developers to configure the memory on their device into different regions with different protection levels. Programmers can leverage the MPU to protect critical processes such as the startup code and RTOS in a privileged partition, and the rest in unprivileged partitions. For example, static random-access memory (SRAM) can be defined as an execute-only memory region to prevent code injection, prohibiting user applications from accessing privileged regions used by the RTOS and thereby corrupting critical tasks. The MPU may also place communication stacks and user code in different partitions to protect the communications stack from the application code.

TrustZone for Cortex-M, which we introduced in the previous chapter, adds another layer of security that enforces hardware isolation between trusted and untrusted code. When you start your development of a project on a Cortex-M device with TrustZone, you will partition your project into a secure and user (non-secure) project. The first step is to identify all code that handles configuration and security such as the startup code, the bootloader, cryptography libraries, and firmware updates, and place them in the secure project. All the rest of the code is then placed in the non-secure project. The goal is to place the minimum amount of code in the secure project and thoroughly analyze this code for security vulnerabilities.

PSA

PSA provides a security framework for IoT devices to enable the right amount of security to be designed for devices. It is not a technology, but rather a process. PSA can be understood as four high-level stages, as outlined here:

  1. Analyze: Understand the threat models for the current use case and define specific security requirements.
  2. Architect: Create a design (hardware and firmware) with security requirements in mind.
  3. Implement: Tie hardware and firmware together through open source firmware references.
  4. Certify: Obtain certification for your product, verifying that security requirements have been met to a certain level.

Trusted Firmware for Cortex-M

TF-M is an open source reference implementation of the PSA framework for Armv8-M and Armv8.1-M architectures (Cortex-M23, Cortex-M33, and Cortex-M55). TF-M implementation is guided by a secure development life cycle workflow, which means it is secure by design. It provides PSA-compliant APIs for developers to use Root-of-Trust (RoT) services from the non-secure world easily. RoT is a source that can always be trusted within a cryptographic system and where security begins.

You can download TF-M from here: https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/.

Implementing secure software in Cortex-M devices is an often-misunderstood topic. We aim to demystify this area in Chapter 7, Enforcing Security.

Implementing safe software

Software development for embedded systems with safety requirements can be challenging. Safety-critical software requires special procedures during design and development. Safety analysis needs to be performed on all the software components in the project, and extensive validation needs to be done to meet the safety standards for your product. Using safety-certified software components in your application can ease your development effort.

A popular set of embedded software components that are qualified for the most safety-critical applications is Arm Functional Safety Run-Time System (FuSa RTS). It applies across the automotive, industrial, and medical industries. The specific components of Arm FuSa RTS are summarized here:

  • FuSa RTX RTOS: Deterministic RTOS that supports complex real-time applications. Enables threads, timers, memory management, and more.
  • FuSa Event Recorder: Provides API function calls that annotate events in code that can be analyzed from memory. Simplifies testing and deployment by being non-intrusive in production code.
  • FuSa CMSIS-Core: Vendor-agnostic software interface allowing access to the processor and device peripherals, in a safety-qualified manner.
  • FuSa C Library: A verified subset of functions from the traditional C library for safety-critical applications.
  • Safety Package: Holistic documentation explaining how to use FuSa RTS in a safety context.

We have now gone over some different software types and libraries addressing various computational needs and product requirements for Cortex-M-based devices.

In the next section, we will look at some use cases for microcontroller applications and explain how to select the software type and libraries for these use cases to create a complete application.

Example software stacks for common use cases

As with selecting hardware, choosing the right software stack depends greatly on your final use case. The functionality required for a low-power IoT sensor and an always-on facial recognition camera is quite different. In Chapter 1, Selecting the Right Hardware, we described six discrete areas to help select the right Cortex-M processor. In contrast, selecting the right software for a given use case, given the number of overlapping options available, has more room to include personal preference.

In this section, we will take the same use cases from the previous chapter and talk through their software requirements. We will then distill the requirements into reasonable selections for each part of the software stack. Note that there are many ways to build a working software stack for these use cases, and other options may be more optimal given previous experience, cost constraints, personal preference, development time versus quality trade-offs, and more.

Medical wearable

As a recap of the previous chapter, this product is a wrist-worn device intended to continuously monitor heart activity. It requires heightened security, low-power draw to prolong battery life, and processing power to quickly process data. The Cortex-M33 was selected as the processor to build around.

While expanding on these requirements to help select the right software stack, it is also critical to transmit the device data to a phone or hub for viewing via Bluetooth. The heart-rate monitoring functionality is critical to the device’s functionality, meaning that the sensor must be deterministically monitored for data. Lastly, due to the private nature of the data, secure storage of the data is required.

Considering all these requirements, developing a bare-metal application with CMSIS is a good option for the software stack. CMSIS has middleware supporting Bluetooth drivers, can leverage TF-M to ensure secure data storage for medical information, and has device drivers to integrate sensors with ease.

Industrial flow sensor

This device measures liquids and gasses in an industrial setting, focusing on reliability and minimalism. The Cortex-M0+ was selected, being the go-to low-power/smallest-area processor.

The primary requirements for this use case are driven from the hardware perspective—highly accurate readings require highly accurate sensors. As this device is intended to be used in a closed-loop industrial setting, connected via local USB wires and not over the internet, security is not a top priority. The low-power requirement is for ease of maintenance, with minimal requirements to keep the power ultra-low via sleep states expected from the software stack. The key factor affecting the software stack is the low-cost nature of the device. Minimizing component costs leads to small memory footprints, meaning the software stack cannot afford code bloat.

In this situation, a bare-metal software stack with very few add-ons is appropriate. Examples can be taken from CMSIS to ease the software boot process, but keeping things bare-metal is ideal to minimize the code footprint to minimize the memory needed in hardware, driving down costs as much as possible.

IoT sensor

This use case is quite general and addresses the explosion of IoT sensors emerging across the world. To create a more concrete example, we can pick a stereotypical IoT sensor use case to select a software stack for. Let’s say we are creating a network of 1,000 IoT devices intended to gather data across a city—humidity, temperature, noise levels, people in the area via heat signatures, and more. Each device collects a data sample every 5 seconds and transmits data back to a centralized database through Wi-Fi (readily available in the city).

To reduce complexity and data transmission costs, the devices perform computation at the edge to get a specific data point and transmit it to the database. To communicate how many people are in the area—for example—instead of sending out the raw heat-signature map every 5 seconds, only the number of people detected is sent. This requires more robust DSP capabilities. The Cortex-M7 is ideal for this use case and has enough security features to make it fit for purpose.

Taking all these requirements into consideration, selecting an RTOS for ease of development and peripheral/sensor integration makes sense. Any of the RTOSs listed previously would work well. Cloud connection and over-the-air firmware updates are necessary, and Keil RTX5 is an excellent option. Leveraging the CMSIS-DSP library will also help expedite development.

ML

This category is quite broad and hard to talk about as a monolith. Narrowing it down into distinct ML use cases will allow us to suggest sensible software stacks serving specific situations. As identified in Chapter 1, Selecting the Right Hardware, these distinct categories are vibration, voice, and vision.

Vibration

This includes motion detection and gesture detection. Let’s consider anomaly detection in a car. The device constantly senses vibrations via an accelerometer, processes the raw data points into the ML features, and performs inference on the device to see whether the vibration is detected as an anomaly.

Translating to requirements: DSP is needed to preprocess the data into features the ML model expects, and a relatively small ML model must be run on the device directly. Assume the processor selected is a Cortex-M4, balancing DSP performance with low area for a small device.

Creating a simple bare-metal application makes sense, especially if there are not many other peripherals or connectivity requirements in the system. Leveraging CMSIS-DSP for feature extraction and tflite-micro as the ML framework is a good approach.

Voice

This includes keyword spotting and speech recognition. A common use case is a voice-enabled assistant, becoming more and more common around the home. The flow and requirements here are largely the same as the vibration use case, just replacing an accelerometer with a microphone and likely cloud connectivity. These changes require significantly more DSP and ML computation, meaning a more powerful processor such as the Cortex-M7 or Cortex-M55.

On the software side, this translates to leveraging an RTOS to ease the integration of DSP, cloud connectivity, ML, and possibly other peripherals. FreeRTOS excels in these voice use cases, containing support for connecting to the AWS cloud and the Alexa Voice Service (AVS) for voice control.

Vision

Includes image classification and object detection/recognition. A well-known example is a video doorbell, which can recognize faces and unlock the door for select individuals. These use cases are the most ML-intensive at the edge and require huge amounts of processing power to run facial recognition inferences.

This type of application is almost the sum of all the previous requirements put together: DSP power, ML processing, enhanced security, cloud connection via Wi-Fi, over-the-air updates, and more. At this level, an RTOS is required and should be selected based on the specific range of features you need to be successful.

Now that we have mapped the different software types and libraries you can leverage for development on your Cortex-M device to your use case, we will introduce SDKs—what they are, their main features, and how you can greatly simplify your software development by using them.

Introducing SDKs for Cortex-M

SDKs are collections of tools and software needed to get started quickly with a particular Cortex-M development board. SDKs come from a variety of sources including microcontroller vendors, board vendors, commercial or open source software (OSS) providers, cloud service providers (CSPs), and even CPU suppliers such as Arm.

The SDK concept is not exclusive to microcontroller development and can take many forms. The most common form of an SDK is a collection of software in the form of libraries, source code, and APIs. SDKs often include examples to help developers get started or learn how to use a service or hardware feature.

SDKs may or may not include software development tools. The core tools of a microcontroller software developer are the text editor, compiler, and debugger. These tools enable developers to navigate the inner loop of code, compile, run, and debug. Engineers have individual preferences for how they would like to mix a bundle of tools and useful software. Some prefer to have everything all in one place as a single bundle, while others prefer to separate tools from embedded software and select exactly what they want. Some SDKs are even configurable for a user to select the tools and software they want to bundle, and then a custom installer is created for download and installation.

The next few pages will discuss what makes SDKs useful, what they contain, and how to select the right one for you.

Purpose of an SDK

A common demonstration of an SDK is Blinky, a program to turn on a light-emitting diode (LED). This is the hello world of embedded programming. Without an SDK and no example software, it would take some effort to initialize the system, configure the hardware, and get to a place where everything is ready to turn on an LED.

With an SDK providing the underlying code to control the LED, it could be as simple as an infinite loop turning the LED on and off, as demonstrated by the following code snippet:

    unsigned int led_state = 1;
    for (;;) {
        if (timeout_delay_is_elapsed()) {
            led_state ^= 1;
            set_led_port(led_state);
        }
    }

With an SDK, we don’t need to know anything about setting up the CPU, initializing the hardware, or even the system address for the LED. We don’t even have to know how the LED is connected to the system.

Language bindings

The traditional embedded programming languages of C and assembly are now joined by new languages such as Python and Rust.

SDKs often provide easy-to-use packages for Python. With a Python microcontroller SDK, Blinky is even easier. Python SDKs for microcontrollers have become popular for education as they teach a popular and easy-to-use programming language joined with the hardware details of a microcontroller board. A simple example for blinking an LED in Python is provided here:

while True:
    led.value = True
    time.sleep(0.5)
    led.value = False
    time.sleep(0.5)

Middleware

SDKs typically provide a collection of middleware to make programming easier. As covered earlier in the chapter, middleware makes it easy to implement protocols such as Ethernet, USB, filesystems, storage, and graphical user interfaces (GUIs). Middleware is generally the software that is in the middle, between the hardware drivers and the application code.

In an embedded system with an RTOS or bare-metal operating environment, middleware covers many of the things we would take for granted with an OS such as Linux, and realize that these standards are generally the same for every system: not useful to recreate but important and needed. Middleware is a common component in SDKs.

Cloud connectors

IoT devices typically send data to a cloud service for analysis. Sometimes called IoT connectors or cloud connectors, these libraries are used to send data to Amazon Web Services (AWS) IoT services, to the Microsoft Azure IoT cloud, or to another cloud service. This relieves the developer from having to learn the details of sending the data so that they can just focus on what to send instead of how to send it. CSPs typically provide an SDK with libraries to connect an application directly to the cloud.

Security and encryption

SDKs may also include software for Secure Sockets Layer (SSL) and Transport Layer Security (TLS) for client-server networking applications. Using software from an SDK to create an encrypted connection between a microcontroller and a server is critical. SDKs provide the benefit of a well-tested library, which has been verified to work on a particular microcontroller and provide the best performance utilizing the hardware resources available.

An example of this is Mbed TLS, which is included in many common microcontroller SDKs. You can read more about Mbed TLS here: https://www.trustedfirmware.org/projects/mbed-tls/.

Development tools

SDKs often contain a collection of tools such as a compiler and a debugger to work with the target boards. Development tools can be command-line tools or include user interfaces (UIs). We will cover development tools in more detail in Chapter 3, Selecting the Right Tools, but there are a variety of options available for Cortex-M tools ranging from open source to commercial tools, each with different support options.

Each SDK makes choices about which tools to provide directly or indirectly. An SDK may bundle some tools directly into the installation to make it easy for users to start with a single download and install. SDKs may also choose to support particular tools, such as a compiler, by making sure the compiler works with the source code and libraries and providing project and build files, but users are directed to download and install the compiler from somewhere else.

Build systems

The build system is a key aspect of an embedded software project. For projects using C/C++ and assembly, it determines how the software will be compiled into an executable. There are numerous ways to build software, with so many options available that it may rival the number of programming languages available!

Build systems can be driven from a UI and have the concept of project files, which can be created from a UI, and easy-to-use buttons on the UI invoke build and clean operations. An example of this is the Keil µVision IDE, offering a simple interface from which to build projects. We will use this flow in several examples throughout the book.

Some build systems use text files, the command line, and scripts for complete automation. The most basic way to create a build system is using make or cmake or even just commands in a text file to run.

Some build systems are flexible and can be invoked using either the UI or the command line to provide an easy interface to get the initial project working and later the most automation to build the software.

Lower-level considerations

There can be many similarities and differences between SDKs, making it hard to narrow in on the right one for your project. The next few subsections briefly touch on specific areas to keep in mind when selecting an SDK to use.

Software examples

One of the most helpful components that an SDK can offer is software examples. Useful examples can be one of the most important time-saving features of an SDK. Make sure to use them as intended—as examples. Software examples often demonstrate the concept of how to do something but leave the details of testing and performance optimization to the developer. Don’t assume too much about examples and take them as perfect; they are largely only meant to demonstrate a concept or serve as a quick start.

Software reuse

One of the challenges to consider when reviewing project options is how to reuse existing software in an SDK. Many of the RTOS and middleware components covered in this chapter may be immediately available in an SDK, but not always. It’s important to consider how to integrate libraries and middleware that are not included in an SDK. While all libraries and middleware provide instructions to build it with a compiler, the details may be different from the build system and compiler used in your project. It’s important to investigate these trade-offs when making SDK decisions.

For software reuse, check the following items:

  • List of Cortex-M processors supported
  • Compilers supported
  • Build system used and complexity of migrating to another build system

Sometimes, the best way to analyze these trade-offs is to just get the software and try it out.

IDE

The IDE is a somewhat contentious topic for SDKs: developers have strong preferences for tools, especially for editing. Should it be included or not? The IDE typically merges the editor, compiler, and debugger into a single tool to make things easy and consistent. SDKs often reuse existing components to avoid building them from scratch and to take advantage of environments developers already know. Previously, desktop IDEs such as Eclipse were popular to add to SDKs. Today, cloud IDEs are becoming popular and tools such as Visual Studio Code (VS Code), which can run in the cloud and on the desktop, are popular. We will leverage both desktop IDEs and cloud IDEs through the examples later in this book.

Debugging tools

Another consideration for SDKs is debuggers and hardware debug probes. Probes are used to connect a software debugger to a microcontroller development board. SDKs often include debuggers, which can trigger dependencies on hardware probes. Take a look at the combinations of debuggers, debug probes, and development boards for your project. There are many standards, but the matrix of options can get confusing. We will look at debugging tools in more detail in Chapter 3, Selecting the Right Tools.

Host platform support

In embedded software development, the computer used to code, compile, and run a debugger is called the host or host computer. The Cortex-M microcontroller running the software application is called the target. Unlike laptops or servers, microcontrollers don’t have the compute resources to be both host and target, so these are separated. This division is important for SDK selection as tools used in microcontroller development typically have a limited number of host computers. Practically, this means Windows, Linux, and macOS. Engineers in a development project may have preferences for the host computer they use. More projects are also taking advantage of cloud computing to automate software build and test, so consider the OSs used in the cloud also.

Installing SDKs

SDKs have a variety of installation methods. As microcontroller projects adopt more automation, it’s important to make sure tool and library installations can be easily automated. Automated build systems are moving to virtual machines (VMs) and container images, and making sure SDKs accommodate this automation is important. Watch out for tools that require a graphical installer and especially a click-through end-user license agreement (EULA) to install.

Long-term support

Many SDKs are free to use. Some offer paid support or an active subscription for support. SDK length of support is a secondary factor to review before making selections. IoT devices themselves tend to be used for a long time. Even consumer devices last far longer than mobile phones and laptops, and customers expect software updates and security fixes. Therefore, make sure the SDKs you select match up with the expected life of a product.

Looking at some available SDKs

To give you a glimpse of the wide variety of SDKs available, let’s discuss a few of them. One thing you will pick up quickly is that it is easy to tell how many microcontrollers are available from a vendor by the initial look at the SDK. Vendors who are new to the market, such as the Raspberry Pi 2040, look very different from NXP or ST who have hundreds of different devices and are trying to support them with a common set of tools and software.

Raspberry Pi

Let’s start with the Raspberry Pi Pico. The Pico, released in January 2021, is a new microcontroller at the time of writing this book. One of the unique things about the Pico SDK is that it was designed to be run on a Raspberry Pi running Linux as opposed to a Windows personal computer. All of the content of the SDK is found on GitHub. There is the SDK itself and examples. The SDK relies on numerous open source tools for compilation and debugging. The build system is cmake. Execute the following commands to download the official Pico setup script and run the installation process:

$ mkdir ~/raspberry-pi-pico

$ cd ~/raspberry-pi-pico

$ wget https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh

$ chmod +x pico_setup.sh

$ ./pico_setup.sh

The Raspberry Pi Pico SDK can run on Windows and macOS, but it works great on Linux.

NXP

NXP provides the MCUXpresso SDK to simplify your software development on NXP boards with Arm Cortex-M CPUs in them. It is free and available for download directly from the NXP website. When you download the SDK, you are prompted for the target board you plan to use it for. You can customize your SDK download package to include the components you will need for that board. The components include libraries such as CMSIS-DSP, middleware, and RTOS support. For example, if you download the SDK for use with the LPC55S69-EVK board, which has an Arm Cortex-M33 CPU, you might want to add support for the TF-M library. You can also select the host OS and compiler toolchain you would like to use. Note that Windows, Linux, and Mac are all supported.

ST

ST also provides a whole suite of software development tools for its Arm Cortex-M-based microcontrollers. These tools are referred to as STM32Cube tools and provide a range of support for their portfolio of boards. This includes a graphical tool for generating initialization code for your device, as well as project management and debug features. As with other SDKs, middleware components for peripherals and connectivity modules on the ST boards are also provided. You can even download the STM32Cube package for the specific microcontroller unit (MCU) family you are targeting. The tailored packages contain several out-of-the-box examples that are quite useful to get started on your board right away.

These tools were previously supported only on Windows but recently have added support for Linux as well.

Summary

In this chapter, we first looked at the two main software types ported to Cortex-M microcontrollers—bare-metal and RTOS. We examined several different software libraries specialized for DSP, ML, and security applications.

We then walked through a few different use cases for microcontroller applications and highlighted the software stack most applicable for that use case. Finally, we introduced what SDKs are, their main features, and how they can help accelerate your Cortex-M software development.

To sum up, we have looked at a wide variety of software available for Cortex-M microcontroller applications. Thankfully, there is a large ecosystem of both commercial software and OSS available to use, which makes development easier and helps to create performance-optimized applications.

Next up is Chapter 3, Selecting the Right Tools, the last chapter of this part, where we will navigate through the assortment of tools and environments that enable Cortex-M software development while understanding the benefits of different options.

Further reading

For more information, refer to the following resources:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.105.239