STM32 DMA 知识讲解

来源:本站
导读:目前正在解读《STM32 DMA 知识讲解》的相关信息,《STM32 DMA 知识讲解》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《STM32 DMA 知识讲解》的详细说明。
简介:DMA 传输对于高效能嵌入式系统算法和网络是很重要的。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。DMA 是个非常好的功能,它不但能减轻 CPU 负担,还能提高数据传输速度.

DMA,全称为:DirectMemoryAccess,即直接存储器访问,DMA传输将数据从一个地址空间复制到另外一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。DMA传输对于高效能嵌入式系统算法和网络是很重要的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,能使CPU的效率大为提高。DMA是个非常好的功能,它不但能减轻CPU负担,还能提高数据传输速度.

STM32最多有2个DMA控制器(DMA2仅存在大容量产品中),DMA1有7个通道。DMA2有5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁起来协调各个DMA请求的优先权。

STM32的DMA有以下一些特性:

●每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。

●在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),假如在相等优先权时由硬件决定(请求0优先于请求1,依此类推)。

●独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。

●支持循环的缓冲器管理

●每个通道都有3个事件标志(DMA半传输,DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。

●存储器和存储器间的传输

●外设和存储器,存储器和外设的传输

●闪存、SRAM、外设的SRAM、APB1APB2和AHB外设均可作为访问的源和目标。

●可编程的数据传输数目:最大为65536

库函数下DMA1通道4的配置步骤

1)使能DMA时钟

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//使能DMA时钟

2)初始化DMA通道4参数

DMA通道配置参数种类比较繁多,包括内存地址,外设地址,传输数据长度,数据宽度,通道优先级等等。这些参数的配置在库函数中都是在函数DMA_Init中完成,下面我们看看函数定义:

voidDMA_Init(DMA_Channel_TypeDef*DMAy_Channelx,DMA_InitTypeDef*DMA_InitStruct)

函数的第一个参数是指定初始化的DMA通道号,这个很容易理解,下面我们主要看看第二个参数。跟其他外设一样,同样是通过初始化结构体成员变量值来达到初始化的目的,下面我们来看看DMA_InitTypeDef结构体的定义:

typedefstruct

{

uint32_tDMA_PeripheralBaseAddr;

uint32_tDMA_MemoryBaseAddr;

uint32_tDMA_DIR;

uint32_tDMA_BufferSize;

uint32_tDMA_PeripheralInc;

uint32_tDMA_MemoryInc;

uint32_tDMA_PeripheralDataSize;

uint32_tDMA_MemoryDataSize;

uint32_tDMA_Mode;

uint32_tDMA_Priority;

uint32_tDMA_M2M;

}DMA_InitTypeDef;

第一个参数DMA_PeripheralBaseAddr用来设置DMA传输的外设基地址,比如要进行串口DMA传输,那么外设基地址为串口接受发送数据存储器USART1->DR的地址,表示方法为&USART1->DR。

第二个参数DMA_MemoryBaseAddr为内存基地址,也就是我们存放DMA传输数据的内存地址。

第三个参数DMA_DIR设置数据传输方向,决定是从外设读取数据到内存还送从内存读取数据发送到外设,也就是外设是源地还是目的地,这里我们设置为从内存读取数据发送到串口,所以外设自然就是目的地了,所以选择值为DMA_DIR_PeripheralDST。

第四个参数DMA_BufferSize设置一次传输数据量的大小

第五个参数DMA_PeripheralInc设置传输数据的时候外设地址是不变还是递增。如果设置为递增,那么下一次传输的时候地址加1,这里因为我们是一直往固定外设地址&USART1->DR发送数据,所以地址不递增,值为DMA_PeripheralInc_Disable;

第六个参数DMA_MemoryInc设置传输数据时候内存地址是否递增。这个参数和DMA_PeripheralInc意思接近,只不过针对的是内存。这里我们的场景是将内存中连续存储单元的数据发送到串口,毫无疑问内存地址是需要递增的,所以值为DMA_MemoryInc_Enable。

第七个参数DMA_PeripheralDataSize用来设置外设的数据长度是为字节传输(8bits),半字传输(16bits)还是字传输(32bits),这里我们是8位字节传输,所以值设置为DMA_PeripheralDataSize_Byte。

第八个参数DMA_MemoryDataSize是用来设置内存的数据长度,和第七个参数意思接近,这里我们同样设置为字节传输DMA_MemoryDataSize_Byte。

第九个参数DMA_Mode用来设置DMA模式是否循环采集,也就是说,比如我们要从内存中采集64个字节发送到串口,如果设置为重复采集,那么它会在64个字节采集完成之后继续从内存的第一个地址采集,如此循环。这里我们设置为一次连续采集完成之后不循环。所以设置值为DMA_Mode_Normal。在我们下面的实验中,如果设置此参数为循环采集,那么你会看到串口不停的打印数据,不会中断,大家在实验中可以修改这个参数测试一下。

第十个参数是设置DMA通道的优先级,有低,中,高,超高三种模式,这里我们设置优先级别为中级,所以值为DMA_Priority_Medium。如果要开启多个通道,那么这个值就非常有意义。

第十一个参数DMA_M2M设置是否是存储器到存储器模式传输,这里我们选择DMA_M2M_Disable。

实例代码:

DMA_InitTypeDefDMA_InitStructure;

DMA_InitStructure.DMA_PeripheralBaseAddr=&USART1->DR;//DMA外设ADC基地址

DMA_InitStructure.DMA_MemoryBaseAddr=cmar;//DMA内存基地址

DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;//从内存读取发送到外设

DMA_InitStructure.DMA_BufferSize=64;//DMA通道的DMA缓存的大小

DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不变

DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//内存地址递增

DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//8位

DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//8位

DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//工作在正常缓存模式

DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;//DMA通道x拥有中优先级

DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//非内存到内存传输

DMA_Init(DMA_CHx,&DMA_InitStructure);//根据指定的参数初始化

3)使能串口DMA发送

进行DMA配置之后,我们就要开启串口的DMA发送功能,使用的函数是:

USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);

如果是要使能串口DMA接受,那么第二个参数修改为USART_DMAReq_Rx即可。

4)使能DMA1通道4,启动传输。

使能串口DMA发送之后,我们接着就要使能DMA传输通道:

DMA_Cmd(DMA_CHx,ENABLE);

通过以上3步设置,我们就可以启动一次USART1的DMA传输了。

5)查询DMA传输状态

在DMA传输过程中,我们要查询DMA传输通道的状态,使用的函数是:

FlagStatusDMA_GetFlagStatus(uint32_tDMAy_FLAG)

比如我们要查询DMA通道4传输是否完成,方法是:

DMA_GetFlagStatus(DMA2_FLAG_TC4);

这里还有一个比较重要的函数就是获取当前剩余数据量大小的函数:

uint16_tDMA_GetCurrDataCounter(DMA_Channel_TypeDef*DMAy_Channelx)

比如我们要获取DMA通道4还有多少个数据没有传输,方法是:

DMA_GetCurrDataCounter(DMA1_Channel4);

1.DMA_InitTypeDef DMA_InitStructure;2.3.u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度      4.//DMA1的各通道配置5.//这里的传输形式是固定的,这点要根据不同的情况来修改6.//从存储器->外设模式/8位数据宽度/存储器增量模式7.//DMA_CHx:DMA通道CHx8.//cpar:外设地址9.//cmar:存储器地址10.//cndtr:数据传输量 11.12.void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)13.{14.    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    //使能DMA传输15.    DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值16.    DMA1_MEM_LEN=cndtr;17.    18.    DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址19.    DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址20.    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设21.    DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小22.    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变23.    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增24.    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位25.    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位26.    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式27.    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 28.    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输29.    DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器30.}31.32.//开启一次DMA传输33.void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)34.{ 35.    DMA_Cmd(DMA_CHx, DISABLE ); //关闭USART1 TX DMA1 所指示的通道 36.     DMA_SetCurrDataCounter(DMA1_Channel4,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小37.     DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道 

1.u8 SendBuff[5200];2.MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)SendBuff,5168);//DMA1通道4,外设为串口1,存储器为SendBuff,长度5168.3.4.USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //使能串口1的DMA发送 5.    6.    MYDMA_Enable(DMA1_Channel4);//开始一次DMA传输!    7.    if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET)    //判断通道4传输完成8.        {9.            DMA_ClearFlag(DMA1_FLAG_TC4);//清除通道4传输完成标志10.            break; 11.        }12.        pro=DMA_GetCurrDataCounter(DMA1_Channel4); 

提醒:《STM32 DMA 知识讲解》最后刷新时间 2024-03-14 01:09:48,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《STM32 DMA 知识讲解》该内容的真实性请自行鉴别。