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

相关推荐
wuyk5551 小时前
防逆向基础:在量产固件中关闭调试接口并设置读保护(RDP)的正确姿势
stm32·单片机·嵌入式硬件·性能优化·重构
小小de风呀4 小时前
de风——【从零开始学习Linux】(九):进程基础 —— 从冯诺依曼体系到 fork 创建进程
linux·学习
李某学编程4 小时前
基于ARM的微机原理学习笔记(一)
arm开发·笔记·学习
zhangrelay4 小时前
单片机原理与接口技术-2026融合版-从MEGA2560-ESP32与Wokwi到ROS2-Lyrical与具身智能栈
单片机·嵌入式硬件
Song_RsHt4 小时前
Redis 与微服务,什么场景下无可替代
java·redis·后端·学习·微服务
lhbweilai5 小时前
分析FreeRTOS内核对象API的源码实现(八)
c语言·开发语言·stm32·单片机
艾络迅Acceleronix6 小时前
环境监测终端:STM32+EG800Z AT+ 艾络迅平台实战|多传感器采集联动全流程
c语言·stm32·单片机·嵌入式硬件·物联网·1024程序员节
涂山苏苏⁠6 小时前
stm32复习总结
stm32·单片机·嵌入式硬件
Zwawa6 小时前
一只按键不只“按下”:短按、长按和连按如何共存
c语言·单片机·嵌入式
苏格拉真没有底7 小时前
ESP32 AI MCP调试器
stm32·单片机·嵌入式硬件