Designing High Load UART Communication with STM32

1 Introduction

Direct Memory Access (DMA) is a component used by the CPU to “move” (copy) data from one address space to another without CPU intervention during the data copying process. The CPU is notified once the data copying is complete.

As a result, using DMA can free up CPU resources when copying large amounts of data. Typical DMA data copying processes include:

  • Memory -> Memory, copying between memories

  • Peripheral -> Memory, such as the data reception process from UART, SPI, I2C, etc.

  • Memory -> Peripheral, such as the data transmission process to UART, SPI, I2C, etc.

2 Is DMA Necessary for UART?

UART (Universal Asynchronous Receiver-Transmitter) is a low-speed serial asynchronous communication method suitable for low-speed communication scenarios, typically using a baud rate of less than or equal to 115200 bps.
For communication scenarios with a baud rate less than or equal to 115200 bps and a small amount of data, using DMA is generally unnecessary, or it does not fully utilize the benefits of DMA.
For large quantities of data or when the baud rate increases, DMA must be used to free up CPU resources, as high baud rates can lead to the following issues:
  • For transmission, using polling can block threads and consume a lot of CPU resources to “move” data, wasting CPU.
  • For transmission, using interrupt-based transmission will not block threads, but it will waste a lot of interrupt resources, with the CPU frequently responding to interrupts; at a baud rate of 115200 bps, 11520 bytes are transmitted in 1 second, requiring a response to an interrupt approximately every 69 microseconds. If the baud rate is increased further, more CPU resources will be consumed.
  • For reception, if the traditional interrupt mode is still used, it will also consume a large amount of CPU resources due to frequent interrupts.
Therefore, in high baud rate scenarios, it is very necessary to use DMA for UART.

3 Implementation

Designing High Load UART Communication with STM32
Overall Design Diagram

4 Using DMA with STM32 UART

Regarding using DMA with STM32 UART, there are many examples on development boards and tutorials from various bloggers online. The steps, processes, and configurations are generally similar, and the correctness is usually fine, but these are just basic demo examples, which are fine for the learning process; however, they lack rigor for actual project use, which could lead to data anomalies when the data volume is large.

Testing Platform:

  • STM32F030C8T6
  • UART1/UART2
  • DMA1 Channel2—Channel5
  • ST Standard Library
  • Clock Speed 48MHz (External 12MHz Crystal)
Designing High Load UART Communication with STM32
Insert Image Description Here

5 UART DMA Reception

5.1 Basic Process

Designing High Load UART Communication with STM32
UART Reception Flowchart

5.2 Related Configurations

Key Steps

[1] Initialize UART

[2] Enable UART DMA reception mode and enable UART idle interrupt

[3] Configure DMA parameters, enabling DMA channel buffer half-full (half data transmitted) interrupt and buffer overflow (data transmission completed) interrupt

Why Is It Necessary to Use DMA Channel Buffer Half-Full Interrupt?

Many tutorials and examples for UART DMA mode reception generally use “buffer half-full interrupt” + “DMA transfer complete interrupt” to receive data.

This approach has risks; when DMA completes data transfer, the CPU intervenes to start copying the DMA channel buffer data. If data continues to arrive during this time, DMA will continue to move data to the buffer, potentially overwriting data, as DMA data movement is not controlled by the CPU, even if you have disabled CPU interrupts.

A rigorous approach requires using dual buffers, with CPU and DMA each accessing their own memory alternately, known as “ping-pong buffering.” The processing flow should be as follows:

[1] First, DMA moves data to buffer1, and when done, it notifies the CPU to copy buffer1 data.

[2] Second, DMA moves data to buffer2, which will not conflict with the CPU copying buffer1 data.

[3] Third, when buffer2 data transfer is complete, it notifies the CPU to copy buffer2 data.

[4] After completing the third step, DMA returns to execute the first step, and this process continues.

Designing High Load UART Communication with STM32
Dual Buffer DMA Data Transfer Process

The STM32F0 series DMA does not support dual buffer (depending on the specific model) mechanisms but provides a “half-full interrupt”.

This means that an interrupt signal can be generated when data is moved to half the size of the buffer. Based on this mechanism, we can implement dual buffering by simply allocating a larger buffer space.

[1] First, when DMA completes moving data to the first half of the buffer, it generates a “half-full interrupt,” and the CPU copies the first half of the buffer data.

[2] Second, DMA continues to move data to the second half of the buffer, which will not conflict with the CPU copying the first half of the buffer data.

[3] Third, when the second half of the buffer data transfer is complete, it triggers an “overflow interrupt,” and the CPU copies the second half of the buffer data.

[4] After completing the third step, DMA returns to execute the first step, and this process continues.

Designing High Load UART Communication with STM32
Using Half-Full Interrupt DMA Data Transfer Process

The UART2 DMA mode reception configuration code is as follows, and it is basically consistent with the configuration of other peripherals using DMA; pay attention to the key configurations:

  • For UART reception, set the DMA channel working mode to continuous mode.

  • Enable DMA channel receive buffer half-full interrupt and overflow (transfer complete) interrupt.

  • Before starting the DMA channel, clear the relevant status flags to prevent data corruption during the first transfer.

Designing High Load UART Communication with STM32

DMA Error Interrupt "DMA_IT_TE" is generally used for debugging purposes to check the number of errors occurring with DMA; this interrupt can be disabled in released software.

5.3 Reception Handling

Based on the above description mechanism, there are three interrupt scenarios in which the CPU needs to copy buffer data to FIFO when using DMA for UART data reception:

  • DMA channel buffer overflow (transfer complete) scenario.

  • DMA channel buffer half-full scenario.

  • UART idle interrupt scenario.

The first two scenarios have already been described in previous articles. The UART idle interrupt refers to the interrupt signal generated when the UART detects that no data has arrived for a certain period after data transmission is complete.

5.3.1 Receiving Data Size

The data transfer process is random, and the data size is also variable, with several possible situations:
  • The data size is exactly an integer multiple of the DMA receive buffer size, which is the ideal state.
  • The data size is less than the DMA receive buffer or less than half of the receive buffer; in this case, the UART idle interrupt will be triggered.
Therefore, we need to calculate the current received data size based on <span>"DMA channel buffer size", "DMA channel buffer remaining space size", "last received total data size"</span>.
/* Get the remaining buffer size of the DMA channel for reception */
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

DMA Channel Buffer Overflow Scenario Calculation

Receiving Data Size = DMA Channel Buffer Size - Last Received Total Data Size

DMA channel buffer overflow interrupt handling function:

Designing High Load UART Communication with STM32

DMA Channel Buffer Half-Full Scenario Calculation

Receiving Data Size = DMA Channel Total Received Data Size - Last Received Total Data Size
DMA Channel Total Received Data Size = DMA Channel Buffer Size - DMA Channel Remaining Buffer Size

DMA channel buffer half-full interrupt handling function:

Designing High Load UART Communication with STM32

UART Idle Interrupt Scenario Calculation

The calculation for the received data size in the UART idle interrupt scenario is the same as that for the “DMA channel buffer half-full scenario” calculation.

UART idle interrupt handling function

Note: In addition to copying the data to the UART receive FIFO in the UART idle interrupt handling function, special handling can also be added, such as marking the completion of UART data transmission or processing variable length data.

5.3.2 Receiving Data Offset Address

To copy valid data to the FIFO, we need to know not only the valid data size but also the offset address of the data stored in the DMA receive buffer.

The valid data offset address can be recorded as the total size of the last received data, which can be cleared in the DMA channel buffer full interrupt handling function, as the next data will be stored from the beginning of the buffer.

In the DMA channel buffer overflow interrupt handling function, clear the data offset address:

Designing High Load UART Communication with STM32

5.4 Application Method for Reading UART Data

After the previous processing steps, the UART data has been copied to the receive FIFO, and the application task only needs to retrieve data from the FIFO for processing. The prerequisite is that the processing efficiency must be greater than the DMA data receiving efficiency, otherwise, data loss or overwriting may occur.

6 UART DMA Transmission

6.1 Basic Process

Designing High Load UART Communication with STM32
UART Transmission Flowchart

6.2 Related Configurations

Key Steps

[1] Initialize UART

[2] Enable UART DMA transmission mode

[3] Configure the DMA transmission channel; this step does not need to be set during initialization and should only be configured when there is data to send.

The UART2 DMA mode transmission configuration code is as follows, and it is basically consistent with the configuration of other peripherals using DMA; pay attention to the key configurations:

  • For UART transmission, set the DMA channel working mode to single mode (normal mode), and reconfigure DMA each time data needs to be sent.
  • Enable DMA channel transmission complete interrupt, utilizing this interrupt information to handle some necessary tasks, such as clearing the transmission status and starting the next transmission.
  • Before starting the DMA channel, clear the relevant status flags to prevent data corruption during the first transfer.

6.3 Transmission Handling

The data waiting to be sent is stored in the transmission FIFO, and the transmission handling function needs to loop to check whether there is data in the transmission FIFO. If there is, it copies that data to the DMA transmission buffer and then starts the DMA transfer.

The prerequisite is to wait for the previous DMA transfer to complete, which is indicated by receiving the DMA transfer complete interrupt signal <span>"DMA_IT_TC"</span>.

UART Transmission Handling Function:

Designing High Load UART Communication with STM32

  • Note the transmission status flag; it must first be set to “transmission status” before starting the DMA transfer. If this step is reversed, when the data amount is small, the DMA transfer time is short, and the <span>"DMA_IT_TC"</span> interrupt may execute before the “transmission status flag is set,” leading to a misjudgment that DMA is still processing the transmission status (the transmission flag cannot be cleared).

Note: Regarding the DMA transmission start function, some blog articles describe that it is sufficient to only change the size of the DMA transmission buffer; however, testing has shown that this method works for small data amounts but fails for larger data amounts and does not trigger the DMA transmission complete interrupt. Therefore, the reliable approach is to reconfigure all parameters of the DMA channel every time a DMA transmission is started. This step is merely a register configuration process and will not consume much CPU execution time.

DMA Transfer Complete Interrupt Handling Function:

Designing High Load UART Communication with STM32

The above UART transmission handling function can be called in several situations:

  • Called by the main thread task, provided that the thread cannot be blocked by other tasks, otherwise it will lead to FIFO overflow.

    Designing High Load UART Communication with STM32

  • Called in the timer interrupt.
    Designing High Load UART Communication with STM32
  • Called in the DMA channel transfer complete interrupt.
    Designing High Load UART Communication with STM32

How Much Data to Copy to the DMA Transmission Buffer Each Time:

This question depends on the specific application scenario, with the principle being that as long as the data amount in the transmission FIFO is greater than or equal to the DMA transmission buffer size, the DMA transmission buffer should be filled, and then the DMA transfer should be started to fully utilize the DMA performance.

Therefore, it is necessary to balance the efficiency of each DMA transfer and the real-time nature of the UART data flow, referring to several implementation types:

  • Periodically querying the sending FIFO data to start DMA transmission, maximizing DMA sending efficiency, but potentially reducing the real-time nature of the UART data flow.
  • Real-time querying of sending FIFO data with timeout handling, which is the ideal method.
  • Handling in the DMA transfer complete interrupt to ensure a continuous real-time data flow.

7 UART Devices

7.1 Data Structures

7.2 External Interfaces

8 Complete Source Code

Code Repository:

https://github.com/Prry/stm32f0-uart-dma

Stress Test:

  • At a baud rate of 1.5 Mbps, the serial port assistant sends 1k bytes of data every millisecond, and the STM32F0 receives the data via DMA, then sends it back to the serial port assistant via DMA, with no pressure.
  • At a baud rate of 1.5 Mbps, large file transmission tests can be conducted, saving the received data as a file and comparing it with the source file.
  • High baud rate tests for the serial port require that both the USB to TTL tool and the serial port assistant support it; recommended USB to TTL tools with CP2102 or FT232 chips.
Designing High Load UART Communication with STM32
1.5 Mbps Serial Loopback Stress Test
Original text:
blog.csdn.net/qq_20553613/article/details/108367512
Direct source: 【小麦大叔】



END



【Free download】Multisim simulation 100 examples.rar



Follow the Breadboard Community WeChat account
Reply: Simulation 100
To download for free








































































Leave a Comment