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

相关推荐
liuyicenysabel7 小时前
多服务上线日记三:
运维·服务器·笔记·学习
YM52e8 小时前
鸿蒙ArkTS实战项目 - 门店陈列巡检台:巡检卡片与多列切换实现
学习·华为·harmonyos
嵌入式阿蔡8 小时前
传感器_03:电机驱动——让 GPIO 当指挥官,别让 GPIO 当电源
网络·stm32·单片机·嵌入式硬件·嵌入式实时数据库
一只小小的芙厨9 小时前
基础数论总结
笔记·学习·算法
国科安芯10 小时前
ASL706S:让 MCU 不再“失忆跑飞“的守护芯片
分布式·单片机·嵌入式硬件·安全·fpga开发·架构
hsjiasb10 小时前
FreeRTOS学习(三十七)——常见错误与工程规范
学习·学习笔记·freertos
小席是个热心肠11 小时前
Redis的自我学习
数据库·redis·学习
zyf10441611 小时前
暑期实践日志 Day33:完成全部字幕添加,工作基本收尾
学习·计算机网络·剪辑·暑期实践·课题任务
Chris _data12 小时前
WPF 上位机开发学习笔记 - 第四天
笔记·学习·wpf
HY小宝F12 小时前
树莓派 FFmpeg 实战笔记(二):命令行、源码编译与硬件编码的真相
学习·职场和发展·ffmpeg