浅谈STM32DMA模块的使用

转自:http://blog.ednchina.com/jack_chang/123085/message.aspx

http://article.ednchina.com/Other/200806050734461.htm

By Jack Chang

Thu Jun 5 2008  18:30:49

E-mail:zhang-weihong@126.com QQ:179748613

前言:接触MCU的编程已经有几年的历史,刚开始是从PLC(C语言的)学习与应用,后来有学习了8bits的AVR单片机,对MCU有一定的了解;最近接触了STM32的Chip,发现其优点不只是单单宣传的32bits的MCU的速度,而且在编程的风格上也有了较大的变化(与我原有的编程习惯);特别是有一个与CPU并行运行的模块:DMA,对它印象深刻。现在就和大家一起讨论学习这个Module,谈谈我在学习中一些感悟和大家一起分享;如有对DMA理解和应用上的错误和偏差,欢迎“拍砖”和提出更正,虾米在此感谢大家了。哈哈!

什么是STM32的DMA?其全称是:Direct Memory Access;根据ST公司提供的相关信息,DMA是STM32中一个独立与Cortex-M3内核的模块,有点类似与ADC、PWM、TIMER等模块;主要功能是通信“桥梁”的作用,可以将所有外设映射的寄存器“连接”起来,这样就可以高速问各寄存器,其传输不受CPU的支配,传输还是双向的;例如,从“表面”上看,它可以将flash中的数据与储存器中变量建立通讯,还可以将一外设的积存器或缓冲器与另外设的寄存器或缓冲器建立双向通讯,有点像把外设硬件之间用“导线”连接在一起了。其间的通讯不占CPU资源,访问速度高,对于实时性强的应用将是一个很好的选择;当然,对于实时性非常强的,建议还是采用专用的DSP芯片。

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

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

DMA_DeInit(DMA_Channel1);

上面这句是给DMA配置通道,根据ST提供的资料,STM3210Fx中DMA包含7个通道(CH1~CH7),也就是说可以为外设或memory提供7座“桥梁”(请允许我使用桥梁一词,我觉得更容易理解,哈哈,别“拍砖”呀!);

DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;

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

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总算设置好了,但是,DMA通道又是怎样与外设联系在一起的呢?哈哈,这也是我当初最想知道的一个事情,别急!容我想喝口茶~~~~~~哈哈哈!

要使DMA与外设建立有效连接,这不是DMA自身的事情,是各个外设的事情,每个外设都有 一个xxx_DMACmd(XXXx,Enable )函数,如果使DMA与ADC建立有效联系,就使用ADC_DMACmd(ADC1,Enable); (这里我启用了ADC中的ADC1模块)。

下面就以我的一个实例来和大家一起学习。这个实例仿真是成功的,我使用的是IAR Embedded Workbench IDE(v4.42) 和Manley Mini-kit评估板+ST-Link II来调试,是一个USART+ADC+DMA的例子。

首先,按照相关的资料提示,建立好项目路径、拷贝库文件和相关必要的文件,并建立一个新工程;还有就是设置好IAR IDE的相关设置。一切准备就绪后就开始修改相关的文档:

conf.h文档的修改是根据应用中有启用的相关功能Module。如下图:

ADC模块的启用设置:

点击看大图

DMA模块的启用设置:

点击看大图

USART模块启用的设置:

点击看大图

其他的如flash、GPIO、RCC、NVIC、HSE等就不一一举例,因为这些几乎每个工程都要用到。

再回头看看我的main.c文档,

下图是相关的私有定义

点击看大图

USART的配制如下(9600,8, N,1):

点击看大图

DMA的配置如下:

点击看大图

ADC的配置如下图(采用了2路A/D多通道的ADC模式):

点击看大图

给各个模块配置的时钟使能如下图;在此想罗嗦一句就是在这个位置的设置我没有给DMA配置时钟,造成DMA功能无法正常使用,也就是前面所有说的与我原先的编程风格有较大的变化的原因,想说一句:在项目中所使用的所有功能模块都要在此配置时钟才能正常工作。

点击看大图

GPIO的配置

点击看大图

如果有开中断子程序,请在在NVIC中配置,还可以定义每个中断子程序的优先级别,由于我的工程没有用到,在此就不罗嗦了。

我项目应用到的文件目录如下图:

45510a7a-2732-4ec3-a8fe-36c12b448571.JPG

我的项目仿真结果如下;PA0与GND间接了一个1.5V的干电池,其结果是如中ADC_ConvertedValue[0]的值;PA1悬空,未接模拟信号。

点击看大图

我的硬件仿真平台如下2图:红色的是我AVR mega16L Mini开发板,主要是利用了其中的POWER和RS232

点击看大图

点击看大图

用PC端USART数据采集结果:(图中的显示是我将ADC转换后的值给字符串化了)

点击看大图

ST-link II仿真窗口的测试结果与USART采集到的数据结果差异说明:由于Manley 的stme32 Mini-kit评估板套件无法给ADC和USART同时组合仿真,我是分别分开仿真和USART数据传输的,所以出现差异。

心得: 1、这次学习STM32的MCU,最大的心得是改变我原有的编程思维,原来学习AVR的时候,文件库需要自己写,属于底层操作,如要自己写直接操作各外设的寄存器,复杂的还需要自己写设置函数,对底层要有非常的清楚的认识,编写的代码的工作量也比较大;稍有不慎,容易把寄存器弄错;调试也会花费较大的时间。而STM32的编程风格给我一个全新的视角(哈哈!别拍砖,虽然属菜鸟级别,但比较容易接受新的东西),感觉只要按其提供的资料建立起工程的基本构架,很多都是ST公司提供封装好的接口(类似windows的API),直接调用接口和做少许修改就可以完成你想要的工程结果。

2、 清晰的工程构架:ST提供一些工程案例的基本构架,只要熟悉这些构架,对构架做一些适当的修改,你将很轻松的完成你的任务,开发周期也可以缩短很多。请记住:牢记工程构架;

3、 哈哈!不想罗嗦的是STM32的速度和丰富的外设。(再罗嗦可能会被成批的砖头拍死,哈哈哈哈!)

4、 更有信心用STM32做其他更复杂一些的项目。祝大家好运!(别拍砖头呀!哈哈!)

转载于:https://www.cnblogs.com/hnrainll/archive/2011/01/18/1937891.html

浅谈STM32的DMA模块的使用相关推荐

  1. 借WS2812 PWM DMA驱动调试浅谈STM32调试思路

    借WS2812 PWM DMA驱动调试浅谈STM32调试思路 ​ 接触STM32差不多有4年了,在学校参加比赛时也需要进行各种调试工作,团队的配合也需要个人具有领域内快速定位与解决BUG的能力,前些日 ...

  2. **浅谈STM32系列单片机的零基础学习方法**

    浅谈STM32系列单片机的零基础学习方法 *很多朋友想必在零基础学习STM32F1这系列单片机时会感觉无从下手,或者不知道写程序时到底是用库函数好还是寄存器好.* 我个人认为一个零基础的朋友可以通过以 ...

  3. python sys模块作用_浅谈Python中的模块

    模块 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在Python中,一个.py文件就称之为一个模块(Mod ...

  4. ant man 什么意思_浅谈为什么很多蓝牙模块厂家选择nRF52832?

    浅谈为什么很多蓝牙模块厂家选择nRF52832? 现在蓝牙低功耗(BLE)SOC作为新一代蓝牙,以其低功耗的优势,正凸显出强大的市场竞争力,而其中Nordic公司的nRF52832这一款低功耗蓝牙芯片 ...

  5. stm32中断优先级_浅谈STM32串口USART1的使用

    浅谈STM32串口USART1的使用 通用同步异步收发器(USART)提供了一种灵活的方法来与使用工业标准NR 异步串行数据格式的外部设备之间进行全双工数据交换.USART利用分数波特率发生器提供宽范 ...

  6. python如何导入requests模块_浅谈python中requests模块导入的问题

    浅谈python中requests模块导入的问题 今天使用Pycharm来抓取网页图片时候,要导入requests模块,但是在pycharm中import requests 时候报错. 原因: pyt ...

  7. 浅谈游戏服务器---功能模块上来看

    游戏服务器在网游上的作用不容考虑,游戏能做大到什么程度,还是有很大的依靠的,这篇文章先从功能模块的角度来谈一个完善的游戏服务器需要实现哪.     一:游戏服务器的作用:连接各个网游客户端,实现各客户 ...

  8. map文件分析 stm32_浅谈STM32的启动过程

    分享这篇文章,谈一下STM32启动流程.如果读者朋友已经有过汇编相关基础,能够够好理解本文内容.汇编语言是比C语言更接近机器底层的编程语言,能让我们更好的理解和操纵硬件底层. STM32三种启动模式 ...

  9. 浅谈游戏单位属性模块设计:属性组成、分级、计算与同步

    一个单位的属性(攻击力.最大血量.防御力等)一般由多个模块决定,比如我们游戏的属性由三块决定: 1.基础属性:由单位的等级和成长决定. 2.装备属性:影响人物面板显示的属性值.最常见的是装备等. 3. ...

最新文章

  1. Spring Boot 整合Pagehelper(为什么PageHelper分页不生效)
  2. Ansible 基础-介绍
  3. systemd的程序自启动脚本编写
  4. 解决Cannot convert a symbolic Tensor (lstm/strided_slice:0) to a numpy array.
  5. 初烧盲狙一条铁三角e40
  6. linux 两个mysql_Linux下安装两个MySQL的方法
  7. ALinq 让Mysql变得如此简单
  8. 打包maven后出现jar包丢失
  9. 做互联网的基因,互联网营销
  10. 请大家一起呼吁媒体不要进行幸还者回忆性采访
  11. java 万年历 农历_万年历(java实现)
  12. 计算机打印服务总是自动关闭,win10系统电脑打印机print spooler服务总是自动停止的设置教程...
  13. 安装增强功能时,未能加载虚拟光盘 D:\VirtualBox\VBoxGuestAdditions.iso到虚拟电脑
  14. bat脚本——提取多个文件夹到指定路径
  15. 计算机网络和现场总线的区别,现场总线系统的特点和组成
  16. 沪牌学院-沪拍拍课堂4: 实拍前的演练
  17. 综合交易平台API技术开发指南
  18. 渗透测试-不死马的创建和查杀
  19. Python爬虫之MongoDB
  20. 某程序员哀叹:做码农真的很悲哀,有的35岁就没人要了

热门文章

  1. 正则表达式的顺序优先级
  2. codeforces 450B. Jzzhu and Sequences 解题报告
  3. JavaBean的保存范围与javaBean的删除
  4. [恢]hdu 2524
  5. » 欄位太小以致於無法接受您試圖加入的資料數量
  6. 基于 OpenCV 的人脸识别
  7. Git pull[push] 不用每次输入用户名和密码
  8. Apache Kafka:大数据的实时处理时代
  9. ELF文件格式与进程地址空间的联系
  10. 使用redis和fastjson做应用和mysql之间的缓存