本文主要介绍的是DMA相关的知识,首先:

1)在实现DMA传输时,是由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把 总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过 程必须经过DMA请求、DMA响应、DMA传输、DMA结束4个步骤。
2)DMA技术的出现,使得外围设备可以通过DMA控制器直接访问内存,与此同时,CPU可以继续执行程序.那么DMA控制器与CPU怎样分时使用内存呢?通常采用以下三种方法:(1)停止CPU访内存;(2)周期挪用;(3)DMA与CPU交替访问内存

具体说明:

1.DMA有什么用?

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

2.有多少个DMA资源?

有两个DMA控制器,DMA1有7个通道,DMA2有5个通道。

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

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

SRAM的两个区域之间;

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

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

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

4.DMA可以传递多少数据?

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

直接存储器存取(Direct Memory Access,DMA)是计算机科学中的一种内存访问技术。它允许某些电脑内部的硬体子系统(电脑外设),可以独立地直接读写系统存储器,而不需绕道 CPU。在同等程度的CPU负担下,DMA是一种快速的数据传送方式。它允许不同速度的硬件装置来沟通,而不需要依于 CPU的大量中断请求。【摘自Wikipedia】

现在越来越多的单片机采用DMA技术,提供外设和存储器之间或者存储器之间的高速数据传输。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器
来实行和完成。STM32就有一个DMA控制器,它有7个通道,每个通道专门用来管理一个或多个外设对存储器访问的请求,还有一个仲裁器来协调各个DMA请求的优先权。

DMA 控制器和Cortex-M3核共享系统数据总线执行直接存储器数据传输。当CPU和DMA同时访问相同的目标(RAM或外设)时,DMA请求可能会停止 CPU访问系统总线达若干个周期,总线仲裁器执行循环调度,以保证CPU至少可以得到一半的系统总线(存储器或外设)带宽。

在发生一个事件后,外设发送一个请求信号到DMA控制器。DMA控制器根据通道的优先权处理请求。当DMA控制器开始访问外设的时候,DMA控制器立即发送给外设一个应答信号。当从DMA控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求,DMA控制器同时撤销应答信号。如果发生更多的请求时,外设可以启动下次处理。

总之,每个DMA传送由3个操作组成:

1). 从外设数据寄存器或者从DMA_CMARx寄存器指定地址的存储器单元执行加载操作。

2). 存数据到外设数据寄存器或者存数据到DMA_CMARx寄存器指定地址的存储器单元。

3). 执行一次DMA_CNDTRx寄存器的递减操作。该寄存器包含未完成的操作数目。

仲裁器根据通道请求的优先级来启动外设/存储器的访问。优先级分为两个等级:软件(4个等级:最高、高、中等、低)、硬件(有较低编号的通道比拥有较高编号的通道有较高的优先权)。

可以在DMA传输过半、传输完成和传输错误时产生中断。

STM32中DMA的不同中断(传输完成、半传输、传输完成)通过“线或”方式连接至NVIC,需要在中断例程中进行判断。

进行DMA配置前,不要忘了在RCC设置中使能DMA时钟。STM32的DMA控制器挂在AHB总线上。

DMA总共有7个通道,各个通道的DMA映射关系如下:

外设的事件连接至相应DMA通道,每个通道均可以通过软件触发实现存储器内部的DMA数据传输(M2M模式)

Tips:库2.0中函数RCC_AHBPeriphClockCmd的参数由“RCC_AHBPeriph_DMA”改成“RCC_AHBPeriph_DMA1”(如果是DMA1控制器的话)。

DMA的传输标志位(CHTIFx、CTCIFx、CGIFx)由硬件设置为“1”,但需要软件清零,在中断服务程序中清除。当CGIFx(全局中断标志位)清零后,CHTIFx 和 CTCIFx均清零。

5.过程:怎样启用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_Cmd(DMA_Channel1,ENABLE);

哈哈哈!这一句我想我就不罗嗦了,大家一看就明白。

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

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

2)

一个简单的例子 transfer  a word data buffer
from FLASH memory to embedded SRAM memory.

在V3.1.2库的位置

STM32F10x_StdPeriph_Lib_V3.1.2\Project\STM32F10x_StdPeriph_Examples\DMA\FLASH_RAM

DMA_DeInit(DMA1_Channel6);

//peripheral base address

DMA_InitStructure.DMA_PeripheralBaseAddr =
(uint32_t)SRC_Const_Buffer;

//memory base address

DMA_InitStructure.DMA_MemoryBaseAddr =
(uint32_t)DST_Buffer;

//数据传输方向    Peripheral is source

DMA_InitStructure.DMA_DIR =
DMA_DIR_PeripheralSRC;

//缓冲区大小 Number of data
to be transferred (0 up to 65535).数据传输数目

DMA_InitStructure.DMA_BufferSize =
BufferSize;

//
the Peripheral address register is incremented

DMA_InitStructure.DMA_PeripheralInc =
DMA_PeripheralInc_Enable;

//the memory address register is incremented

DMA_InitStructure.DMA_MemoryInc =
DMA_MemoryInc_Enable;

//the Peripheral data width

DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Word;

DMA_InitStructure.DMA_MemoryDataSize =
DMA_MemoryDataSize_Word;

DMA_InitStructure.DMA_Mode =
DMA_Mode_Normal;

DMA_InitStructure.DMA_Priority =
DMA_Priority_High;

//the DMAy Channelx will be used in
memory-to-memory transfer

//DMA通道的操作可以在没有外设请求的情况下进行,这种操作就是存储器到存储器模式。

DMA_InitStructure.DMA_M2M =
DMA_M2M_Enable;

DMA_Init(DMA1_Channel6,
&DMA_InitStructure);

DMA_ITConfig(DMA1_Channel6, DMA_IT_TC,
ENABLE);

DMA_Cmd(DMA1_Channel6, ENABLE);

=======================================================================

3)外设的DMA请求映像

要使DMA与外设建立有效连接,这不是DMA自身的事情,是各个外设的事情,每个外设都有
一个

xxx_DMACmd(XXXx,Enable )函数,如果使DMA与ADC建立有效联系,就使用
ADC_DMACmd

(ADC1,Enable); (这里我启用了ADC中的ADC1模块)。

DMA_DeInit(DMA1_Channel1);

DMA_InitStructure.DMA_PeripheralBaseAddr =
ADC1_DR_Address;

DMA_InitStructure.DMA_MemoryBaseAddr =
(uint32_t)&AD_Value;

//u16 
AD_Value[2];   不加&应该也可以  数组名 代表地址

DMA_InitStructure.DMA_DIR =
DMA_DIR_PeripheralSRC;

DMA_InitStructure.DMA_BufferSize = 2;      //############## 改了

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_InitStructure.DMA_Mode =
DMA_Mode_Circular;

DMA_InitStructure.DMA_Priority =
DMA_Priority_High;

DMA_InitStructure.DMA_M2M =
DMA_M2M_Disable;

DMA_Init(DMA1_Channel1,
&DMA_InitStructure);

DMA_Cmd(DMA1_Channel1, ENABLE);

ADC_InitStructure.ADC_Mode =
ADC_Mode_Independent;

ADC_InitStructure.ADC_ScanConvMode =
ENABLE;

ADC_InitStructure.ADC_ContinuousConvMode =
ENABLE;

ADC_InitStructure.ADC_ExternalTrigConv =
ADC_ExternalTrigConv_None;

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStructure.ADC_NbrOfChannel =
2;      //##############     改了

ADC_Init(ADC1, &ADC_InitStructure);

//内部温度传感器  添加这一句

ADC_TempSensorVrefintCmd(ENABLE);

//##############     改了

//################ Channel 10(电位器)

ADC_RegularChannelConfig(ADC1,
ADC_Channel_10, 1, ADC_SampleTime_13Cycles5);

//###### 内部温度传感器  Channel 16 ###################

ADC_RegularChannelConfig(ADC1,
ADC_Channel_16, 2, ADC_SampleTime_55Cycles5);

使能ADC1的DMA请求映像

ADC_DMACmd(ADC1, ENABLE);

ADC_Cmd(ADC1, ENABLE);

//使用之前一定要校准

ADC_ResetCalibration(ADC1);

while(ADC_GetResetCalibrationStatus(ADC1));

ADC_StartCalibration(ADC1);

while(ADC_GetCalibrationStatus(ADC1));

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

最后附笔记:

驱动之DMA的介绍与应用20170210的更多相关文章

  1. linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)

    原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...

  2. usb驱动开发篇简易介绍

    我这里重点的介绍如何写驱动程序,对于一些应用程序我就不做介绍了,因为我对于那些高层的东西写得很少.倘若再讲,有班门弄斧之嫌,呵呵! 作为WIN98和WIN2K推荐的一项新技术来说,USB的驱动程序和以 ...

  3. 蜕变成蝶~Linux设备驱动之DMA

    如果不曾相逢 也许 心绪永远不会沉重 如果真的失之交臂 恐怕一生也不得轻松 一个眼神 便足以让心海 掠过飓风 在贫瘠的土地上 更深地懂得风景 一次远行 便足以憔悴了一颗 羸弱的心 每望一眼秋水微澜 便 ...

  4. 迅为iTOP-4418/6818开发板-驱动-IO初始化配置介绍和例程

    对于所有的处理器,pad 一般可以分为两大类:IO(输入输出).Power(VDD 和GDD).类似摄像头 IO.以太网 IO.PWM 的 IO 等等,都可以统称为 IO.一个 IO,有可能能够被配置 ...

  5. Linux Framebuffer 驱动框架之一概念介绍及LCD硬件原理【转】

    本文转载自:http://blog.csdn.net/liuxd3000/article/details/17464779 一.基本概念 帧缓冲(Framebuffer)是Linux系统为显示设备提供 ...

  6. Linux设备驱动Hello World程序介绍

    自古以来,学习一门新编程语言的第一步就是写一个打印“hello world”的程序(可以看<hello world 集中营>这个帖子供罗列了300个“hello world”程序例子)在本 ...

  7. 驱动之LCD的介绍与应用20170209

    本文主要介绍的是LCD的介绍与应用,直接看个人笔记即可:

  8. 驱动之NandFlash的介绍与应用20170209

    本文主要介绍的是NAND FLASH的介绍与应用,直接看个人笔记即可:

  9. Spring注解驱动第三讲--@Filter介绍

    上一讲主要针对@ComponentScan注解做了一些说明,本文主要对@Filter的扫描条件,再做一些详细的介绍 1,FilterType.ANNOTATION 按照注解的方式进行扫描.后面clas ...

随机推荐

  1. 420. Count and Say【LintCode java】

    Description The count-and-say sequence is the sequence of integers beginning as follows: 1, 11, 21, ...

  2. CSP201312-3:最大的矩形

    引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...

  3. JAVA学习笔记--简介几个常见关键字static、final、this、super

    一.static static(静态的),可以放在类.方法.字段之前. 通常,当创建类时,就是在描述那个类的外观与行为.除非用 new 创建那个类的对象,否则,实际上并未获得任何对象.执行 new 来 ...

  4. 曾经我是一个只会excel的数据分析师,直到我遇到了……

    我是一个数据分析师. 准确来说我是一个当年只会excel数据透视表,就天不怕地不怕地来当数据分析师的人.当年的某一天,我的老板Q我: 小刘啊,我小姨子给了我一个全国市委书记的名单,你帮我看看,有什么规 ...

  5. sip鉴权认证算法详解及python加密

    1. 认证和加密    认证(Authorization)的作用在于表明自己是谁,即向别人证明自己是谁.而相关的概念是MD5,用于认证安全.注意MD5仅仅是个hash函数而已,并不是用于加密.因为ha ...

  6. loadrunner socket协议问题归纳(2)

    编写步骤 1.建立与服务端的连接 rc=lrs_create_socket(“socket0”,”TCP”,”LocalHost=0”,”RemoteHost=127.0.0.1:8808”,LrsL ...

  7. 【转】React-Native 实现增量热更新的思路

    所谓热更新就是在不重新安装的前提下进行代码和资源的更新,相信在整个宇宙中还不存在觉得热更新不重要的程序猿. 增量热更新就更牛逼了,只需要把修改过和新增的代码和资源推送给用户下载即可,增量部分的代码和资 ...

  8. Phonegap 环境配置

    目前要开发 Web App 还是有比较多的选择的 如 Phonegap.MUI.AppCan,接下来以 Web前端开发工程师 的角度来一个 Phonegap 的 First Blood 一.开发环境: ...

  9. java包名命名规范

    Java的包名都有小写单词组成,类名首字母大写:包的路径符合所开发的 系统模块的 定义,比如生产对生产,物资对物资,基础类对基础类.以便看了包名就明白是哪个模块,从而直接到对应包里找相应的实现. 由于 ...

  10. 项目Beta冲刺(团队)第二天

    1.昨天的困难 夜间模式实现的时候一点击开关就会出现app黑屏卡死的状态,recreate()方法实现有问题 服务器有点问题 2.今天解决的进度 成员 进度 陈家权 研究如何实现私信模块 赖晓连 最新 ...