【STM32】RTT-Studio中HAL库开发教程五:UART的DMA应用

一、简介

1.关于DMA

   DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU的大量中断负载。否则,CPU需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU对于其他的工作来说就无法使用。
  简单的来说,能控制主存内部读写,这样有利于减轻CPU负担,加快读取速度。
  在没有DMA之前,串口每次发送数据时都要由CPU将源地址上的数据拷贝到串口发送的相关寄存器上;串口每次接收数据时都要由CPU将发送来的数据拷贝到主存上。而加了DMA后,只需要告诉DMA源地址和目标地址,DMA通道就能够自动进行数据的转移,即CPU只需要告诉DMA:串口需要发送的数据在哪里,串口接收到的数据应该存在哪里,运输的工作则交由DMA去做,运输期间CPU就可以去处理别的事情,这就大大提高了CPU的运行效率。


2.DMA使用场景

DMA用在只需要传输数据,不需要处理数据的地方,有三种传输方式:

  • 外设→存储器 (例如:将串口RDR寄存器写入某数据buf)
  • 存储器→外设 (例如:将某数据buf写入串口TDR寄存器)
  • 存储器→存储器(例如:复制某特别大的数据buf)

3.DMA控制结构

Stm32F4最多有:2个DMA控制器,各8个数据流,每个数据流有8个通道(或请求),每个通道有一个仲裁器,用于处理请求的优先级。
在这里插入图片描述


4.IDLE空闲中断

(1)STM32 IDLE 接收空闲中断—接受完一帧数据,触发中断
  在使用串口接受字符串时,可以使用空闲中断(IDLEIE置1,即可使能空闲中断),这样在接收完一个字符串,进入空闲状态时,即将IDLE置1,便会激发一个空闲中断。在中断处理函数,我们可以解析这个字符串。

(2)STM32的IDLE的中断产生条件
  在串口无数据接收的情况下,不会产生,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一但接收的数据断流,没有接收到数据,即产生IDLE中断

(3)STM32 RXNE接收数据中断—接受到一个字节的数据,触发中断
  当串口接收到一个bit的数据时,(读取到一个停止位) 便会触发 RXNE接收数据中断


5.实现方法

利用串口IDLE空闲中断的方式接收一帧数据,方法如下:

  • 选择一个串口,并配置成空闲中断IDLE模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。
  • 初始化完成之后,当外部给单片机发送数据的时候,假设这次接受的数据长度是200个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区数组里面。
  • 当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用__HAL_DMA_GET_COUNTER(&hdma_usart1_rx)。
  • 函数计算出当前DMA接收存储空间剩余字节:本次的数据接受长度=预先定义的接收总字节-接收存储空间剩余字节。

例如:本次串口接受200个字节,HAL_UART_Receive_DMA(&huart1,rx_buffer,200);//打开DMA接收。然后我发送了HelloWord9个字节的数据长度,那么此时 GET_COUNTER函数读出来 接收存储空间剩余字节 就是191个字节,实际接受的字节(9) = 预先定义的接收总字节(200) - __HAL_DMA_GET_COUNTER()(191):9 = 200-191


二、RTT配置

(1)配置串口:主要是配置使用的串口号,以及打开RTT所需要的驱动函数。

/** After configuring corresponding UART or UART DMA, you can use it.
 *
 * STEP 1, define macro define related to the serial port opening based on the serial port number
 *                 such as     #define BSP_USING_UART1
 *
 * STEP 2, according to the corresponding pin of serial port, define the related serial port information macro
 *                 such as     #define BSP_UART1_TX_PIN       "PA9"
 *                             #define BSP_UART1_RX_PIN       "PA10"
 *
 * STEP 3, if you want using SERIAL DMA, you must open it in the RT-Thread Settings.
 *                 RT-Thread Setting -> Components -> Device Drivers -> Serial Device Drivers -> Enable Serial DMA Mode
 *
 * STEP 4, according to serial port number to define serial port tx/rx DMA function in the board.h file
 *                 such as     #define BSP_UART1_RX_USING_DMA
 *
 */

#define BSP_USING_UART1
#define BSP_UART1_TX_PIN       "PA9"
#define BSP_UART1_RX_PIN       "PA10"

#define BSP_USING_UART3
#define BSP_UART3_TX_PIN       "PD8"
#define BSP_UART3_RX_PIN       "PD9"

(2)配置初始化函数:主要是使用CubeMx配置生成串口的初始化代码,并将代码复制到board.c中。

extern DMA_HandleTypeDef hdma_usart3_rx;
extern DMA_HandleTypeDef hdma_usart3_tx;

/**
* @brief USART MSP Initialization
* This function configures the hardware resources used in this example
* @param husart: USART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
   
   
    GPIO_InitTypeDef GPIO_InitStruct = {
   
   0};
    if (huart->Instance == USART3)
    {
   
   
        /* Peripheral clock enable */
        __HAL_RCC_USART3_CLK_ENABLE();
        __HAL_RCC_GPIOD_CLK_ENABLE();

        /**USART3 GPIO Configuration
         PD8     ------> USART3_TX
         PD9     ------> USART3_RX
         */
        GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        /* USART3 DMA Init */
     
### GD32F303 UART 配置及使用教程 #### 1. 数据手册中的串口引脚说明 GD32F303 的串口相关引脚可以通过其数据手册进行查询。具体来说,在文档 `GD32F303xx_Datasheet_Rev2.0.pdf` 中提供了详细的引脚定义以及功能描述[^1]。这些信息对于硬件连接和初始化设置至关重要。 #### 2. USART 配置基础 USART(通用同步/异步收发器)的配置涉及多个参数,包括波特率、字长、停止位、校验模式等。通常情况下,这些参数可以在寄存器层面手动设定或者通过 HAL 自动完成。以下是常见的配置项: - **波特率 (Baud Rate)**:决定通信速度。 - **字长 (Word Length)**:一般为 8 或者 9 位。 - **停止位 (Stop Bits)**:可以选择 1 或 2 停止位。 - **校验模式 (Parity Mode)**:可选无校验、偶校验或奇校验。 #### 3. DMA 技术的应用 为了提高数据传输效率并减少 CPU 占用时间,DMA(直接内存访问)技术被广泛应用于串口通信中。DMA 可以在后台自动处理数据搬运工作,从而让主程序专注于其他任务。有关 DMA 的基础知识已经在参考资料中提及[^2],其中包括如何配置 DMA 控制器来管理 USART 接收缓冲区。 #### 4. RTT Studio 下的 HAL 开发实例 如果采用 Real-Time Thread (RTT) 操作系统及其配套工具链,则可以利用 HAL 简化开发过程。一篇针对 STM32 平台的文章详细介绍了基于 RTTHAL 实现 UART DMA 收发的方法[^3]。尽管该文章主要面向 STM32 微控制器系列,但由于两者架构相似度较高,因此许多概念可以直接迁移至 GD32 系列上。 下面给出一段简单的代码片段用于演示基本操作: ```c #include "gd32f30x.h" void usart_dma_init(void){ // 初始化 GPIO, RCC, NVIC 等外设资源 /* 配置 USART */ usart_deinit(USARTx); usart_baudrate_set(USARTx, BAUD_RATE); // 设置波特率 usart_word_length_set(USARTx, USART_WL_8BIT);// 字符长度 usart_stop_bit_set(USARTx, USART_STB_1BIT); // 停止位数 usart_parity_config(USARTx, USART_PM_NONE); // 校验方式 usart_hardware_flow_rts_config(USARTx, USART_RTS_DISABLE); usart_hardware_flow_cts_config(USARTx, USART_CTS_DISABLE); /* 启用接收中断 */ usart_interrupt_enable(USARTx, USART_INT_RBNE); /* 配置 DMA */ dma_channel_disable(DMAx, DMA_CHy); dma_memory_address_config(DMAx, DMA_CHy, (uint32_t)&buffer[0]); dma_transfer_number_config(DMAx, DMA_CHy, BUFFER_SIZE); dma_circulation_mode_enable(DMAx, DMA_CHy); dma_direction_config(DMAx, DMA_CHy, DMA_MEMORY_TO_PERIPHERAL); dma_priority_level_config(DMAx, DMA_CHy, DMA_PRIORITY_HIGH); dma_channel_enable(DMAx, DMA_CHy); } int main(){ usart_dma_init(); while(1){ // 主循环逻辑 } } ``` 上述代码展示了如何初始化 USART 和关联的 DMA 通道,并设置了必要的回调函数以便于后续的数据处理。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值