一、DMA简介

  DMA,全称为:Direct Memory Access,即直接存储器访问,DMA 用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当 CPU 初始化这个传输动作,传输动作本身是由DMA 控制器 来实行和完成。DMA 传输对于高效能嵌入式系统算法和网络是很重要的。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。STM32 最多有 2 个 DMA 控制器(DMA2 仅存在大容量产品中),DMA1 有 7 个通道,DMA2 有 5个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个 DMA 请求的优先权。

  从外设(TIMx、ADC、SPIx、I2Cx 和 USARTx)产生的 DMA 请求,通过逻辑或输入到DMA 控制器,这就意味着同时只能有一个请求有效。外设的 DMA 请求,可以通过设置相应的外设寄存器中的控制位,被独立地开启或关闭。

表1 DMA各通道一览表

  逻辑或是指通道 1 的几个 DMA1 请求(ADC1、 TIM2_CH3、 TIM4_CH1),这几个是通过逻辑或到通道 1 的,这样我们在同一时间,就只能使用其中的一个。其他通道也是类似的。

二、DMA寄存器

  注意: 在以下列举的所有寄存器中,所有与通道6和通道7相关的位,对DMA2都不适用,因为DMA2只有5个通道。

 1、DMA 中断状态寄存器(DMA_ISR)

  如果开启了 DMA_ISR 中这些中断,在达到条件后就会跳到中断服务函数里面去,如果没开启,我们也可以通过查询这些位来获得当前 DMA 传输的状态。这里常用的是TCIFx,即通道 DMA 传输完成与否的标志。注意此寄存器为只读寄存器,所以在这些位被置位之后,只能通过其他的操作来清除。

 2、DMA 中断标志清除寄存器(DMA_IFCR)。

图2 DMA_IFCR 寄存器

  DMA_IFCR 的各位就是用来清除 DMA_ISR 的对应位的,通过写 0 清除。在 DMA_ISR 被置位后,我们必须通过向该位寄存器对应的位写入 0 来清除。

三、库函数下 DMA1 通道 4 的配置步骤:

  1、使能 DMA 时钟

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能 DMA 时钟

  2、初始化 DMA 通道 4 参数

  DMA 通道配置参数种类比较繁多,包括内存地址,外设地址,传输数据长度,数据宽度,通道优先级等等。这些参数的配置在库函数中都是在函数 DMA_Init 中完成,下面我们看看函数定义:

    void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,DMA_InitTypeDef* DMA_InitStruct)

  函数的第一个参数是指定初始化的 DMA 通道号,主要看看第二个参数。跟其他外设一样,同样是通过初始化结构体成员变量值来达到初始化的目的,下面看看 DMA_InitTypeDef 结构体的定义:
  typedef struct
  {
    uint32_t DMA_PeripheralBaseAddr;
    uint32_t DMA_MemoryBaseAddr;
    uint32_t DMA_DIR;
    uint32_t DMA_BufferSize;
    uint32_t DMA_PeripheralInc;
    uint32_t DMA_MemoryInc;
    uint32_t DMA_PeripheralDataSize;
    uint32_t DMA_MemoryDataSize;
    uint32_t DMA_Mode;
    uint32_t DMA_Priority;
    uint32_t DMA_M2M;
  }DMA_InitTypeDef;

  这个结构体的成员比较多,但是每个成员变量的意义在前面基本都已经提到过,再做个简要的介绍。

  第一个参数 DMA_PeripheralBaseAddr 用来设置 DMA 传输的外设基地址,比如要进行串口DMA 传输,那么外设基地址为串口接受发送数据存储器 USART1->DR 的地址,表示方法为&USART1->DR。

  第二个参数 DMA_MemoryBaseAddr 为内存基地址,也就是我们存放 DMA 传输数据的内存地址。

  第三个参数 DMA_DIR 设置数据传输方向,决定是从外设读取数据到内存还送从内存读取数据发送到外设,也就是外设是源地还是目的地,这里我们设置为从内存读取数据发送到串口,所以外设自然就是目的地了,所以选择值为 DMA_DIR_PeripheralDST。

  第四个参数 DMA_BufferSize 设置一次传输数据量的大小,这个很容易理解。

  第五个参数 DMA_PeripheralInc 设置传输数据的时候外设地址是不变还是递增。如果设置为递增,那么下一次传输的时候地址加 1,这里因为我们是一直往固定外设地址&USART1->DR发送数据,所以地址不递增,值为 DMA_PeripheralInc_Disable;

  第六个参数 DMA_MemoryInc 设置传输数据时候内存地址是否递增。 这个参数和DMA_PeripheralInc 意思接近,只不过针对的是内存。这里我们的场景是将内存中连续存储单元的数据发送到串口,毫无疑问内存地址是需要递增的,所以值为 DMA_MemoryInc_Enable。

  第七个参数 DMA_PeripheralDataSize 用来设置外设的数据长度是为字节传输(8bits) ,半字传输 (16bits) 还是字传输 (32bits) ,这里我们是 8 位字节传输,所以 值设置为DMA_PeripheralDataSize_Byte。

  第八个参数 DMA_MemoryDataSize 是用来设置内存的数据长度,和第七个参数意思接近,这里我们同样设置为字节传输 DMA_MemoryDataSize_Byte。

  第九个参数 DMA_Mode 用来设置 DMA 模式是否循环采集,也就是说,比如我们要从内存中采集 64 个字节发送到串口,如果设置为重复采集,那么它会在 64 个字节采集完成之后继续从内存的第一个地址采集,如此循环。这里我们设置为一次连续采集完成之后不循环。所以设置值为 DMA_Mode_Normal。在我们下面的实验中,如果设置此参数为循环采集,那么你会看到串口不停的打印数据,不会中断,大家在实验中可以修改这个参数测试一下。

  第十个参数是设置 DMA 通道的优先级,有低,中,高,超高三种模式,这个在前面讲解过,这里我们设置优先级别为中级,所以值为 DMA_Priority_Medium。如果要开启多个通道,那么这个值就非常有意义。

  第十一个参数 DMA_M2M 设置是否是存储器到存储器模式传输,这里我们选择DMA_M2M_Disable。

  这里给出上面场景的实例代码:
  DMA_InitTypeDef DMA_InitStructure;
  DMA_InitStructure.DMA_PeripheralBaseAddr = &USART1->DR; //DMA 外设 ADC 基地址
  DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA 内存基地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //从内存读取发送到外设
  DMA_InitStructure.DMA_BufferSize = 64; //DMA 通道的 DMA 缓存的大小
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不变
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址递增
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //8 位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 8 位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA 通道 x 拥有中优先级
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非内存到内存传输
  DMA_Init(DMA_CHx, &DMA_InitStructure); //根据指定的参数初始化
  

 3、使能串口 DMA 发送

  进行 DMA 配置之后,我们就要开启串口的 DMA 发送功能,使用的函数是:
    USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
  如果是要使能串口 DMA 接受,那么第二个参数修改为 USART_DMAReq_Rx 即可。

 4、使能 DMA1 通道 4,启动传输。

  使能串口 DMA 发送之后,我们接着就要使能 DMA 传输通道:
    DMA_Cmd(DMA_CHx, ENABLE);
  通过以上 3 步设置,我们就可以启动一次 USART1 的 DMA 传输了。

 5、查询 DMA 传输状态

  在 DMA 传输过程中,我们要查询 DMA 传输通道的状态,使用的函数是:
    FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)
  比如我们要查询 DMA 通道 4 传输是否完成,方法是:
    DMA_GetFlagStatus(DMA2_FLAG_TC4);
  这里还有一个比较重要的函数就是获取当前剩余数据量大小的函数:
    uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx)
  比如我们要获取 DMA 通道 4 还有多少个数据没有传输,方法是:
    DMA_GetCurrDataCounter(DMA1_Channel4);
  DMA 相关的库函数更详细的资料可以查看固件库中文手册。

转载于:https://www.cnblogs.com/microxiami/p/3740935.html

STM32学习笔记——DMA控制器(向原子哥学习)相关推荐

  1. 一文弄懂元学习 (Meta Learing)(附代码实战)《繁凡的深度学习笔记》第 15 章 元学习详解 (上)万字中文综述

    <繁凡的深度学习笔记>第 15 章 元学习详解 (上)万字中文综述(DL笔记整理系列) 3043331995@qq.com https://fanfansann.blog.csdn.net ...

  2. 【C++学习笔记】CAD中环的偏移学习

    [C++学习笔记]CAD中环的偏移学习 最近一直在研究CAD中偏移命令的实现,奈何自己没有技术,就上网找了一个[1]作为记录. #include <iostream> #include & ...

  3. 七、PHP框架Laravel学习笔记——资源控制器

    一.资源控制器 声明:资源控制器是某个特定场景下的产物,完全理解需要 PHP 项目基础: 比如开发过博客系统,留言帖子系统之类,具有类似思维,否则你懂的-: 只是学习了 PHP 基础,就立刻学习框架的 ...

  4. 视觉SLAM十四讲学习笔记-第四讲---第五讲学习笔记总结---李群和李代数、相机

    第四讲---第五讲学习笔记如下: 视觉SLAM十四讲学习笔记-第四讲-李群与李代数基础和定义.指数和对数映射_goldqiu的博客-CSDN博客 视觉SLAM十四讲学习笔记-第四讲-李代数求导与扰动模 ...

  5. jboss esb 学习笔记与html的传输,Jboss_ESB学习笔记1.doc

    Jboss_ESB学习笔记1 JBoss ESB学习笔记1--搭建ESB开发环境 最近由于工作需要用到了JBoss ESB,可在网上这方面的资料实在少的让人不敢恭维,而JBoss ESB的官方文档对初 ...

  6. 《深度学习笔记》——listnumpy索引操作的学习笔记

    1 致谢 感谢网友粗面鱼丸提供的资料, 原文链接:https://www.cnblogs.com/subic/p/8710946.html 2 初始python中的索引操作 2.1 单次索引x[0:2 ...

  7. 风变编程python第一关_风变编程【学习笔记】,第8关学习心得及代码扩展

    新手入门学习python   过程必定有很多疑惑和不理解的地方 我会慢慢更新前8关和后面课程的学习笔记及心得,争取用我自己踩过的雷和出现错误的地方,给大家提个醒 第8关,没有很多知识点,主要是告诉大家 ...

  8. 《强化学习与最优控制》学习笔记(三):强化学习中值空间近似和策略空间近似概述

    写在前面的 前一章链接: <强化学习与最优控制>学习笔记(二):强化学习与最优控制的一些术语对比 这章主要是对应书中第二章前面的值空间近似和策略空间近似的简要介绍部分. 在本书的第一章就指 ...

  9. 【学习笔记】React+React全家桶学习笔记

    文章目录 1 为什么要使用React 2 React的定义 3 React的三大特性 4 React入门 4.1 hello_react 4.2 虚拟DOM的创建 4.3 JSX 4.4 模块与组件, ...

最新文章

  1. WebService之soap类型的服务和rest类型的服务
  2. treeview托拽和动态添加节点以及treeview和xml的交互的实现
  3. 「推荐系统」 领域的最新进展你知道么?
  4. Redis之Redis内存模型
  5. 结合案件要素序列的罪名预测方法
  6. python中os模块里有哪些类_python-os模块的常用方法
  7. 微星小飞机界面翻译_6 款实用小程序良心推荐,每一款都好用
  8. 用VC2013编译了一个程序,在Windows 8、Windows 7(64位、32位)下都能正常运行。但在Win XP,Win2003下运行时,却报错不能运行
  9. python采集数据搭建小说网站_Python制作爬虫采集小说
  10. 数据库技术与应用课程设计-学生信息管理系统
  11. Zune支持哪些格式?
  12. CATIA V5-6 R2017 支架类零件设计
  13. prisma 连接不上Postgres
  14. 需求预测——Predicting origin-destination ride-sourcing demand with a spatio-temporal encoder-decoder
  15. 云南省科协第十届学术年会在曲靖开幕
  16. 有12个球,外形相同,其中一个小球的质量与其他11个不同,给一个天平,需要几次把这个小球找出来并且求出这个小球是比其他的轻还是重
  17. 关于2022年宣城市集成电路布图设计登记有效期及收费相关说明
  18. 服务器内存与CPU的搭配
  19. 实习时候的亚子==(四)
  20. Python---陈氏绘制雷达图

热门文章

  1. mysql自增主键归零的方法
  2. C#有关Session 操作的几个误区【转】
  3. questions for the exploitation of technologies
  4. 图书馆access的Google chrome 插件
  5. 三星的typec可以充MacBook
  6. 1970.1.1这个特殊时间
  7. C#中的默认访问修饰符
  8. Flutter 填坑之 表单数据哪里去了?
  9. poj 2683 Ohgas#39; Fortune 利率计算
  10. 《淘宝店铺 大数据营销+SEO+爆款打造 一册通》一一2.2 实时直播抢占生意先机...