跳过正文
  1. 技术杂项/

Mastering STM32 2nd

·2305 字·11 分钟
目录

Preface
#

This is a lot of time but things changed a lot even for me in these years. A totally different job, full of too many responsibilities, and a daughter came in the middle, and now my free time ranges from the 5:00am to 7:00am, and you can figure out how hard is to work to a book with 900 pages in just two hours a day.
(page: i)

Appreciate your hardworking, so inspiring.

How is the Book Organized
#

Moreover, a custom and secure bootloader is shown, which can upgrade the on-board firmware through the USART peripheral.
(page: vi)

This teaches us how to upgrade the on-board firmware.

Chapter 26 describes a solution to interface Nucleo boards to the Internet by using the W5500 network processor. The chapter shows how-to develop Internet- and web-based applications using STM32 microcontrollers even if they do not provide a native Ethernet peripheral.
(page: vi)

How to develop Internet and web base applications using STM32.

Introduction
#

Introduction to STM32 MCU Portfolio
#

1.1 Introduction to ARM Based Processors
#

When dealing with ARM based processors, a lot of confusion may arise since there are many different ARM architecture revisions (ARMv6, ATMv6-M, ARMv7-M, ARMv7-A, ARMv8-M and so on) and many core architectures, which are in turn based on an ARM architecture revision. For the sake of clarity, for example, a processor based on the Cortex-M4 core is designed on the ARMv7-M architecture.
An ARM architecture is a set of specifications regarding the instruction set, the execution model, the memory organization and layout, the instruction cycles and more, which precisely describes a machine that will implement said architecture. If your compiler is able to generate assembly instructions for that architecture, it is able to generate machine code for all those actual machines (aka, processors) implementing that given architecture.
Cortex-M is a family of physical cores designed to be further integrated with vendor-specific silicon devices to form a finished microcontroller. The way a core works is not only defined by its related ARM architecture (eg. ARMv7-M), but also by the integrated peripherals and hardware capabilities defined by the silicon manufacturer. For example, the Cortex-M4 core architecture is designed to support bit-data access operations in two specific memory regions using a feature called bit-banding, but it is up to the actual implementation to add such feature or not.
(page: 2)

This clarified the relationship between ARM and Cortex-M.

1.1.1 Cortex and Cortex-M Based Processors
#

Cortex microcontrollers are divided into three main subfamilies:

The difference between different ARM Cortex families (Cortex-A, Cortex-M, Cortex-R).

1. 1.1.1.1 Core Registers
#

  1. Like all RISC architectures, Cortex-M processors are load/store machines, which perform operations only on CPU registers except1 for two categories of instructions: load and store, used to transfer data between CPU registers and memory locations.

A metaphor about the essence of CPU.

1.1.1.2 Memory Map
#

ARM defines a standardized memory address space common to all Cortex-M cores, which ensures code portability among different silicon manufacturers. The address space is 4GB wide, and it is organized in several sub-regions with different logical functionalities. Figure 1.3 shows the memory layout of a Cortex-M processor 3.

The next 0.5GB of memory is dedicated to the mapping of peripherals. Every peripheral provided by the MCU (timers, I2C and SPI interfaces, USARTs, and so on) has an alias in this region. It is up to the specific MCU to organize this memory space.

Peripherals are mapped to this section of Memory.

STM32CubeMX Tool
#

Introduction to CubeMX Tool
#

There are many basic but useful informations about how to configure microcontroller using CubeMX.

  • project-name.ioc. This file is the CubeMX main project file, containing all the
    configurations performed in CubeMX.
  • Different meanings when pins was colored.
  • How to find alternative pins.
  • How to set different functions of pin.
  • How to lock a pin.
  • Define custom labels for MCU signal (which will generate a corresponding macro in .h file).
  • Different status of peripheral in Mode panel.

What is the Cube Low-Layer API?

In the recent years, ST answered to strong criticism of the library’s performances by introducing the Cube Low-Layer (shortened LL) set of drivers. As the name suggest, the LL library is born to be very optimized, leaving to the programmer the responsibility to deal with very specific characteristics of the given STM32 series and the given P/N.

This book will not cover topics related to the LL library

If you need to control every single aspect of a given peripheral to reach the most optimized
code, then the LL library is what you need. But, at the first instance, I suggest you start designing the firmware by using the CubeHAL and then moving to the next step, unless you are a very experienced firmware developer.

(page: 103)

Understanding project structure
#

The Figure 4.14 is a good reference in this quick walkthrough.
(page: 105)

A quick walkthrough of the project structure generated by CubeMX.

Introduction to Debugging
#

What is behind a Debug Session
#

Figure 5.1 tries to provide an overview of the debug setup behind the scenes.
(page: 117)

We can know how GDB client, STLINK GDB Server, STLINK and MCU work together in debugging.

I/O Retargeting
#

Often, the usage of breakpoints is not possible while debugging, because this would cause the loss of relevant events. At the same time, to print on a serial console a few messages could help a lot in understanding what’s going wrong with our firmware.
The simplest and effective solution is to redefine the needed system calls (_write(), _read(), _isatty(), _close(), _fstat()) to retarget the STDIN, STDOUT and STDERR standard streams to the Nucleo USART2. This can be easily done in the following way:
(page: 125)

After retargeting I/O like print() function to USART, we can easily print messages.

If you are going to use printf()/scanf() functions to print/read float datatypes on the serial console (but also if you are going to use sprintf() and similar routines), you need to explicitly enable float support in newlib-nano, which is the more compact version of the C runtime library for embedded systems.

If you encountered problems when using printf to print float numbers, just check above.

Diving into HAL
#

GPIO Management
#

STM32 Peripherals Mapping and HAL Handlers
#

Every STM32 peripheral is interconnected to the MCU core by several orders of buses, as shown in Figure 6.1
(page: 130)

How peripherals are connected to MCU by buses, and mapped to address space.

A peripheral is controlled by modifying and reading each register of these mapped regions.
(page: 133)

One of the HAL roles is to abstract from the specific peripheral mapping. This is done by defining several handlers for each peripheral. A handler is nothing more than a C struct, whose references are used to point to real peripheral address.
(page: 134)

GPIOS Configuration
#

Interrupts Management
#

without the help by the hardware it is impossible to have a true preemptive system, which allows switching between several execution contexts without irreparably losing the current execution flow.
(page: 143)

NVIC Controller
#

NVIC is a dedicated hardware unit inside the Cortex-M based microcontrollers that is responsible othe exceptions handling. Figure 7.1 shows the relation between the NVIC unit, the Processor Core and peripherals.
(page: 143)

Here we have to distinguish two types of peripherals: those external to the Cortex M core, but internal to the STM32 MCU (e.g., timers, UARTS, and so on), and those peripherals external to the MCU at all.
(page: 143)

A dedicated programmable controller, named External Interrupt/Event Controller (EXTI), is responsible of the interconnection between the external I/O signals and the NVIC controller.
(page: 143)

- Reset: this exception is raised just after the CPU resets. Its handler is the real entry point of the running firmware. In an STM32 application all starts from this exception.
(page: 144)

It’s interesting to know that firmware was started from a execption.

Enabling Interrupts
#

Figure 7.3: The relation between GPIO, EXTI lines and corresponding ISR in an STM32F4 MCU

Interrupt Lifecycle
#

It’s important to understand interrupt lifecycle, just read this part.

The Figure 7.11 clearly shows the relation between the peripheral IRQ pending state and the ISR pending state. Signal I/O is the external peripheral driving the I/O (e.g., a tactile switch connected to a pin). When the signal level changes, the EXTI line connected to that I/O generates an IRQ and the corresponding pending bit is asserted. As consequence, the NVIC generates the interrupt. When the processor starts servicing the ISR, the ISR pending bit is cleared automatically, but the peripheral IRQ pending bit will be held high until it is cleared by the application code.
(page: 157)

The Figure 7.12 shows another case. Here we force the execution of the ISR setting its pending bit. Since this time the external peripheral is not involved, there is no need to clear the corresponding IRQ pending bit.
(page: 157)

It’s interesting to check how signals changes in interrupt lifecycle.

However, take in mind that to avoid losing important interrupts, it is a good design practice to clear peripherals IRQ pending status bit as their ISR start to be serviced. The processor core does not keep track of multiple interrupts (it does not queue interrupts), so if we clear the peripheral pending bit at the end of an ISR, we may lose important IRQs that fire in the middle.
(page: 158)

Interrupt Priority Levels
#

The complication arises from the fact that the IPR register can be logically subdivided in two parts: a series of bits defining the preemption priority¹³ and a series of bits defining the sub-priority.
(page: 164)

It’s important to know this Priority Group feature.

Mark All Interrupts at Once or a Priority Basis
#

Sometimes we want to be sure that our code is not preempted to allow the execution of interrupts or more privileged code. That is, we want to ensure that our code is thread-safe. Cortex-M based processors allow to temporarily mask the execution of all interrupts and exceptions, without disabling one by one. Two special registers, named PRIMASK and FAULTMASK allow to disable all interrupts and exceptions respectively.
(page: 173)

However, take in mind that, as general rule, interrupt must be masked only for really short time, otherwise you could lose important interrupts. Remember that interrupts are not queued.
(page: 173)

Cortex-M3/4/7/33 cores allow to selectively mask interrupts on a priority basis. The BASEPRI register masks exceptions or interrupts on a priority level.
(page: 174)

Universal Asynchronous Serial Communications
#

Introduction to UARTs and USARTs
#

Here we know the difference between USART(Universal Synchronous Receiver/Transmitter) and UART(Universal Asynchronous Receiver/Transmitter).

UART Initialization
#

The function attribute __weak is a GCC way to declare a symbol (here, a function name)
with a weak scope visibility, which we will be overwritten if another symbol with the same
name with a global scope (that is, without the __weak attribute) is defined elsewhere in the
application (that is, in another relocatable file). The linker will automatically substitute the
call to the function HAL_UART_MspInit() defined inside the HAL if we implement it in our
application code.

This __weak function attribute is important.

UART Communication in Interrupt Mode
#

A more elegant and performing solution is to use a temporary memory area where to store the byte sequences and to let the ISR to execute the transfer. A queue is the best options to handle FIFO events. There are several ways to implement a queue, both using static and dynamic data structure. If we decide to implement a queue with a predefined area of memory, a circular buffer is the data structure suitable for this kind of applications.
(page: 199)

It’s interesting to check this circular buffer queue transmission solution.

DMA Management
#

Introduction to DMA
#

Why the DMA is a so important feature? Every peripheral in an STM32 microcontroller needs to exchange data with the internal Cortex-M core. Some of them translate this data in electrical I/O signals to exchange it to the outside world according to a given communication protocol (this is the case, for example, of UART or SPI interfaces). Others are just designed so that the access to their registers inside the peripheral memory mapped region (from 0x4000 0000 to 0x5FFF FFFF) causes a changing to their state (for example, the GPIOx->ODR register drives the state of all I/Os connected to that port). However, keep in mind that from the CPU point of view this also implies a memory transfer between the MCU core and the peripheral.
The MCU - in theory - could be designed so that every peripheral would have its own storage area (dedicated memories), and it in turn could be tightly coupled with the MCU core to minimize the costs related to memory transfers. This, however, complicates the MCU architecture, requiring a lot of more silicon and more “active components” that consume power. So, the approach used in all embedded microcontrollers is to use some portions of the internal SRAM memory as temporary area storage for different peripherals. It is up to the user to decide how much room to dedicate to these areas.
(page: 206)

Here we get the concept how MCU core exchanges data with peripherals:

  • Communication protocol (URAT, SPI, etc)
  • Memory map

The HAL_UART_Receive() function will access twenty times to the huart2.Instance->DR data register to transfer bytes from the peripheral to the internal memory, plus it will poll the UART RXNE flag to detect when the new data is ready to be transferred. The CPU will be involved during these operations (see Figure 9.1), even if its role is “limited” to move data from the peripheral to the SRAM.
(page: 207)

To receive a data with 20 bytes, the CPU has to transfer data from data register of the peripheral to SRAM 20 times.