DMA部分我用到的相对简单,当然,可能这是新东西,我暂时还用不到它的复杂功能吧。下面用问答的形式表达我的思路。

DMA有什么用?

       直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。

有多少个DMA资源?

       有两个DMA控制器DMA17个通道,DMA25个通道。

数据从什么地方送到什么地方?

       外设到SRAMI2C/UART等获取数据并送入SRAM);

       SRAM的两个区域之间;

       外设到外设(ADC读取数据后送到TIM1控制其产生不同的PWM占空比);

       SRAM到外设(SRAM中预先保存的数据送入DAC产生各种波形);

       ……还有一些目前还搞不清楚的。

DMA可以传递多少数据?

       传统的DMA的概念是用于大批量数据的传输,但是我理解,在STM32中,它的概念被扩展了,也许更多的时候快速是其应用的重点。数据可以从165535个。

通道是如何分配的?

       见下面的这个表:

如何来用DMA

       确定数据来源,确定数据目的地,选择使用哪个通道,设定传输多少个数据,设定数据传递模式等等就可以了。且读一下STM32提供给我们的例子。

//

……

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM1_CCR3_Address;

  //设定外围设备的地址

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SRC_Buffer;

  //设定内存地址,SRC_Buffer是前面定义的一个数组

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  //方向控制

  DMA_InitStructure.DMA_BufferSize = 3;                                //缓冲区大小

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外围地址增量控制

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址增量控制

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

  //DMA_PeripheralDataSize_HalfWord的值为0x100,后一个为0x400,在在stm32f10x_dma.h中定义,用于决定存储器数据宽度*/

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

 

这些设置将会对CCRx寄存器进行操作,如下图所示:

以下是stm32f10x_dma.c中有关DMA的初始化设置代码

tmpreg |= DMA_InitStruct->DMA_DIR | DMA_InitStruct->DMA_Mode |

            DMA_InitStruct->DMA_PeripheralInc | DMA_InitStruct->DMA_MemoryInc |

            DMA_InitStruct->DMA_PeripheralDataSize | DMA_InitStruct->DMA_MemoryDataSize |

            DMA_InitStruct->DMA_Priority | DMA_InitStruct->DMA_M2M;

  

  DMAy_Channelx->CCR = tmpreg;

 /看到了,这里对CCR寄存器进行了写操作,它把上面的那些设置都设定进去了。

 

  DMAy_Channelx->CNDTR = DMA_InitStruct->DMA_BufferSize;

 

 

  DMAy_Channelx->CPAR = DMA_InitStruct->DMA_PeripheralBaseAddr;

 

  DMAy_Channelx->CMAR = DMA_InitStruct->DMA_MemoryBaseAddr;

//内存地址送入CMAR寄存器

    

说明:这个图从PDF截下来,图中那个DMA_CPARx写错了,应该是DMA_CMARx

------------------------------------------------------------------------------------------

再来看一个DMA的例子

 

  DMA_DeInit(DMA1_Channel5);

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM1_CCR1_Address;

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC1_DR_Address;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

  DMA_InitStructure.DMA_BufferSize = 1;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  DMA_Init(DMA1_Channel5, &DMA_InitStructure);

 

  DMA_Cmd(DMA1_Channel5, ENABLE);

还有一些目前暂时还没有去搞清楚的,比如中断处理等,等到需要时再看吧。



怎样启用DMA?首先,众所周知的是初始化,任何设备启用前都要对其进行初始化,要对模块初始化,还要先了解该模块相应的结构及其函数,以便正确的设置;由于DMA较为复杂,我就只谈谈DMA的基本结构和和常用函数,这些都是ST公司提供在库函数中的。

1、  下面代码是一个标准DMA设置,当然实际应用中可根据实际情况进行裁减:

 

  DMA_DeInit(DMA_Channel1);

  上面这句是给DMA配置通道,根据ST提供的资料,STM3210Fx中DMA包含7个通道(CH1~CH7),这里需要选择一个传输通道

 

  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;

  上面语句中的DMA_InitStructure是一个DMA结构体,在库中有声明了,当然使用时就要先定义了;DMA_PeripheralBaseAddr是该结构体中一个数据成员,给DMA一个起始地址,好比是一个buffer起始地址,数据流程是:外设寄存器à DMA_PeripheralBaseAddàmemory中变量空间(或flash中数据空间等),ADC1_DR_Address是ADC1的地址,既然是桥梁,肯定要连接两个端点,这里需要明白所需要连接的外设的地址;

 

  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;

  上面这句很显然是DMA要连接在Memory中变量的地址,ADC_ConvertedValue是我自己在memory中定义的一个变量;

 

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

  上面的这句是设置DMA的传输方向,就如前面我所说的,DMA可以双向传输,也可以单向传输,这里设置的是单向传输,如果需要双向传输:把DMA_DIR_PeripheralSRC改成DMA_DIR_PeripheralDST即可。

 

 

 DMA_InitStructure.DMA_BufferSize = 2;

  上面的这句是设置DMA在传输时缓冲区的长度,前面有定义过了buffer的起始地址:ADC1_DR_Address ,为了安全性和可靠性,一般需要给buffer定义一个储存片区,这个参数的单位有三种类型:Byte、HalfWord、word,我设置的2个half-word(见下面的设置);32位的MCU中1个half-word占16 bits。

 

 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  上面的这句是设置DMA的外设递增模式,如果DMA选用的通道(CHx)有多个外设连接,需要使用外设递增模式:DMA_PeripheralInc_Enable;我的例子里DMA只与ADC1建立了联系,所以选用DMA_PeripheralInc_Disable

 

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

上面的这句是设置DMA的内存递增模式,DMA访问多个内存参数时,需要使用DMA_MemoryInc_Enable,当DMA只访问一个内存参数时,可设置成:DMA_MemoryInc_Disable。

 

 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

上面的这句是设置DMA在访问时每次操作的数据长度。有三种数据长度类型,前面已经讲过了,这里不在叙述。

 

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

与上面雷同。在此不再说明。

 

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  上面的这句是设置DMA的传输模式:连续不断的循环模式,若只想访问一次后就不要访问了(或按指令操作来反问,也就是想要它访问的时候就访问,不要它访问的时候就停止),可以设置成通用模式:DMA_Mode_Normal

 

  DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  上面的这句是设置DMA的优先级别:可以分为4级:VeryHigh,High,Medium,Low.

 

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  上面的这句是设置DMA的2个memory中的变量互相访问的

 

  DMA_Init(DMA_Channel1,&DMA_InitStructure);

  前面那些都是对DMA结构体成员的设置,在次再统一对DMA整个模块做一次初始化,使得DMA各成员与上面的参数一致。

 

  /*DMA Enable*/

  DMA_Cmd(DMA_Channel1,ENABLE);

使能此通道。

当然更多的还需要看固件库函数的说明。

 

 

这里面知识DMA的一个简单应用,后面做很多设计在数据传输上需要做这种转变,特别是像我这样从单片机学过来的,现在里面有了更好的方式要学会去运用,不能固守原来单片机的设计思路。这个相信也是后面学习中很重要的一部分。


关键字:STM32  DMA  寄存器 引用地址:STM32之DMA二

上一篇:STM32 USB Virtual COM USB转串口的功能实现
下一篇:stm32 usb数据缓冲区疑问

推荐阅读

        在人工智能这股浪潮袭来之初,通常很难判断谁才会成为“大赢家”。        每一波重大的科技浪潮袭来时,都会产生几家非常有价值的科技公司,有的市值甚至会达到几千亿美元。不过在这股浪潮袭来之初,通常很难判断谁才会成为“大赢家”。        然而只要你研究过科技史,你就会发现,当这些技术浪潮袭来时,有两类公司的...
杭州新迪数字工程系统有限公司与西门子数字化工业软件在上海举办战略合作签约仪式。新迪公司创始人兼 CEO 叶修梓博士、西门子工业软件全球高级副总裁兼大中华区 CEO 梁乃明代表双方签署战略合作协议。双方将共同致力于工业数字化领域的深度合作、联合发展。双方管理层参与并见证了签约仪式,共同规划发展愿景。 目前,新迪公司是西门子在中国工业软件...
据报道,特斯拉即将在内华达州的Gigafactory生产松下生产的新电池单元,充电速度更快,因此可以预期特斯拉汽车的充电速度也得到相应提升。今年早些时候,松下宣布向内华达州Gigafactory额外投资1亿美元,这是与特斯拉合作,专门为电动汽车制造商生产电池单元的工厂。松下表示,将把内华达州Gigafactory生产的电池能量密度提高5%,总产量提高10%。曾长期在...
时钟源ATmega128 芯片有如下几种通过熔丝位选择的时钟源。时钟输入到AVR 时钟发生器,并通往其他合适的模块。Note: 1. 对于所有的熔丝位, “1” 表示未编程, “0” 代表已编程。每个时钟源在后续部分单独介绍。当CPU 自掉电模式或省电模式唤醒之后,被选择的时 钟源用来为启动过程定时,保证振荡器在开始执行指令之前进入稳定状态。当CPU 从...

史海拾趣

问答坊 | AI 解惑

分布式温度控制

    有谁能提供有关基于MS-51的分布式温度控制有关资料,谢谢了!!!!!   急用!急用!!!!!!!!!!!!!!!!…

查看全部问答∨

双向手灯

如果你有在漆黑一片的环境中走路的经历,一定会知道,只有一个手电筒虽然要比没有手电好得多,但是也并不见得能让你行走的步伐加快多少。因为,单个的手电筒只能照亮一个方向,而我们不仅要看清前面的路还要同时兼顾脚下,所以,如果只有一个手电筒 ...…

查看全部问答∨

window ce 6.0 矩阵键盘驱动

如何自己写成键盘的单体的流驱动,有两个问题没有解决 ,请问各位大侠: (1)键盘驱动 改如何将扫描的键盘值发送到GWES? 是通过那个函数发送过去的啊? (2)GWES可以加载流驱动到GWES吗?如果可以 如何让GWES加载?如果不行 应该怎么处理? …

查看全部问答∨

关于单片机控制步进电机!!

   小弟最近在做步进电机,想要单片机控制,但步进电机比较大,驱动电流在2A以上,请问各位高手帮忙介绍一下可以用的驱动芯片,谢谢!…

查看全部问答∨

如何确保WinCE的稳定性

如题: 如何确报WinCE的稳定性 如果在运行过程中,出现意外死机等不正常现象,如何处理... …

查看全部问答∨

最近论坛好象有问题

不稳定,资源不能上传,有时出上传界面时,用户名竟然不是自己的!!而且哪个资源也没有上传成功,虽然提示是成功了,可以搜不到资源.更离谱的是竟然计时出负值,晕啊 预计剩余时间: 剩余 -955 秒 文件名:14095955345.rar (7.64MB/185.12KB) 正在上传 14 ...…

查看全部问答∨

高手来帮忙,菜鸟问题(EVC 中 动态链接库的头文件怎么定义)

   在EVC中新建了个动态链接库名位dll。里面代码也很简单好用。 #include "stdafx.h" BOOL APIENTRY DllMain( HANDLE hModule,                      &n ...…

查看全部问答∨

i.mx25 ADC

i.MX25是freescale的ARM9处理器,400MHZ主频,DDR2控制器,是针对工业市场设计的,和TI的AM18xx类似,和atmel的也类似。这个用来做工业产品是很好的这是个应用笔记,说的是ADC模块…

查看全部问答∨

请教:怎样把FPGA的数据送给Matlab画图

请教:怎样把FPGA的数据送给Matlab画图…

查看全部问答∨

晶振清洗问题

本帖最后由 jameswangsynnex 于 2015-3-3 19:57 编辑 请问晶振可以清洗吗 用什么清洗液体不会损害晶振 …

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved