SAM4E单片机之旅——20、DMAC之使用Multi-buffer进行内存拷贝
这次使用这个DMAC的Multi-buffer传输功能,将两个缓冲区的内容拷贝至一个连续的缓冲区中。
一、 DMAC
在M4中,DMA控制器(DMAC)比外设DMA控制器(PDC)要复杂,但是功能更加强大。
为适应不同的传输要求,DMAC 可以进行灵活的自定义配置,甚至配备了一个FIFO缓存。比如可以为源设备和目标设备分别设定传输时,地址的变动方式(递增、递减或固定);以及一次传输的数据量(字节、半字或字)。
DMAC有4个通道,每个通道可以进行一个传输任务。进行传输的设备可分为“内存”及“非内存”:内存表示随时可以对该设备进行访问,而非内存表示需要一个信号(握手接口)来触发或控制对设备的访问。握手接口可以选择硬件或软件的,并且可以在传输的过程中动态配置。
另外,比起PDC只能设置下一次传输的参数(传输地址,数据量大小等),DMAC可以先在内存中保存好若干次传输的参数,然后自动进行多次传输(Multi-buffer传输)。
二、 Multi-buffer传输的实现机制
每个通道有若干个寄存器。其中:源地址和目的地址寄存器(SADDR和DADDR),描述符地址寄存器(DSCR),控制器存器(CTRLA和CTRLB)这几个寄存器可以根据需要进行自动修改。在内存中有一块区域(LLI),连续地储存着这几个寄存器的目标设置。然后就像一个链表一样,DSCR表示下一个区域的地址:
在启用通道时,如果DSCR为0,则表示只需进行一次传输,在传输完成后就关闭通道。
如果DSCR不为0,则表示进行多次传输,而这几个寄存器的更新过程如下:
获取DSCR指向的LLI的内容。如果DSCR为0,则任务结束。
根据当前CTRLB寄存器的内容,判断是否需要根据该LLI更新SADDR及DADDR。然后根据该LLI更新其余寄存器(CTRLA,CTRLB,DSCR)。
根据新的寄存器内容进行传输。
传输完成后,将CTRLA的内容回写至内存中(传输中仅有该寄存器的BTSIZE和DONE字段会发生该变)。
根据通道CFG寄存器的Stop On Done(SOD)字段判断是否需要重新执行以上过程。
所以,在启用通道前,除了要设置好CFG寄存器外,也需要设置好CTRLB。
三、 实现思路
重申一下目标:将两个缓冲区的内容拷贝至一个连续的缓冲区中。
由于源缓冲区有两个,所以我们将使用两个LLI。其中每个LLI的SADDR指向每个源缓冲区的首地址,并且在每次获取LLI时,更新SADDR。而由于目标缓冲区是连续的,所以不需要更新DADDR。
然后在启用通道前,设置好DADDR。同时,设置CTRLB,该通道不从LLI中更新DADDR地址;设置好DSCR,使其指向第一个LLI。
四、 使用LLI
定义LLI结构体。
LLI的内存布局不复杂,但是使用结构体来进行操作也很有助于简化工作。而且由于布局简单,也不用太关注内存对齐的细节。(另外,在使用LLI时,需要它的地址是字对齐的。)
typedef struct _lli{
uint32_t SADDR;
uint32_t DADDR;
uint32_t CTRLA;
uint32_t CTRLB;
uint32_t DSCR;
}LLI;LLI的初始化。
由于两个LLI的设置有许多相同的部分,所以将共同的部分抽象出来。
// lli: 需要初始化的LLI的地址
// saddr: 源地址
// btsize: 传输次数
// next_lli: 下一个LLI的地址。如果是最后一个LLI,该参数为NULL即可
void InitLLI(LLI* lli, void* saddr, uint16_t btsize, LLI* next_lli)
{
lli->SADDR = (uint32_t)saddr;
lli->DADDR = 0; // DADDR 不会被使用,初始化为即可
lli->DSCR = DMAC_DSCR_DSCR_Msk & (uint32_t)next_lli;
lli->CTRLA =
DMAC_CTRLA_BTSIZE(btsize) // 传输次数
| DMAC_CTRLA_SRC_WIDTH_WORD // 源设备一次传输一个字
| DMAC_CTRLA_DST_WIDTH_WORD // 目标设备一次传输一个字
;
lli->CTRLB =
DMAC_CTRLB_SRC_DSCR_FETCH_FROM_MEM // 从LLI中更新SRC地址
| DMAC_CTRLB_DST_DSCR_FETCH_DISABLE // 不更新DST地址
| DMAC_CTRLB_FC_MEM2MEM_DMA_FC // 设备类型:内存至内存
| DMAC_CTRLB_SRC_INCR_INCREMENTING // 传输时,源地址递增
| DMAC_CTRLB_DST_INCR_INCREMENTING // 传输时,目标地址递增
;
}
五、 实现过程
缓冲区。
// 源缓冲区
uint32_t src1[2];
uint32_t src2[3];
// 目标缓冲区
uint32_t dst[5];
// 向源缓冲区时填充内容
src1[0] = 50; src1[1] = 51;
src2[0] = 52; src2[1] = 53; src2[2] = 54;设置LLI。
注意,要确保LLI的实例在整个程序的运行过程中都是有效的。比如如果LLI是储存在函数的栈中的话,那么函数退出后,该LLI即无效了。所以可以选择在堆中分配LLI实例的空间,或是将其定义为全局变量,也可以在main函数中定义实例。
LLI first_lli, last_lli;
InitLLI(&first_lli, (void*)src1, 2, &last_lli);
InitLLI(&last_lli, (void*)src2, 3, 0);启用DMAC。
// PMC
PMC->PMC_PCER0 = 1 << ID_DMAC;
DMAC->DMAC_GCFG =
DMAC_GCFG_ARB_CFG_ROUND_ROBIN; // 轮转优先级
DMAC->DMAC_EN = DMAC_EN_ENABLE;配置通道。
// 使用的通道为通道0
#define DMAC_CH 0
// 使DSCR指向first_lli
DMAC->DMAC_CH_NUM[DMAC_CH].DMAC_DSCR =
(uint32_t)(void*)(&first_lli);
// 设置目标地址
DMAC->DMAC_CH_NUM[DMAC_CH].DMAC_DADDR =
(uint32_t)(void*) dst;
// 设置CTRLB,使通道从LLI中更新源地址
DMAC->DMAC_CH_NUM[DMAC_CH].DMAC_CTRLB =
DMAC_CTRLB_SRC_DSCR_FETCH_FROM_MEM
| DMAC_CTRLB_DST_DSCR_FETCH_DISABLE;
// 配置CFG寄存器
DMAC->DMAC_CH_NUM[DMAC_CH].DMAC_CFG =
DMAC_CFG_SOD_DISABLE
| DMAC_CFG_FIFOCFG_ALAP_CFG
;启用通道。
DMAC->DMAC_CHER = DMAC_CHER_ENA0 << DMAC_CH;
等待通道关闭,即传输完成。
const uint32_t check_bit = DMAC_CHSR_ENA0 << DMAC_CH;
while( (DMAC->DMAC_CHSR & check_bit) != 0);
SAM4E单片机之旅——20、DMAC之使用Multi-buffer进行内存拷贝的更多相关文章
- SAM4E单片机之旅——21、DMAC之USART回显
DMAC也可以和外设进行数据交互.之前我们曾使用PDC进行USART的数据回显,这次就使用DMAC完成相同的工作.而且由于DMAC有内部的缓冲区,实现起来更为简单. 一. USART设置 因为之前已经 ...
- SAM4E单片机之旅——23、在AS6(GCC)中使用FPU
浮点单元(Floating Point Unit,FPU),是用于处理浮点数运算的单元. 为使用FPU,除了需要启用FPU外,还需要对编译器进行设置,以使其针对浮点运算生成特殊的指令.虽然在Atmel ...
- SAM4E单片机之旅——18、通过AFEC(ADC)获取输入的电压
很多时候,一个电压不仅仅需要定性(高电平或者低电平),而且要定量(了解具体电压的数值).这个时候就可以用到模数转换器(ADC)了.这次的内容是测量开发板搭载的滑动变阻器(VR1)的电压,然后把ADC转 ...
- SAM4E单片机之旅——24、使用DSP库求向量数量积
DSP(Digital Signal Processing,数字信号处理)中会使用大量的数学运算.Cortex-M4中,配置了一些强大的部件,以提高DSP能力.同时CMSIS提供了一个DSP库,提供了 ...
- SAM4E单片机之旅——22、GMAC和PHY的介绍与初始化
网络通信的作用不用多说,而这次进行的工作即是对以太网通信过程中,需要用到的硬件部分进行初始化,也介绍了发送和接收数据的方法. 由于较为复杂,所以使用了ASF框架.但是也会对用到的库函数的实现做一个介绍 ...
- SAM4E单片机之旅——13、LCD之ASF初步
在Atmel Studio 6中,集成了Atmel Software Framework(ASF框架).通过它提供的库,可以很快速地完成新的项目. 这次的最终目标使用ASF在LCD上显示出文字“Hel ...
- SAM4E单片机之旅——9、UART与MCK之MAINCK
为得到更高的带宽,需要使用更高的波特率.UART波特率的计算已经介绍过了,现在就尝试下调整外设的时钟频率.可以有多种方法调整外设时钟(MCK)的频率,这里先介绍先主要时钟(MAINCK)的设置,其中包 ...
- SAM4E单片机之旅——3、LED闪烁之定时器中断
让一个LED灯闪烁不过瘾,我们应该让这块开发板完成一点更高难度的任务:比如让两个LED灯闪烁. …… 当然了,以我们的现在使用的空循环技术,还是可以实现这点的.但是这样显得略为低端.所以我们使用一个高 ...
- SAM4E单片机之旅——2、LED闪烁之轮询定时器
之前我们使用空循环,达到了延迟的目的,但是这样子的延迟比较不精确.现在就使用实时定时器(RTT)来进行更为精确的计时.RTT虽然不是特别通用,在某些单片机上可能没有,但它较为简单. RTT内部有一个计 ...
随机推荐
- HashMap的实现原理
1.HashMap的数据结构 数组的特点是:寻址容易,插入和删除困难:而链表的特点是:寻址困难,插入和删除容易.那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的, ...
- MyBatis魔法堂:ResultMap详解
一.前言 MyBatis是基于“数据库结构不可控”的思想建立的,也就是我们希望数据库遵循第三范式或BCNF,但实际事与愿违,那么结果集映射就是MyBatis为我们提供这种理想与现实间转换的手段了, ...
- mysql一个事务中有DDL语句的binlog情况
在autocommit=1的情况下,开启一个事务,如果里面有DDL语句,那么事务开始到DDL语句之间的DML语句都会被提交.再开启新的事务.可以从binlog中看出 session语句: 09 ...
- [课程设计]Scrum日记本项目进度
Sprint 1时间:11.14-11.23 冲刺一这一阶段中主要实现的是界面和互交(已实现这两个功能) 燃尽图: 项目进度: 第一阶段:现阶段已经实现界面和互交. 第二阶段:进行填入信息,并记录日期 ...
- DataGridView隐藏列用CSS实现
隐藏DataGridView某一列,用CSS控制 CSS Code: .hidden{ display:none;} c# Code: <asp:BoundField DataField=&qu ...
- Python入门笔记(26):Python执行环境
一.python特定的执行环境 在当前脚本继续进行 创建和管理子进程 执行外部命令或程序 执行需要输入的命令 通过网络来调用命令 执行命令来创建需要处理的输出 动态生成Python语句 导入Pytho ...
- SqlServer 2008 R2定时备份数据库,并且发送邮件通知
先配置数据库的邮件设置,这样才可以发送邮件. 2. 3. 4. 5. 6. 7. 8. 9. 10. 总的预览图,如图 执行这一段(先发送备份邮件,然后进行数据备份,将昨天的发送数据插入到另一张表中, ...
- jquery fadeOut 异步
1. 概述 jquery实现动画效果的函数使用起来很方便,不过动画执行是异步的, 所以要把自定义的操作放在回调函数里. 2. example <html> <body> < ...
- Form.action传值问题
通过浏览器地址栏输入url并通过?传递参数请求资源时,?后面的参数叫做 "查询字符串",会触发后台Servlet的doGet(),因为通过浏览器地址栏直接访问的方式是GET方式. ...
- SharePoint 禁用本地回环的两个方法
有两种方法中,若要变通解决此问题,请根据您的具体情况使用下列方法之一. 方法 1: 指定主机名 (如果需要 NTLM 身份验证,请首选方法) 指定的主机名的映射到环回地址,并可以连接到 Web 站点在 ...