嵌入式学习(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下载

相关推荐
笨鸟先飞的橘猫1 小时前
skynet——网络模块学习
网络·学习·skynet
xd1855785551 小时前
鸿蒙PC平台Flutter魔术教学应用开发实践:打造跨端沉浸式魔术学习体验
人工智能·学习·flutter·华为·harmonyos·鸿蒙
Zevalin爱灰灰2 小时前
USB协议介绍及使用(基于STM32)
stm32·单片机·嵌入式硬件
Zevalin爱灰灰2 小时前
J-Link+Ozone调试教程
stm32·嵌入式硬件·调试
nh75272 小时前
(一)HPM自定义工程创建实操
单片机·risc-v·hpm·先楫
Linging_242 小时前
基于Langchain得AI Agent相关知识学习
人工智能·学习·langchain
minglie111 小时前
高等代数试题
学习
Xiaofeng369312 小时前
GPT-5.6 发布后,我用了一个周末重新规划学习路线图
gpt·学习
其实防守也摸鱼13 小时前
运维--怎么看接口的请求和返回
运维·学习·网络安全·网络攻击模型·burpsuite·攻防对抗·蓝队