Example architecture ¶
This section focuses on the major concepts of the example architecture. It is not exhaustive. It is a quick way to spot the major architecture points that are of interest to port and adapt the example code.
It complements the information available in How to read an example.
Layered architecture ¶
Each example application is separated into units, with minimal overlap between the functions of the individual units. This separation of concerns is achieved using modularization, encapsulation, and by arranging the software in layers, as depicted below.
Block diagram of the software layers of the example. ¶
The hardware elements are:
The device
The board specific elements.
These elements are the ones that change and require the porting of the software layers.
The services layer contains the hardware abstraction layer (HAL) and other STM32Cube components:
Drivers
The HAL drivers are series-specific. Select the right HAL for the target board.
The part drivers are series agnostic. The same part drivers are used across all STM32 series.
Middleware is series agnostic: the same set of modules is used across all STM32 series.
Utilities: the utilities are series agnostic. The same utilities are used across all STM32 series.
The layered architecture of the example application is designed to separate the different concerns of the example code clearly:
The infrastructure code is located in the
main.cfile. This code is the same for all examples.- The functional code is located in the
example.cfile. This code is: specific to the example
hardware-agnostic
toolchain-agnostic
- The functional code is located in the
- The configuration code is located in the
[board_name]/folder. This code is specific to: the STM32 series
the toolchain.
- The configuration code is located in the
Detailed layered architecture of the example, down to the file names. ¶
In particular:
Infrastructure: nothing to port at this level.
The system initialization is called from here but implemented in the Application resources layer.
The
mx_system.hfile abstracts the dependencies to configure the system.
Note
This layer gathers all the collateral elements to run the example. It is meant to be replaced by the custom infrastructure code of the target application.
Application use-case: nothing to port at this level.
The
example.cfile implements the use-case code and is hardware-agnostic.The
example.hfile abstracts the dependencies to configure the use-case.
Application resources: this is the layer that needs to be ported.
The
[board_name]/generated/folder contains the configuration code for the STM32 microcontroller and its peripherals.This layer is split in software units, each of them implementing a specific service.
mx_[pppi].cimplements the configuration code for the hardware instance[pppi]of the peripheral.mx_[pppi].hcollects all required dependencies so that this configuration code can run. It includes the HAL drivers in a series agnostic way (stm32hal.h).
The modular organization of this code allows the rework and reuse of each unit independently.
Example dependencies ¶
All example projects handle their dependencies in the same way. This ensures that all example projects are compatible with each other and can be used together. It also defines which elements of an example must be ported and which elements are just reused “as is”.
Typical dependencies ¶
Overview of typical HAL example dependencies
See the detailed dependency tables below for specific information.
The infrastructure code has the following direct dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The STM32 device startup code. |
This code is provided by the DFP library of the STM32 device. |
It provides the vector table, the system startup code, and the linker file. |
Select the proper DFP library for the STM32 device. |
|
The system configuration for this use-case. |
This code is written in the example project and leverages the HAL driver (for instance: RCC and PWR). |
It provides the system clock configuration and the system initialization code. |
The STM32CubeMX2 tool generates this code. |
|
The PRINTF service if it is used. |
This code is provided by the
|
It provides the basic I/O functions for printing serial logs. |
This utility is hardware-agnostic, but it requires a serial interface to be configured. |
|
The LED part driver if it is used. |
This code is provided by the
|
It provides the basic I/O functions to control the LED over a GPIO. |
This part driver is hardware-agnostic, but it requires a GPIO to be configured. |
This code has indirect dependencies when the LED part driver and the PRINTF services are used:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The GPIO peripheral. |
This code is provided by the HAL driver. |
It provides the basic I/O functions to control the GPIO. |
This code is hardware-agnostic, but it requires a GPIO to be configured in the application resource layer. |
|
The USART peripheral if the PRINTF service is used. |
This code is provided by the HAL driver. |
It provides the basic I/O functions to control the USART. |
This code is hardware-agnostic, but it requires a USART to be configured in the application resources layer. |
The application use-case code has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The HAL driver of the peripheral being demonstrated. |
This code is provided by the HAL library. |
It provides the functional APIs which are hardware-agnostic. |
The HAL code implementing the APIs is hardware-specific. The proper HAL library must be selected.
The API calls themselves are hardware-agnostic. No porting required in
|
|
The resource configuration code for the peripheral being demonstrated. |
This code is provided by the example project. |
It configures the STM32 peripherals. |
This code is generated in the application resources layer by the STM32CubeMX2 tool. |
The application resources layer has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The HAL driver of the peripheral being demonstrated. |
This code is provided by the HAL library. |
It provides the initialization and configuration APIs which are hardware-specific. |
The code in
|
|
The HAL system drivers. |
This code is provided by the HAL library. |
It provides system services for the HAL peripheral driver, such as Cortex®, RCC, DMA. |
The proper HAL library must be selected for the STM32 device. |
The infrastructure code has the following direct dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The STM32 device startup code. |
This code is provided by the DFP library of the STM32 device. |
It provides the vector table, the system startup code, and the linker file. |
Select the proper DFP library for the STM32 device. |
|
The system configuration for this use-case. |
This code is written in the example project and leverages the system initialization. |
It provides the system clock configuration and the system initialization code. |
The STM32CubeMX2 tool generates this code. |
The application use-case code has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The device-family-specific LL implementation. |
This code is provided by the example project as
|
It contains device-family-specific use-case code using LL APIs. |
Device-family-specific files must be adapted for each STM32 series. Different implementations may exist for different device families. |
|
The LL driver for the peripheral being demonstrated. |
This code is provided by the HAL library. |
It provides low-level functional APIs with inline functions for direct hardware access. |
The LL drivers are not hardware-agnostic. The proper HAL library must be selected. |
|
The resource configuration code for the peripheral being demonstrated. |
This code is provided by the example project. |
It initializes LL peripheral drivers. |
This code is generated in the application resources layer by the STM32CubeMX2 tool. |
The application resources layer has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The LL drivers files for the STM32 peripheral being demonstrated. |
This code is provided by the HAL library. |
It provides register-level access and configuration functions. |
The proper HAL library must be selected for the STM32 device. LL APIs are more hardware-specific than HAL. |
|
The LL system files for peripheral initialization. |
This code is provided by the HAL library. |
It provides system-level functions for clock configuration, DMA, and other peripheral services. |
Proper HAL library selection is required. |
The infrastructure code has the following direct dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The STM32 device startup code. |
This code is provided by the DFP library of the STM32 device. |
It provides the vector table, the system startup code, and the linker file. |
Select the proper DFP library for the STM32 device. |
|
The system configuration for this use-case. |
This code is written in the example project and leverages the HAL driver. |
It provides the system clock configuration, HAL initialization, and peripheral setup required by the middleware. |
The STM32CubeMX2 tool generates this code. |
|
The RTOS kernel if used for the scheduling. |
This code is provided by the RTOS middleware library (FreeRTOS). |
It provides task/thread scheduling. |
If using RTOS-based middleware, ensure the RTOS is properly configured (heap size, task stack sizes, etc.). |
|
The PRINTF service if it is used. |
This code is provided by the
|
It provides the basic I/O functions for printing debug traces. |
This utility is hardware-agnostic, but it requires a serial interface to be configured. |
|
The LED part driver if it is used. |
This code is provided by the
|
It provides the basic I/O functions to control the LED over a GPIO. |
This part driver is hardware-agnostic, but it requires a GPIO to be configured. |
This code has indirect dependencies when the LED part driver and the PRINTF services are used:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The GPIO peripheral. |
This code is provided by the HAL driver. |
It provides the basic I/O functions to control the GPIO. |
This code is hardware-agnostic, but it requires a GPIO to be configured in the application resource layer. |
|
The USART peripheral if the PRINTF service is used. |
This code is provided by the HAL driver. |
It provides the basic I/O functions to control the USART. |
This code is hardware-agnostic, but it requires a USART to be configured in the application resources layer. |
The application use-case code has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The middleware component being demonstrated. |
This code is provided by the middleware library. |
It provides the functional APIs used by the use-case code. |
Middleware APIs are hardware-agnostic. No porting required in
|
|
The resource configuration for this middleware component. |
This code is provided by the example project. |
It configures the resources used by this middleware component. It can include dependent middleware components and part drivers when required. |
This code is generated in the application resources layer by the STM32CubeMX2 tool. |
The application resources layer has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The HAL drivers for resources used by the middleware. |
This code is provided by the HAL library and the example project. |
It provides the HAL APIs used to initialize and control middleware resources. |
The code in
|
|
The resources binding for part drivers used by the middleware (when applicable). |
This code is provided by the part driver and the example project. |
It binds HAL resources to the part driver interfaces used by this middleware. |
The code in
|
|
The resource configuration for dependent middleware components (when applicable). |
This code is provided by the middleware library and the example project. |
It configures middleware dependencies such as scheduler, storage, or protocol layers. |
Configuration files (for instance
|
The infrastructure code has the following direct dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The STM32 device startup code. |
This code is provided by the DFP library of the STM32 device. |
It provides the vector table, the system startup code, and the linker file. |
Select the proper DFP library for the STM32 device. |
|
The system configuration for this use-case. |
This code is written in the example project and leverages the HAL driver. |
It provides the system clock configuration and the system initialization code. |
The STM32CubeMX2 tool generates this code. |
|
The part driver library (sensor, codec, memory, network, etc.). |
This code is provided by the part driver library. |
It provides object-oriented APIs with instance handles for controlling external components. |
Select the proper part driver library for the specific external component on the target board. |
|
The PRINTF service if it is used. |
This code is provided by the
|
It provides the basic I/O functions for printing debug traces. |
This utility is hardware-agnostic, but it requires a serial interface to be configured. |
|
The LED part driver if it is used. |
This code is provided by the
|
It provides the basic I/O functions to control the LED over a GPIO. |
This part driver is hardware-agnostic, but it requires a GPIO to be configured. |
This code has indirect dependencies when the LED part driver and the PRINTF services are used:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The GPIO peripheral. |
This code is provided by the HAL driver. |
It provides the basic I/O functions to control the GPIO. |
This code is hardware-agnostic, but it requires a GPIO to be configured in the application resource layer. |
|
The USART peripheral if the PRINTF service is used. |
This code is provided by the HAL driver. |
It provides the basic I/O functions to control the USART. |
This code is hardware-agnostic, but it requires a USART to be configured in the application resources layer. |
The application use-case code has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The part driver component being demonstrated. |
This code is provided by the part driver library. |
It provides the functional APIs used by the use-case code. |
Part driver APIs are hardware-agnostic. No porting required in
|
|
The resource configuration for this part driver component. |
This code is provided by the example project. |
It configures the communication and control resources used by this part driver. |
This code must be ported to the target hardware. |
The application resources layer has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The HAL drivers for resources used by the part driver. |
This code is provided by the HAL library. |
It provides the HAL APIs used to initialize and control part driver resources. |
The code in
|
|
The resources binding for the part driver interface. |
This code is provided by the example project as
|
It binds HAL handles and resources to the part driver interface. |
This binding must be present and ported for the target hardware. |
The infrastructure code has the following direct dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The STM32 device startup code. |
This code is provided by the DFP library of the STM32 device. |
It provides the vector table, the system startup code, and the linker file. |
Select the proper DFP library for the STM32 device. |
|
The system configuration for this use-case. |
This code is written in the example project and leverages the HAL driver. |
It provides the system clock configuration and the system initialization code. |
The STM32CubeMX2 tool generates this code. |
|
The utility library (advanced trace, EEPROM emulation, sequencer, etc.). |
This code is provided by the utility library. |
It provides reusable components for tracing, memory management, or task sequencing. |
Select the proper utility library for the desired functionality. |
|
The PRINTF service if it is used. |
This code is provided by the
|
It provides the basic I/O functions for printing debug traces. |
This utility is hardware-agnostic, but it requires a serial interface to be configured. |
|
The LED part driver if it is used. |
This code is provided by the
|
It provides the basic I/O functions to control the LED over a GPIO. |
This part driver is hardware-agnostic, but it requires a GPIO to be configured. |
This code has indirect dependencies when the LED part driver and the PRINTF services are used:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The GPIO peripheral. |
This code is provided by the HAL driver. |
It provides the basic I/O functions to control the GPIO. |
This code is hardware-agnostic, but it requires a GPIO to be configured in the application resource layer. |
|
The USART peripheral if the PRINTF service is used. |
This code is provided by the HAL driver. |
It provides the basic I/O functions to control the USART. |
This code is hardware-agnostic, but it requires a USART to be configured in the application resources layer. |
The application use-case code has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The utility component being demonstrated. |
This code is provided by the utility library. |
It provides the functional APIs used by the use-case code. |
Utility APIs are hardware-agnostic. No porting required in
|
|
The resource configuration for this utility component. |
This code is provided by the example project. |
It configures the resources used by this utility component. It can include part drivers when required. |
This code is generated in the application resources layer by the STM32CubeMX2 tool. |
The application resources layer has the following dependencies:
|
Dependency |
Origin |
Description |
Porting |
|---|---|---|---|
|
The HAL drivers for resources used by the utility. |
This code is provided by the HAL library. |
It provides the HAL APIs used to initialize and control utility resources. |
The code in
|
|
The resources binding for part drivers used by the utility (when applicable). |
This code is provided by the part driver and the example project. |
It binds HAL resources to part driver interfaces used by this utility. |
The code in
|
|
The utility configuration files. |
This code is provided by the utility library and the example project. |
It provides functional configuration options for the demonstrated utility component. |
Utility configuration files must be adapted to the target hardware and use-case. |
Encapsulation concept ¶
The examples are designed to be as simple as possible, so global variables are used to share data between the different layers. Nevertheless, the examples are also designed to be modular and reusable.
The code is divided into layers and each layer can contain several software units. Each unit is composed of two files as listed below:
The
.hfile contains the interface of the unit,and the
.cfile contains the implementation of the unit (for instance the code to configure a peripheral driver).
The dependencies of a unit are also minimized, and handled in the most hardware agnostic way possible.
For example, the HAL library is always included through its
stm32hal.h
file to avoid series dependencies.
This means that when a unit needs porting or reusing, only the
.c
and
.h
files of this unit need to be updated.
The dependencies are clearly identified, as well as what must be ported and what can be reused.
In particular:
mx_hal_def.h: this gives the list of all the HAL drivers used in the example and the configuration code in use.mx_[pppi].c/h: this gives the porting scope of the peripheral instance[pppi].
Besides, the HAL library itself is modular. The components that the example requires are defined in the file
stm32[tn]xx_hal_conf.h, where
[tn]
identifies the STM32 series.
Resources handling ¶
Portability comes at the cost of abstraction between the application logic and the system interfaces.
In a general manner:
The HAL library offers the hardware abstraction.
The exact hardware resources in use must also be abstracted. For example, direct hardware instance identifiers like
USART1are not used inexample.c.
The hardware resources are abstracted thanks to the concept of aliasing . Aliases connect the use-case layer (software-oriented) and the resources configuration layer (hardware-oriented).
The STM32CubeMX2 tool generates the aliases, based on user labels defined in this tool.
The aliases are defined in the
mx_hal_def.h
file.
The same concept of alias exists also for the other libraries like the part drivers, middleware, or utilities.
For instance, the aliases for the part drivers are defined in the
mx_[part_driver].h
file.
Important
Any change in the use-case code (
example.c) must use these aliases when resources are involved.
This ensures that the code is hardware agnostic and can be reused on any STM32 series.