打印
[DemoCode下载]

ARM Cortex-M4的DMA使用方法

[复制链接]
3931|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
734774645|  楼主 | 2016-11-27 19:31 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
DMA 的英文拼写是“Direct Memory Access”,汉语的意思就是直接
内存访问,是一种不经过 CPU 而直接从内存存取数据的数据交换模式。在 DMA
模式下,常见的 CPU 如图 24.1.1 只须向 DMA 控制器下达指令,让 DMA 控制
器来处理数据的传送,数据传送完毕再把信息反馈给 CPU,这样就很大程度上
减轻了 CPU 资源占有率,可以大大节省系统资源。
DMA 控制器是一种在系统内部转移数据的独特外设,可以将其视为一种能
够通过一组专用总线将内部和外部存储器与每个具有 DMA 能力的外设连接起来
的控制器。它之所以属于外设,是因为它是在处理器的编程控制下来执行传输
的。
DMA 既可以指内存和外设直接存取数据这种内存访问的计算机技术,又可
以指实现该技术的硬件模块(对于通用计算机 PC 而言,DMA 控制逻辑由 CPU
和 DMA 控制接口逻辑芯片共同组成,嵌入式系统的 DMA 控制器内建在处理器芯
片内部,一般称为 DMA 控制器,DMAC)。
值得注意的是,通常只有数据流量较大(kBps 或者更高)的外设才需要支
持 DMA 能力,这些应用方面典型的例子包括视频、音频和网络接口。

沙发
734774645|  楼主 | 2016-11-27 19:32 | 只看该作者
一、 基本原理
直接内存访问(DMA)是一种完全由硬件执行 I/O 交换的工作方式。在这种方式中,DMA 控制器从 CPU 完全接管对总线的控制,
数据交换不经过 CPU,而直接在内存和 I/O 设备之间进行。DMA 方式一般用于高速传送成组数据。DMA 控制器将向内存发出地址和控
制信号,修改地址,对传送的字的个数计数,并且以中断方式向 CPU 报告传送操作的结束。
DMA 方式的主要优点是速度快。由于 CPU 根本不参加传送操作,因此就省去了 CPU 取指令、取数、送数等操作。在数据传送过
程中,没有保存现场、恢复现场之类的工作。内存地址修改、传送字个数的计数等等,也不是由软件实现,而是用硬件线路直接实现
的。所以 DMA 方式能满足高速 I/O 设备的要求,也有利于 CPU 效率的发挥。
多种 DMA 至少能执行以下一些基本操作:
1) 从外围设备发出 DMA 请求;
2) CPU 响应请求,把 CPU 工作改成 DMA 操作方式,DMA 控制器从 CPU 接管总线的控制;
3) 由 DMA 控制器对内存寻址,即决定数据传送的内存单元地址及数据传送个数的计数,并执行数据传送的操作;
4) 向 CPU 报告 DMA 操作的结束;
注意:在 DMA 方式中,一批数据传送前的准备工作,以及传送结束后的处理工作,均由管理程序承担,而 DMA 控制器仅负责数据传送
的工作。
二、 传送方式
DMA 技术的出现,使得外围设备可以通过 DMA 控制器直接访问内存,与此同时,CPU 可以继续执行程序。DMA 控制器与 CPU 分
时使用内存通常采用以下三种方法:
1. 停止 CPU  访问内存
当外围设备要求传送一批数据时,由 DMA 控制器发一个停止信号给 CPU,要求 CPU 放弃对地址总线、数据总线和有关控制总线
的使用权。DMA 控制器获得总线控制权以后,开始进行数据传送。在一批数据传送完毕后,DMA 控制器通知 CPU 可以使用内存,并把
总线控制权交还给 CPU。在这种 DMA 传送过程中,CPU 基本处于不工作状态或者说保持状态。这种传送方式的时间图如下:

优点: 控制简单,它适用于数据传输率很高的设备进行成组传送。
缺点: 在 DMA 控制器访问内存阶段,内存的效能没有充分发挥,相当一部分内存工作周期是空闲的。这是因为,外围设备传送
两个数据之间的间隔一般总是大于内存存储周期,即使高速 I/O 设备也是如此。

使用特权

评论回复
板凳
734774645|  楼主 | 2016-11-27 19:34 | 只看该作者
2. 周期挪用:
当 I/O 设备没有 DMA 请求时,CPU 按程序要求访问内存;一旦 I/O 设备有 DMA 请求,则由 I/O 设备挪用一个或几个内存周期。
I/O 设备要求 DMA 传送时可能遇到两种情况:
1) 此时 CPU 不需要访问内存,如 CPU 正在执行乘法指令。由于乘法指令执行时间较长,此时 I/O 访问内存与 CPU 访问内存没有冲
突,即 I/O 设备挪用一二个内存周期对 CPU 执行程序没有任何影响。
2) I/O 设备要求访问内存时 CPU 也要求访问内存,这就产生了访问内存冲突,在这种情况下 I/O 设备访问内存优先,因为 I/O 访
问内存有时间要求,前一个 I/O 数据必须在下一个访问内存请求到来之前存取完毕。显然,在这种情况下 I/O 设备挪用一至二
个内存周期,意味着 CPU 延缓了对指令的执行,或者更明确地说,在 CPU 执行访问内存指令的过程中插入 DMA 请求,挪用了一
至二个内存周期。
这种传送方式的时间图如下:
周期挪用访问内存
与停止 CPU 访内存的 DMA 方法比较,周期挪用的方法既实现了 I/O 传送,又较好地发挥了内存和 CPU 的效率,是一种广泛采用
的方法。但是 I/O 设备每一次周期挪用都有申请总线控制权、建立总线控制权和归还总线控制权的过程,所以传送一个字对内存来说
要占用一个周期,但对 DMA 控制器来说一般要 2—5 个内存周期(视逻辑线路的延迟而定)。因此,周期挪用的方法适用于 I/O 设备读
写周期大于内存存储周期的情况。



使用特权

评论回复
地板
734774645|  楼主 | 2016-11-27 19:35 | 只看该作者
3.DMA  与 CPU  交替访内存:
如果 CPU 的工作周期比内存存取周期长很多,此时采用交替访问内存的方法可以使 DMA 传送和 CPU 同时发挥最高的效率。假设
CPU 工作周期为 1.2μs,内存存取周期小于 0.6μs,那么一个 CPU 周期可分为 C1 和 C2 两个分周期,其中 C1 供 DMA 控制器访内
存,C2 专供 CPU 访问内存。这种传送方式的时间图如下:


DMA 与 CPU 交替访问内存


使用特权

评论回复
5
734774645|  楼主 | 2016-11-27 19:37 | 只看该作者
功能描述
在阅读下面内容的时候,“PDMA”的含义等同于“DMA”,前者摘自新唐公司的 M451 官方手册,表达意思为外设直接访问内存。
直接存储器存取(PDMA)用于高速数据传输。PDMA 控制器可以从一个地址到另一个地址传输数据,无需 CPU 介入。这样做的好
处是减少 CPU 的工作量,把节省下的 CPU 资源做其他应用。PDMA 控制器包含 12 个通道,每个通道支持内存和外设之间的数据传输
和内存与内存之间的数据传输。
一、 特性
 支持 12 个可独立配置的通道。
 支持 2 种优先级选择(固定优先级(fixed priority)或轮循调度优先级(round-robin priority))。
 传输数据宽度支持 8 位,16 位,32 位。
 支持源地址与目的地址方向递增或固定,数据宽度支持字节,半字,字。
 支持软件,SPI, UART, DAC, ADC 和 PWM 请求。
 支持 Scatter-Gather 模式,通过描述符链表执行灵活的数据传输。
 支持单一和批量传输类型。
Scatter-Gather 方式是与 block DMA 方式相对应的一种 DMA 方式。
在 DMA 传输数据的过程中,要求源物理地址和目标物理地址必须是连续的。但在有的计算机体系中,如 IA,连续的存储器地址
在物理上不一定是连续的,则 DMA 传输要分成多次完成。如果传输完一块物理连续的数据后发起一次中断,同时主机进行下一块物理
连续的传输,则这种方式即为 Block DMA 方式。
Scatter-Gather 方式则不同,它是用一个链表描述物理不连续的存储器,然后把链表首地址告诉 DMAMaster。DMAMaster
传输完一块物理连续的数据后,就不用再发中断了,而是根据链表传输下一块物理连续的数据,最后发起一次中断。
很显然 Scatter-Gather 方式比 Block DMA 方式效率高。
总而言之,Scatter-Gather 模式为"分散-收集"DMA 允许在一次单一的 DMA 处理中传输资料到多个内存区域。相当于把多个
简单的 DMA 要求串在一起,目的是要减轻 CPU 的多次输出输入中断和资料复制任务。
二、 内部框图
PDMA 控制器框图
直接存储器存取(PDMA)控制器接口时钟可以通过寄存器 PDMACKEN (CLK_AHBCLK[1])使能。

使用特权

评论回复
6
734774645|  楼主 | 2016-11-27 19:39 | 只看该作者
三、 实现方式
直接存储器存取(PDMA)控制器可以从一个地址到另一个地址传输数据,无需 CPU 介入。PDMA 有 12 个独立通道,因为每次只有
一个通道工作,因此,PDMA 控制器支持两种通道优先级:固定优先级和伦循调度优先级(round-robin priority),PDMA 控制
器通道执行的优先级是从高到低的。PDMA 控制器支持两种运行模式:基本模式和 Scatter-gather 模式。基本模式用于按照一个
传输描述符链表格传输数据。Scatter-gather 模式对于每个 PDMA 都有多个传输描述符链表格,所以 PDMA 控制器通过这些表格,
实现灵活的数据传输,传输描述符链表数据结构包含了传送信息,例如:传输源地址,传输定义地址,传输计数,批量传输数据大小,
传输类型和操作模式。下图是描述符链表(DSCT)数据结构。
描述符链表入口结构
PDMA 控制器也支持单一和成组数据的传输类型,请求源可以是软件请求,接口请求,内存之间的数据传输是使用软件请求。单一传输的意思是软件或接口准备好传输一个数据(每个数据需要一次请求),批量传输的意思是软件或接口将传输多个数据(多个数据仅需一次请求)。



使用特权

评论回复
7
734774645|  楼主 | 2016-11-27 19:43 | 只看该作者
四、 通道优先级
PDMA 控制器支持两级通道优先等级,包括固定优先级和轮循调度优先级(round-robin priority)。固定优先级比轮循调度优先级(round-robin priority)的优先级别更高。如果多路通道设定为固定优先级或调度优先级(round-robin priority),高通道的优先级别也高。优先级原则如下表

PDMA 通道的优先级


五、 PDMA  操作模式
PDMA 支持两种操作模式,包括: 基本模式和 Scatter-Gather 模式。

1. 基本模式
基本模式用于执行一个描述符链表的传输模式。该模式用于内存与内存之间的数据传输或接口与内存之间的数据传输。PDMA 控
制器操作模式可以通过寄存器 OPMODE (PDMA_DSCTn_CTL[1:0], n 代表 PDMA 通道数) 设定, 默认设置是在空闲状态(OPMODE
(PDMA_DSCTn_CTL[1:0]) = 0x0),推荐用户设定描述符链表为空闲状态。如果操作模式不是空闲状态,用户重新配置通道设定
可能会引起操作错误。
用 户 必 须 填 写 传 输 计 数 寄 存 器 TXCNT (PDMA_DSCTn_CTL[29:16]) 和 传 输 宽 度 选 择 寄 存 器 TXWIDTH
(PDMA_DSCTn_CTL[13:12]), 目的地址递增大小寄存器 DAINC(PDMA_DSCTn_CTL[11:10]),源地址递增大小寄存器 SAINC
(PDMA_DSCTn_CTL[9:8]), 批 量 大 小 寄 存 器 BURSIZE (PDMA_DSCTn_CTL[6:4]) 和 传 输 类 型 寄 存 器
TXTYPE(PDMA_DSCTn_CTL[2]),那么 PDMA 控制器将在接收到请求信号后执行传输操作。如果相应的 PDMA 中断位 INTENn
(PDMA_INTEN[11:0])使能,传输完成后将给 CPU 产生一个中断,操作模式将被更新为空闲模式,如下图 24.2.3。如果软件配置
操作模式为空闲状态,PDMA 控制器不会执行任何传输,并清除这个操作请求。如果相应的 PDMA 中断位被使能,完成这个任务后也会
给 CPU 产生中断。


2. Scatter-Gather  模式
Scatter-Gather 模式是一个综合模式,通过如下图 24.2.4 描述符链表设定,可以实现灵活的数据传输。通过该模式,用户
可以实现外设的回环访问。用于多路 PDMA 任务或用于系统内存的不同位置(非相邻位置)的数据搬移。

在 Scatter-Gather 模式,这个表用于跳转到下一个表的入口。第一个任务不会做数据搬移操作。如果相应的 PDMA 中断位使
能,寄存器 TBINTDIS (PDMA_DSCTn_CTL[7])=0,完成每个任务后,将给 CPU 产生一个中断,(任务完成,TBINTDIS 位为“0”,
会插入相应的寄存器 TDIFn (PDMA_TDSTS[11:0])标志,TBINTDIS 位为“1” ,禁用 TDIFn)。
如果触发了通道 11,在 Scatter-Gather(OPMODE (PDMA_DSCTn_CTL[1:0]) = 0x10x2)模式,硬件将把寄存器
PDMA_DSCTn_NEXT (link address)和 PDMA_SCATBA (基地址)相加来获取真正的 PDMA 任务信息。例如,基地址是
0x2000_0000(PDMA_SCATBA 寄存器中仅 MSB 16 位有效),目前链接地址是 0x0000_0100(在寄存器 PDMA_DSCTn_NEXT 中,
仅 LSB 16 位(不包括[1:0])有效),那么,下一个 DSCT 的起始地址是 0x2000_0100。


描述符链表格链接单结构
上述链接列表操作是 Scatter-Gather 模式的 DSCT 状态。当加载信息结束后,将自动进入搬移数据状态。然而,如果下一个
PDMA 信息也是 Scatter-Gather 模式,当前任务结束后,硬件将抓下一个 PDMA 块信息。Scatter-Gather 模式只有在 PDMA 控
制器操作模式切换到基本模式并完成最后一次传输或者直接切换到空闲状态后才会结束。


Scatter-Gather 模式的有限状态机

使用特权

评论回复
8
734774645|  楼主 | 2016-11-27 19:45 | 只看该作者
六、 批量传输 Transfer Type  传输类型
PDMA 控制器支持两种传输模式:单一传输和批量传输模式,通过寄存器 TXTYPE (PDMA_DSCTn_CTL[2])设定。
当 PDMA 控 制 器 运 行 在 单 一 传 输 模 式 , 每 搬 移 一 个 数 据 需 要 一 次 请 求 , 当 搬 移 一 次 数 据 , 寄 存 器 TXCNT
(PDMA_DSCTn_CTL[29:16])会减 1,直到寄存器 TXCNT (PDMA_DSCTn_CTL[29:16])为 0,搬移才会完成。在该模式,寄存器
BURSIZE (PDMA_DSCTn_CTL[6:4])不用于控制搬移数据量大小。BURSIZE (PDMA_DSCTn_CTL[6:4])数值是固定的。
在批量搬移模式,PDMA 控制器搬移 TXCNT (PDMA_DSCTn_CTL[29:16])个数据,仅需一次请求。当搬移 BURSIZE
(PDMA_DSCTn_CTL[6:4]) 个数据后,寄存器 TXCNT(PDMA_DSCTn_CTL[29:16])中的数目会减去 BURSIZE。直到 TXCNT
(PDMA_DSCTn_CTL[29:16])递减为 0,搬移数据才完成。该模式用于 PDMA 控制器做批量数据的搬移,但用户需确认外设是否支持
批量数据传输。
图 24.2.6 是基本传输模式的单一传输和批量传输模式举例。在这个例子,通道 1 使用单一传输模式,TXCNT
(PDMA_DSCTn_CTL[29:16]) = 128。通道 0 使用批量传输模式,BURSIZE (PDMA_DSCTn_CTL[6:4]) = 128 并且 TXCNT
(PDMA_DSCTn_CTL[29:16]) = 256。操作顺序如下:
1) 通道 0 与通道 1 同时接收到触发信号。
2) 默认通道 1 的优先级高于通道 0;PDMA 控制器将先加载通道 1 的描述符链表并执行。但通道 1 是单一传输模式,所以 PDMA 控
制器仅传输一个数据。
3) 然后,PDMA 控制器切换到通道 0 并加载通道 0 的描述符链表。通道 0 是批量传输模式,大小是 128 个。所以,PDMA 控制器将
传输 128 个数据。
4) 当通道 0 搬运 128 个数据,通道 1 得到另一个请求信号,所以当通道 0 搬运完 128 个数据,PDMA 控制器将切回通道 1,来搬
运通道 1 的下一个数据。
5) 当通道 1 搬运完数据, PDMA 控制器切换到低优先级的通道 0 来继续搬运下一组 128 个数据。
6) 当通道 0 完成 256 次数据搬移,通道 1 完成 128 次数据搬移,PDMA 将完成数据搬移。
基本模式的单字传输和批量传输举例

使用特权

评论回复
9
734774645|  楼主 | 2016-11-27 19:46 | 只看该作者
#include "SmartM_M4.h"
/*-------------------------------------------------------*/
/* 变量区 */
/*-------------------------------------------------------*/
UINT32 PDMA_TEST_LENGTH = 64;
UINT8 g_szSrcArray[260];
UINT8 g_szDestArray[260];
UINT32 VOLATILE g_bIsTestOver = 0;
/*-------------------------------------------------------*/
/* 函数区 */
/*-------------------------------------------------------*/
/****************************************
*函数名称:main
*输 入:无
*输 出:无
*功 能:函数主体
*****************************************/
INT32 main(VOID)
{
PROTECT_REG
(
/* 系统时钟初始化 */
SYS_Init(PLL_CLOCK);
/* 串口 0 初始化 */
UART0_Init(115200);
/* 使能 PDMA 时钟源 */
CLK_EnableModuleClock(PDMA_MODULE);
)
/* 源数组内容全部初始化为字母 Q */
memset(g_szSrcArray,'Q',sizeof g_szSrcArray);
/* 使能通道 2 的 PDMA 功能 */
PDMA_Open(0x4);
/* 设置通道 2 每次传输数据的宽度为 32 位,总字节数为 64*4=256 字节 */
PDMA_SetTransferCnt(2, PDMA_WIDTH_32, PDMA_TEST_LENGTH);
/* 设置通道 2 的源地址与目的地址,源地址与目的地址增量的大小 */
PDMA_SetTransferAddr(2,
(UINT32)g_szSrcArray,
PDMA_SAR_INC,
(UINT32)g_szDestArray,
PDMA_DAR_INC);
/* 设置通道 2 用于内存外设的 PDMA 传输,不使用“分散-收集”模式 */
PDMA_SetTransferMode(2, PDMA_MEM, FALSE, 0);
/* 设置通道 2 为批量传输,每次传输 4 个数据 */
PDMA_SetBurstType(2, PDMA_REQ_BURST, PDMA_BURST_4);
/* 设置通道 2 触发的中断是 PDMA 传输完成中断 */
PDMA_EnableInt(2, PDMA_INT_TRANS_DONE);
/* 使能 PDMA NVIC 中断 */
NVIC_EnableIRQ(PDMA_IRQn);
g_bIsTestOver = 0;
/* 触发通道 2PDMA 数据传输 */
PDMA_Trigger(2);
/* 等待 PDMA 传输数据完成 */
while(g_bIsTestOver == 0);
/* 检测传输的结果 */
if(g_bIsTestOver == 1)
printf("test done...\n");
else if(g_bIsTestOver == 2)
printf("target abort...\n");
printf("Dest Array:\r\n");
printf(g_szDestArray);
/* 关闭 PDMA 模块 */
PDMA_Close();
while(1);
}
/*-------------------------------------------------------*/
/* 中断服务函数 */
/*-------------------------------------------------------*/
/****************************************
*函数名称:PDMA_IRQHandler
*输 入:无
*输 出:无
*功 能:PDMA 中断服务函数
*****************************************/
VOID PDMA_IRQHandler(VOID)
{
/* 获取 PDMA 的中断状态 */
UINT32 status = PDMA_GET_INT_STATUS();
/* 检测到 PDMA 读/写目标终止中断标志 */
if(status & 0x1)
{
/* 检测是否通道 2 收到 AHB 总线错误响应 */
if(PDMA_GET_ABORT_STS() & 0x4)
g_bIsTestOver = 2;
/* 清除所有通道 AHB 总线错误响应标志位 */
PDMA_CLR_ABORT_FLAG(PDMA_ABTSTS_ABTIFn_Msk);
}
/* 检测到 PDMA 传输完成中断标志 */
else if(status & 0x2)
{
/* 检测是否通道 2 传输数据完成 */
if(PDMA_GET_TD_STS() & 0x4)
g_bIsTestOver = 1;
/* 清除所有通道传输完成标志位 */
PDMA_CLR_TD_FLAG(PDMA_TDSTS_TDIFn_Msk);
}
else
printf("unknown interrupt !!\n");
}


使用特权

评论回复
10
734774645|  楼主 | 2016-11-27 19:50 | 只看该作者
主函数 main 分析:
a. 调用 CLK_EnableModuleClock 函数使能 PDMA 内部时钟模块。
b. 调用 PDMA_Open 函数使能通道 2 的 PDMA 功能。
c. 调用 PDMA_SetTransferCnt 函数设置通道 2 每次传输数据的宽度为 32 位,总字节数为 256 字节,即 4*64=256 字节。
d. 调用 PDMA_SetTransferAddr 函数设置通道 2 的源地址为 g_szSrcArray 数组的起始地址,目的地址为 g_szDestArray
数组的起始地址。由于此前设置传输的数据宽度为 32 位,因此源地址增量的大小每次为 4 字节,目的地址增量的大小同样每次
为 4 字节。
e. 调用 PDMA_SetBurstType 函数设置通道 2 为批量传输,每次传输 4 个数据。
f. 调用 PDMA_EnableInt 函数使能通道 2 传输完成中断。
g. 调用 NVIC_EnableIRQ 函数使能 PDMA NVIC 中断。
h. 一切就绪后,调用 PDMA_Trigger 函数触发通道 2PDMA 数据传输。
i. 检测 g_bIsTestOver 变量是否已被置位,若 g_bIsTestOver 被置为 1 则传输数据完成;若 g_bIsTestOver 被置为 2 则传
输数据中止。
j. 若不再使用 PDMA 功能,则调用 PDMA_Close 函数关闭 PDMA 功能。

使用特权

评论回复
11
wanduzi| | 2018-9-28 20:16 | 只看该作者
多谢,我还以为新的一个接口呢,原来是同一个

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

185

主题

3408

帖子

14

粉丝