龙空技术网

高质量程序是怎么写出来的?串口DMA机制

嵌入式开发胖哥 533

前言:

今天咱们对“dma操作流程”大致比较看重,朋友们都需要学习一些“dma操作流程”的相关知识。那么小编同时在网上搜集了一些有关“dma操作流程””的相关文章,希望兄弟们能喜欢,兄弟们一起来学习一下吧!

摘要:前面讲了一篇关于串口循环队列的,今天说一下串口DMA。直接存储器访问(Direct Memory Access),简称DMA。DMA是CPU一个用于数据从一个地址空间到另一地址空间“搬运”(拷贝)的组件,数据拷贝过程不需CPU干预,数据拷贝结束则通知CPU处理。因此,大量数据拷贝时,使用DMA可以释放CPU资源。DMA数据拷贝过程,典型的有:内存—>内存,内存间拷贝外设—>内存,如uart、spi、i2c等总线接收数据过程内存—>外设,如uart、spi、i2c等总线发送数据过程1、 串口有必要使用DMA吗?

串口(uart)是一种低速的串行异步通信,适用于低速通信场景,通常使用的波特率小于或等于115200bps。对于小于或者等于115200bps波特率的,而且数据量不大的通信场景,一般没必要使用DMA,或者说使用DMA并未能充分发挥出DMA的作用。

对于数量大,或者波特率提高时,必须使用DMA以释放CPU资源,因为高波特率可能带来这样的问题:

对于发送,使用循环发送,可能阻塞线程,需要消耗大量CPU资源“搬运”数据,浪费CPU对于发送,使用中断发送,不会阻塞线程,但需浪费大量中断资源,CPU频繁响应中断;以115200bps波特率,1s传输11520字节,大约69us需响应一次中断,如波特率再提高,将消耗更多CPU资源对于接收,如仍采用传统的中断模式接收,同样会因为频繁中断导致消耗大量CPU资源因此,高波特率场景下,串口非常有必要使用DMA。

2、实现方式3、STM32串口使用DMA

关于STM32串口使用DMA,不乏一些开发板例程及网络上一些博主的使用教程。使用步骤、流程、配置基本大同小异,正确性也没什么毛病,但都是一些基本的Demo例子,作为学习过程没问题;实际项目使用缺乏严谨性,数据量大时可能导致数据异常。

测试平台:

STM32F030C8T6UART1/UART2DMA1 Channel2—Channel5ST标准库主频48MHz(外部12MHz晶振)

4、串口DMA接收4.1 基本流程

4.2 相关配置

关键步骤

初始化串口使能串口DMA接收模式,使能串口空闲中断配置DMA参数,使能DMA通道buf半满(传输一半数据)中断、buf溢满(传输数据完成)中断

为什么需要使用DMA 通道buf半满中断?

3年嵌入式物联网学习资源整理分享:C语言、Linux开发、数据结构;软件开发,STM32单片机、ARM硬件开发、物联网通信开发、综合项目开发教程资料;笔试面试真题。点击下方插件免费领取↓↓↓嵌入式物联网学习资料(头条)

很多串口DMA模式接收的教程、例子,基本是使用了**“空闲中断”+“DMA传输完成中断”**来接收数据。实质上这是存在风险的,当DMA传输数据完成,CPU介入开始拷贝DMA通道buf数据,如果此时串口继续有数据进来,DMA继续搬运数据到buf,就有可能将数据覆盖,因为DMA数据搬运是不受CPU控制的,即使你关闭了CPU中断

严谨的做法需要做双buf,CPU和DMA各自一块内存交替访问,即是"乒乓缓存” ,处理流程步骤应该是这样:

【1】第一步,DMA先将数据搬运到buf1,搬运完成通知CPU来拷贝buf1数据 【2】第二步,DMA将数据搬运到buf2,与CPU拷贝buf1数据不会冲突 【3】第三步,buf2数据搬运完成,通知CPU来拷贝buf2数据 【4】执行完第三步,DMA返回执行第一步,一直循环。

STM32F0系列DMA不支持双缓存(以具体型号为准)机制,但提供了一个buf"半满中断",即是数据搬运到buf大小的一半时,可以产生一个中断信号。基于这个机制,我们可以实现双缓存功能,只需将buf空间开辟大一点即可。

【1】第一步,DMA将数据搬运完成buf的前一半时,产生“半满中断”,CPU来拷贝buf前半部分数据 【2】第二步,DMA继续将数据搬运到buf的后半部分,与CPU拷贝buf前半部数据不会冲突 【3】第三步,buf后半部分数据搬运完成,触发“溢满中断”,CPU来拷贝buf后半部分数据 【4】执行完第三步,DMA返回执行第一步,一直循环。

UART2 DMA模式接收配置代码如下,与其他外设使用DMA的配置基本一致,留意关键配置:

串口接收,DMA通道工作模式设为连续模式使能DMA通道接收buf半满中断、溢满(传输完成)中断启动DMA通道前清空相关状态标识,防止首次传输错乱数据

void bsp_uart2_dmarx_config(uint8_t *mem_addr, uint32_t mem_size){   DMA_InitTypeDef DMA_InitStructure;  DMA_DeInit(DMA1_Channel5);  DMA_Cmd(DMA1_Channel5, DISABLE); DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)&(USART2->RDR);/* UART2接收数据地址 */ DMA_InitStructure.DMA_MemoryBaseAddr   = (uint32_t)mem_addr; /* 接收buf */ DMA_InitStructure.DMA_DIR      = DMA_DIR_PeripheralSRC;  /* 传输方向:外设->内存 */ DMA_InitStructure.DMA_BufferSize    = mem_size; /* 接收buf大小 */ DMA_InitStructure.DMA_PeripheralInc   = DMA_PeripheralInc_Disable;  DMA_InitStructure.DMA_MemoryInc    = DMA_MemoryInc_Enable;  DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Byte;  DMA_InitStructure.DMA_MemoryDataSize   = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode      = DMA_Mode_Circular; /* 连续模式 */ DMA_InitStructure.DMA_Priority     = DMA_Priority_VeryHigh;  DMA_InitStructure.DMA_M2M      = DMA_M2M_Disable;  DMA_Init(DMA1_Channel5, &DMA_InitStructure);  DMA_ITConfig(DMA1_Channel5, DMA_IT_TC|DMA_IT_HT|DMA_IT_TE, ENABLE);/* 使能DMA半满、溢满、错误中断 */ DMA_ClearFlag(DMA1_IT_TC5); /* 清除相关状态标识 */ DMA_ClearFlag(DMA1_IT_HT5); DMA_Cmd(DMA1_Channel5, ENABLE); }

DMA 错误中断“DMA_IT_TE”,一般用于前期调试使用,用于检查DMA出现错误的次数,发布软件可以不使能该中断。

4.3 接收处理

基于上述描述机制,DMA方式接收串口数据,有三种中断场景需要CPU去将buf数据拷贝到fifo中,分别是:

DMA通道buf溢满(传输完成)场景DMA通道buf半满场景串口空闲中断场景

前两者场景,前面文章已经描述。串口空闲中断指的是,数据传输完成后,串口监测到一段时间内没有数据进来,则触发产生的中断信号。

原文作者:果果小师弟

原文标题:高质量程序是怎么写出来的?串口DMA机制

原文链接:

标签: #dma操作流程 #dma测试模式选择