这次使用这个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,则表示进行多次传输,而这几个寄存器的更新过程如下:

  1. 获取DSCR指向的LLI的内容。如果DSCR为0,则任务结束。

  2. 根据当前CTRLB寄存器的内容,判断是否需要根据该LLI更新SADDR及DADDR。然后根据该LLI更新其余寄存器(CTRLA,CTRLB,DSCR)。

  3. 根据新的寄存器内容进行传输。

  4. 传输完成后,将CTRLA的内容回写至内存中(传输中仅有该寄存器的BTSIZE和DONE字段会发生该变)。

  5. 根据通道CFG寄存器的Stop On Done(SOD)字段判断是否需要重新执行以上过程。

所以,在启用通道前,除了要设置好CFG寄存器外,也需要设置好CTRLB

三、 实现思路

重申一下目标:将两个缓冲区的内容拷贝至一个连续的缓冲区中。

由于源缓冲区有两个,所以我们将使用两个LLI。其中每个LLI的SADDR指向每个源缓冲区的首地址,并且在每次获取LLI时,更新SADDR。而由于目标缓冲区是连续的,所以不需要更新DADDR。

然后在启用通道前,设置好DADDR。同时,设置CTRLB,该通道不从LLI中更新DADDR地址;设置好DSCR,使其指向第一个LLI。

四、 使用LLI

  1. 定义LLI结构体。

    LLI的内存布局不复杂,但是使用结构体来进行操作也很有助于简化工作。而且由于布局简单,也不用太关注内存对齐的细节。(另外,在使用LLI时,需要它的地址是字对齐的。)

    typedef struct _lli{uint32_t SADDR;uint32_t DADDR;uint32_t CTRLA;uint32_t CTRLB;uint32_t DSCR;
    }LLI;
  2. 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   // 传输时,目标地址递增;
    }

五、 实现过程

  1. 缓冲区。

    // 源缓冲区
    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;
  2. 设置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);
  3. 启用DMAC。

    // PMC
    PMC->PMC_PCER0 = 1 << ID_DMAC;
    DMAC->DMAC_GCFG =DMAC_GCFG_ARB_CFG_ROUND_ROBIN; // 轮转优先级
    DMAC->DMAC_EN = DMAC_EN_ENABLE;
  4. 配置通道。

    // 使用的通道为通道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;
  5. 启用通道。

    DMAC->DMAC_CHER = DMAC_CHER_ENA0 << DMAC_CH;
  6. 等待通道关闭,即传输完成。

    const uint32_t check_bit = DMAC_CHSR_ENA0 << DMAC_CH;
    while( (DMAC->DMAC_CHSR & check_bit) != 0);

转载于:https://www.cnblogs.com/h46incon/p/3505385.html

SAM4E单片机之旅——20、DMAC之使用Multi-buffer进行内存拷贝相关推荐

  1. SAM4E单片机之旅——13、LCD之ASF初步

    在Atmel Studio 6中,集成了Atmel Software Framework(ASF框架).通过它提供的库,可以很快速地完成新的项目. 这次的最终目标使用ASF在LCD上显示出文字&quo ...

  2. SAM4E单片机之旅——10、UART与MCK之PLL

    为使用更更高的波特率,则需要更更高的外设时钟的频率.这个时候就需要用到锁相环(PLL)了.锁相环可以对输入的时钟进行分频.升频后进行输出.MCK可以使用的锁相环为PLLA,而PLLA的输入时钟为MAI ...

  3. 小猪的Python学习之旅 —— 20.抓取Gank.io所有数据存储到MySQL中

    小猪的Python学习之旅 -- 20.抓取Gank.io所有数据存储到MySQL中 标签:Python 一句话概括本文: 内容较多,建议先mark后看,讲解了一波MySQL安装,基本操作,语法速成, ...

  4. 从51开始的单片机之旅(一)----流水灯、矩形键盘、电子时钟

    说一下个人的学习经历 我做过的项目: 今天先把当初做的89E51总结出来 先说下89E51 一.流水灯.数码管 二.矩阵键盘,蜂鸣器和电子时钟 结语: 说一下个人的学习经历 我是大二开始进入学校电子设 ...

  5. 弹性法计算方法的mck法_SAM4E单片机之旅——9、UART与MCK之MAINCK

    为得到更高的带宽,需要使用更高的波特率.UART波特率的计算已经介绍过了,现在就尝试下调整外设的时钟频率.可以有多种方法调整外设时钟(MCK)的频率,这里先介绍先主要时钟(MAINCK)的设置,其中包 ...

  6. 从51开始的单片机之旅(二)----LCD1602液晶、ADC0809、DAC0832

    说在前面 上篇已经把流水灯.矩形键盘.电子时钟已经总结完了,今天来总结89E51的LCD1602液晶.ADC0809.DAC0832的相关内容 说在前面 一.基本原理介绍 二.原器件介绍 三.设计及接 ...

  7. 【C++探索之旅】第一部分第四课:内存,变量和引用

    内容简介 1.第一部分第四课:内存,变量和引用 2.第一部分第五课预告:简易计算器 内存,变量和引用 上一课<[C++探索之旅]第一部分第三课:第一个C++程序>中,我们已经学习了如何创建 ...

  8. 【漫画+图解】面试官让我用 2GB 内存给 20亿个整数(需要8GB内存)排序,我该咋整??

    排序的时候我们可以选择快速排序或归并排序等算法.为了方便,我们把排序好的2G有序数据称之为有序子串吧.接着我们可以把两个小的有序子串合并成一个大的有序子串. 注意:读取的时候是每次读取一个int数,通 ...

  9. d3力导向图增加节点_D3.js+Es6+webpack构建人物关系图(力导向图),动态更新数据,点击增加节点,拖拽增加连线......

    Java学习手记2--多线程 一.线程的概念 CPU执行程序,就好比一个人在干事情一样,同一个时间你只能做一件事情,但是这样的效率实在是太低了,在你用电脑的时候,听歌就不能浏览网页,看电影就不能下载视 ...

  10. html 5音乐界面控制,使用按钮控制HTML5背景音乐开关

    演示:使用按钮控制HTML5背景音乐开关 你的浏览器不支持audio标签. $("#audio_btn").click(function() { var music = docum ...

最新文章

  1. AI居然能算出情侶能交往多久?使用分析语音数据進行預測
  2. 【回文自动机】bzoj3676 [Apio2014]回文串
  3. 循序渐进linux——基础知识、服务器搭建、系统管理、性能调优、集群应用_第四讲,Proxmox部署与应用...
  4. eps如何建立立体白模_从几个方面说说自动化立体仓库的特别之处
  5. ZOJ2930 The Worst Schedule(最小割)
  6. python前n项和存为一个数组_在Python中存储多个数组
  7. GitHub 标星8.6K:将任何设备转换为电脑的辅助屏幕
  8. MaterialDesign之NavigationView和DrawerLayout实现侧滑菜单栏
  9. 各种排序算法稳定性的探讨
  10. mysql limti_MYSQL分页 limint
  11. 缓存穿透、缓存击穿、缓存雪崩概念及解决方案
  12. pg数据库中读取json
  13. 云栖·武汉峰会 | 现场:阿里云为何频打“自研”牌?
  14. GIS基础(3)火星坐标系?
  15. go,go语言编辑器安装,git安装,即vscode三个插件的安装
  16. 【渗透测试】常用工具总结
  17. 【Git】rebase 用法小结
  18. 图灵4月书讯【黑客与画家将在4月10日左右隆重上市】
  19. Kenney Assets - 提供数以万计免费商用的游戏制作素材下载,包括 2d、3d素材,游戏音效和游戏 UI
  20. 信号与系统复习归纳(十一):Z变换+例题

热门文章

  1. 2021年度汇总丨20大热门TWS耳机功能配置汇总解析
  2. 魅蓝metal刷android 6,魅蓝metal刷机包 Flyme 6.1.0.0Y稳定版 对系统稳定性和功耗表现进行了特定优化...
  3. EXCEL的COUNTIF和COUNTIFS函数的区别和联系
  4. 计算机无法传输文件,qq无法传输文件_电脑文件无法通过QQ发送怎么办
  5. Anchor和目标检测中的理论感受野和实际感受野的关系
  6. 纯CSS实现四种方式文本反差色效果
  7. Android基础篇-DrawerLayout 实现侧滑
  8. CentOS 用Strongswan搭建IPSec ***
  9. 3D hand pose:BMC
  10. 基于element-ui的Vue计算工作日组件