嵌入式学习(46)-基于STM32F407Hal库的DMA乒乓缓存机制

一、概述

DMA 乒乓缓存机制主要思路是利用串口的接收空闲中断搭配DMA接收的半传输中断和全传输中断实现。全满中断和半满中断都很好理解,就是串口 DMA 的缓冲区填充了一半和填满时产生的中断。而空闲中断是串口在上一帧数据接收完成之后在一个字节的时间内没有接收到数据时产生的中断,即总线进入了空闲状态。这对于接收大量数据或不定长数据十分方便。

二、应用

如下图所示向这个缓冲区大小为 20 的程序传送一个大小为 25 的 数据包,它会产生三次中断

大体分为三个状态

  1. 进入半满中断处理缓存区的前半段数据;
  2. 进入传输完成中断,处理后半段数据;
  3. 接收停止,处理空闲中断数据。

这种方式可以实现大量数据的短时间处理也不会丢包

cpp 复制代码
    /* Rx DMA配置 */
    __HAL_RCC_DMA1_CLK_ENABLE();// 低优先级
//    __HAL_LINKDMA( &g_rs458_handler, hdmarx, g_dma_usart2_rx_handle);  /* 将DMA与USART1联系起来(发送DMA) */
    g_dma_usart2_rx_handle.Instance = DMA1_Stream5;                    /* 数据流选择 */
    g_dma_usart2_rx_handle.Init.Channel = DMA_CHANNEL_4;                               /* DMA通道选择 */
    g_dma_usart2_rx_handle.Init.Direction = DMA_PERIPH_TO_MEMORY;           /* 外设到存储器 */
    g_dma_usart2_rx_handle.Init.PeriphInc = DMA_PINC_DISABLE;               /* 外设非增量模式 */
    g_dma_usart2_rx_handle.Init.MemInc = DMA_MINC_ENABLE;                   /* 存储器增量模式 */
    g_dma_usart2_rx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;  /* 外设数据长度:8位 */
    g_dma_usart2_rx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;     /* 存储器数据长度:8位 */
    g_dma_usart2_rx_handle.Init.Mode = DMA_CIRCULAR;                          /* 外设流控模式 */
    g_dma_usart2_rx_handle.Init.Priority = DMA_PRIORITY_MEDIUM;             /* 中等优先级 */
    g_dma_usart2_rx_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;            /* 关闭FIFO模式 */
    g_dma_usart2_rx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;    /* FIFO阈值配置 */
    g_dma_usart2_rx_handle.Init.MemBurst = DMA_MBURST_SINGLE;               /* 存储器突发单次传输 */
    g_dma_usart2_rx_handle.Init.PeriphBurst = DMA_PBURST_SINGLE;            /* 外设突发单次传输 */
    //	
	__HAL_LINKDMA( &g_rs458_handler, hdmarx, g_dma_usart2_rx_handle);  /* 将DMA与USART1联系起来(发送DMA) */
	
	
    HAL_DMA_Init( &g_dma_usart2_rx_handle);                         // 将DMA与USART1联系起来(接收DMA)
    HAL_UART_Receive_DMA( &g_rs458_handler, g_rcvDataBuf2, MAX_BUF_SIZE);            // 开启DMA接收
    HAL_DMA_Start( &g_dma_usart2_rx_handle, (uint32_t) &USART2->DR, (uint32_t) &g_rcvDataBuf2, MAX_BUF_SIZE);
	
    HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 3, 0);
    HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);	
	__HAL_DMA_ENABLE_IT( &g_dma_usart2_rx_handle, DMA_IT_TC);
	__HAL_DMA_ENABLE_IT( &g_dma_usart2_rx_handle, DMA_IT_HT);
	

中断处理:

cs 复制代码
    printf("DMA1_Stream5中断:%d\r\n",DMA_Cnt++);

	
    if (__HAL_DMA_GET_FLAG( &g_dma_usart2_rx_handle, DMA_FLAG_HTIF1_5))       
    {
       __HAL_DMA_CLEAR_FLAG( &g_dma_usart2_rx_handle, DMA_FLAG_HTIF1_5);     

       HAL_UART_Transmit_DMA( &Usart6_HMI_handler, g_txDataBuf2, MAX_BUF_SIZE/2);
       printf("清除DMA_FLAG_HTIF1_5\r\n");
    }	
	
	
	
    if (__HAL_DMA_GET_FLAG( &g_dma_usart2_rx_handle, DMA_FLAG_TCIF1_5))       
    {
       __HAL_DMA_CLEAR_FLAG( &g_dma_usart2_rx_handle, DMA_FLAG_TCIF1_5);     

        //			HAL_UART_Transmit_DMA(&USART6_handler, g_rcvDataBuf6, PACKET_DATA_LEN);
//        __HAL_DMA_CLEAR_FLAG( &g_dma_usart6_tx_handle, DMA_FLAG_TCIF3_7);
	   HAL_UART_Transmit_DMA( &Usart6_HMI_handler, &g_txDataBuf2[MAX_BUF_SIZE/2], MAX_BUF_SIZE/2);	
       printf("清除DMA_FLAG_TCIF1_5\r\n");
    }

三测试数据

测试数据是间隔1ms发送2000个数据,设置的缓存大小是2000;测试发送个数据无丢包,且主程序.

四\程序链接

STM32F407基于Hal库的DMA乒乓缓存机制资源-CSDN下载

相关推荐
小弥儿17 分钟前
GitHub今日热榜 | 2026-08-01:硬件安全工具与AI教育并行
人工智能·学习·开源·github
秋雨梧桐叶落莳29 分钟前
计算器仿写总结
学习·macos·ios·objective-c·cocoa
统计学小王子1 小时前
《数学少年-从正负号到几何原本》(第一章:“刻度之上,零为分界“)--1.2 电梯与账单里的相反数字
学习·初中数学·初中数学科普·数学科普
流云鹤1 小时前
03Java学习day(3)
java·学习
万亿少女的梦1681 小时前
基于STM32、RFID与OneNET的开放性实验室电源节点设计
stm32·物联网·onenet·rfid·esp8266
我命由我123452 小时前
棘轮效应极简理解
经验分享·学习·职场和发展·产品运营·求职招聘·职场发展·学习方法
tt5555555555552 小时前
电工证学习笔记(二)
笔记·学习·电力
wc882 小时前
微软EDGE浏览器功能学习
前端·学习·edge
hPw0eKIqD3 小时前
一步一步学习使用FireMonkey动画() 使用动画组件为窗体添加动态效果
学习
殷忆枫3 小时前
基于STM32+OV2640+ESP8266的无线图像采集系统设计与实现
stm32·单片机·嵌入式硬件