16、DMA直接存储区访问

news2024/12/24 9:23:21

0x01、DMA简介

DMA(Direct Memory Access)一直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以于其他的事情,好像是多线程一样数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是FLASH。DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1有7个通道,DMA2有5个通道,这里的通道可以理解为传输数据的一种管道。要注意的是DMA2只存在于大容量的单片机中。

0x02、DMA功能框图

DMA 控制器独立于内核,属于一个单独的外设,结构比较简单,从编程的角度来看,我们只需掌握功能框图中的三部分内容即可,具体见图 DMA 框图: DMA控制器的框图。

0x0001、DMA请求

如果外设要想通过 DMA 来传输数据,必须先给 DMA 控制器发送 DMA 请求,DMA 收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到传输完毕。

0x0002、通道

DMA 具有12个独立可编程的通道,DMA有DMA1和DMA2 两个控制器,其中 DMA1有7个通道,DMA2有5个通道,每个通道对应不同的外设的 DMA 请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

DMA1有7个通道,DMA2有5个通道,不同的DMA控制器的通道对应着不同的外设请求,这决定了我们在软件编程上该怎么设置,具体见 DMA 请求映像表

DMA1表:

DMA2表:

 

 其中ADC3、SDIO 和 TIM8 的 DMA 请求只在大容量产品中存在,这个在具体项目时要注意。

 0x0003、仲裁器

当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在 DMA_CCRx 寄存器中设置,有4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高比如通道0高于通道 1。在大容量产品和互联型产品中,DMA 控制器拥有高于 DMA2 控制器的优先级。

0x03、DMA数据配置

使用 DMA,最核心就是配置要传输的数据,包括数据从哪里来,要到哪里去,传输的数据的单位是什么,要传多少数据,是一次传输还是循环传输等等。 

0x0001、从哪里来到哪里去

我们知道DMA 传输数据的方向有三个: 从外设到存储器,从存储器到外设,从存储器到存储器具体的方向 DMA_CCR 位 4 DIR 配置:  表示从外设到存储器,1表示从存储器到外设。这里面涉及到的外设地址由 DMA CPAR 配置,存储器地址由 DMA CMAR 配置

  • 外设到存储器

当我们使用从外设到存储器传输时,以 ADC 采集为例。DMA外设寄存器的地址对应的就是ADC数据寄存器的地址,DMA 存储器的地址就是我们自定义的变量 (用来接收存储 AD 采集的数据的地址。方向我们设置外设为源地址。

  • 存储器到外设

当我们使用从存储器到外设传输时,以串口向电脑端发送数据为例。DMA 外设寄存器的地址对应的就是串口数据寄存器的地址,DMA 存储器的地址就是我们自定义的变量(相当于一个缓冲区,用来存储通过串口发送到电脑的数据) 的地址。方向我们设置外设为目标地址。

  • 存储器到存储器

当我们使用从存储器到存储器传输时,以内部FLASH 向内部 SRAM 复制数据为例。DMA 外设寄存器的地址对应的就是内部 FLASH (我们这里把内部FALSH 当作一个外设来看)的地址,DMA存储器的地址就是我们自定义的变量 (相当于一个缓冲区,用来存储来自内部 FLASH 的数据)的地址。方向我们设置外设(即内部FLASH) 为源地址。跟上面两个不一样的是,这里需要把DMA_CCR 位 14: MEM2MEM: 存储器到存储器模式配置为 1,启动 M2M 模式 

0x0002、要传多少,单位是什么

当我们配置好数据要从哪里来到哪里去之后,我们还需要知道我们要传输的数据是多少,数据的单位是什么。
以串口向电脑发送数据为例,我们可以一次性给电脑发送很多数据,具体多少由 DMA_CNDTR配置,这是一个 32 位的寄存器,一次最多只能传输 65535 个数据。
要想数据传输正确,源和目标地址存储的数据宽度还必须一致,串口数据寄存器是 8位的,所以我们定义的要发送的数据也必须是 8 位。外设的数据宽度由 DMA CCR 的 PSIZE[1:0] 配置,可以是 8/16/32 位,存储器的数据宽度由 DMA CCR 的 MSIZE[1:0] 配置,可以是 8/16/32 位。
在 DMA 控制器的控制下,数据要想有条不紊的从一个地方搬到另外一个地方,还必须正确设置两边数据指针的增量模式。外设的地址指针由 DMA CCRx 的 PINC 配置,存储器的地址指针由MINC 配置。以串口向电脑发送数据为例,要发送的数据很多,每发送完一个,那么存储器的地址指针就应该加 1,而串口数据寄存器只有一个,那么外设的地址指针就固定不变。具体的数据指针的增量模式由实际情况决定。

0x0003、什么时候传输完成

数据什么时候传输完成,我们可以通过查询标志位或者通过中断的方式来鉴别。每个 DMA 通道在 DMA 传输过半、传输完成和传输错误时都会有相应的标志位,如果使能了该类型的中断后则会产生中断。有关各个标志位的详细描述请参考 DMA 中断状态寄存器 DMA ISR 的详细描述传输完成还分两种模式,是一次传输还是循环传输,一次传输很好理解,即是传输一次之后就停止,要想再传输的话,必须关断DMA 使能后再重新配置后才能继续传输。循环传输则是一次传输完成之后又恢复第一次传输时的配置循环传输,不断的重复。具体的由 DMA_CCR 寄存器的CIRC 循环模式位控制。

0x04、DMA初始化结构体详解 

标准库函数对每个外设都建立了一个初始化结构体 xxx InitTypeDef(xxx 为外设名称),结构体成员用于设置外设工作参数,并由标准库函数 xxx Imit0 调用这些设定参数进入设置外设相应的寄存器,达到配置外设工作环境的目的。
结构体 xxx InitTypeDef 和库函数 xxx Init 配合使用是标准库精所在,理解了结构体xxx_InitTypeDef 每个成员意义基本上就可以对该外设运用自如。结构体 xxx InitTypeDef 定义在stm32f10x xxx.h(后面xxx 为外设名称)文件中,库函数xxx Init 定义在 stm32f10x xxx.c 文件中编程时我们可以结合这两个文件内注释使用。

/** 
  * @brief  DMA Init structure definition
  */

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;
  1. DMA PeripheralBaseAddr: 外设地址,设定 DMA_CPAR 寄存器的值;一般设置为外设的数据寄存器地址,如果是存储器到存储器模式则设置为其中一个存储器地址。
  2. DMA_Memory0BaseAddr: 存储器地址,设定 DMA_CMAR 寄存器值;一般设置为我们自定义存储区的首地址。
  3. DMA DIR: 传输方向选择,可选外设到存储器、存储器到外设。它设定 DMA_CCR 寄存器的DIR[1:0] 位的值。这里并没有存储器到存储器的方向选择,当使用存储器到存储器时,只需要把其中一个存储器当作外设使用即可。
  4. DMA_BulferSize: 设定待传输数据数目,初始化设定 DMA_CNDTR 寄存器的值
  5. DMA_Peripheralnc: 如果配置为 DMA Peripherallnc_Enable,使能外设地址自动递增功能,它设定 DMA_CCR 寄存器的 PINC 位的值;一般外设都是只有一个数据寄存器,所以一般不会使能该位。
  6. DMA MemoryInc:如果配置为 DMA MemoryInc_Enable,使能存储器地址自动递增功能,它设定 DMA_CCR 寄存器的 MINC 位的值;我们自定义的存储区一般都是存放多个数据的,所以要使能存储器地址自动递增功能。
  7. DMA PeripheralDataSize: 外设数据宽度,可选字节(8 位)、半字(16 位)和字(32 位),它设定DMA CCR 寄存器的 PSIZE[1:0] 位的值。
  8. DMA MemoryDalaSize: 在储器数据宽度,可选字节(8 位)、半字(16 位)和字(32 位),它设定DMA_CCR 寄存器的 MSIZE[1:0] 位的值。当外设和存储器之间传数据时,两边的数据宽度应该设置为一致大小。
  9. DMA_Mode: DMA 传输模式选择,可选一次传输或者循环传输,它设定 DMA_CCR 寄存器的CIRC 位的值。例程我们的 ADC 采集是持续循环进行的,所以使用循环传输模式。
  10. DMA_Priority: 软件设置通道的优先级,有 4个可选优先级分别为非常高、高、中和低,它设定 DMA_CCR 寄存器的 PL[1:0] 位的值。DMA 通道优先级只有在多个 DMA 通道同时使用时才有意义,如果是单个通道,优先级可以随便设置。
  11. DMA_M2M: 存储器到存储器模式,使用存储器到存储器时用到,设定 DMA CCR 的位14MEN2MEN 即可启动存储器到存储器模式。 

0x05、串口1通过DMA发送试验

1、通过DMA_InitStructure结构体配置串口1发送的DMA

#define  USART1_TX_DMA_CHANNEL    DMA1_Channel4          // 串口1发送对应的DMA请求通道4
#define  USART_DR_ADDRESS         (USART1_BASE + 0x04)   // 外设寄存器地址 串口1的数据寄存器USART_DR地址  偏移量4
#define  SENDBUFF_SIZE            5000                   // 一次发送的数据量

void USART1_DMA_Config(void)
{
    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                       // 开启DMA时钟

    DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;             // 设置DMA源地址:串口数据寄存器地址
    DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t )SendBuff;          // 内存地址(要传输的变量的指针)
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralDST;        // 方向:从内存到外设
    DMA_InitStructure.DMA_BufferSize         = SENDBUFF_SIZE;                // 传输大小
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;    // 外设地址不增
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;         // 内存地址自增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  // 外设数据单位
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;	     // 内存数据单位
//    DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal ;             // DMA模式,一次模式
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;            // DMA模式,循环模式
    DMA_InitStructure.DMA_Priority           = DMA_Priority_Medium;          // 优先级:中
    DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;              // 禁止内存到内存的传输

    DMA_Init(USART1_TX_DMA_CHANNEL, &DMA_InitStructure);                     // 配置DMA通道
    DMA_Cmd (USART1_TX_DMA_CHANNEL,ENABLE);                                  // 使能DMA
}

这里有几个参数是通过#define定义的

第一个是串口1发送的DMA通道,在参考手册中查表可知该通道为DMA1_Channel4;

第二个是DMA源地址即串口数据寄存器地址USART_DR_ADDRESS,它的地址是串口1的基地址加4即USART1_BASE + 0x04;

第三个是一次发送的数据量,这个可由使用者自由定义,这里定位为5000个字节

2、通过USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);函数请求DMA串口发送数据 

总结:整个过程中比较重要的两步就是上诉的两步,一是DMA的配置,二是向DMA请求发送

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/623301.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022 中国开源创新大赛,时序数据库 TDengine 榜上有名

近日,2022 中国互联网发展创新与投资大赛暨 2022 年中国开源创新大赛在北京落下帷幕,本次大赛由中央网信办信息化发展局指导,中国互联网发展基金会、中国网络空间研究院、中国互联网投资基金联合主办。非常荣幸的是,凭借着强大的开…

他们用卫星,让中国量子通信领跑全球

光子盒研究院 上周二(5月30日),中国宣布其神舟十六号飞船与天宫三号空间站成功对接,官方媒体称景海鹏、朱杨柱和桂海潮这三名中国宇航员将有机会研究“新的量子现象”。这意味着中国量子技术发展的一大突破:我们现在可…

IVD体外诊断已经发展成为医疗健康市场活跃领域之一

体外诊断领域的布局覆盖免疫诊断、血液诊断、尿液诊断、生化诊断、微生物诊断等。得益于自主研发驱动下的技术积累和产品创新 近年来,体外诊断已经发展成为医疗健康市场最活跃、增长最快的领域之一。 从全球体外诊断发展来看,据Kalorama Information的统…

接口测试 —— Requests库介绍

1、Requests库 Requests库是用Python语言编写,基于urllib3模块,采用Apache2 Licensed开源协议的 HTTP 库。 虽然Python的标准库中urllib3模块已经包含了平常我们使用的大多数功能,但是它的 API使用起来让人感觉不太友好。而Requests库使用的…

Vue+springboot果蔬有机蔬菜商城销售种植系统与设计

对于网站的前台设计,要保证主界面的整洁有序,能够抓住人的眼球,不会产生视觉疲劳,更重要的是,带给人容易操作的直观感受,这样才能留住用户去进行使用,增加三分热度的延续期。在系统的后台设计上…

2023预备金九银十,400道阿里必问软件测试高频面试考点详细解析

前言 临近秋招,又到了“金九银十”面试求职高峰期,在金九银十时也参与过不少面试,2023都说工作不好找,也是对开发人员的要求变高。前段时间自己有整理了一些软件测试面试常问的高频考点问题做成一份PDF文档(400道高频…

东软、联影、科曼在今届CMEF好猛, “挖挖”背后的共同点

走出三年疫情阴霾,医疗行业迎来爆发式的展会营销盛况。5月14-17日,为期4天的第87届中国国际医疗器械博览会(CMEF)在上海圆满落幕! 在这场32万平方米的全球医疗产业“航母级”盛会中,一众行业大咖、来自120…

优思学院|如何通过实验设计改善产品质量?

你的企业是否经常因为产品和服务不符合客户的期望而感到苦恼?你是否在想有没有一种方法可以在任何时候都可以帮助你解决问题? 那么,您需要一种突破性改进工具,它也是六西格玛项目中的”杀手锏",它称为实验设计&a…

玩转学生信息管理系统——【c++】

设计一个管理系统实现对学生的基本信息(至少包括姓名、学号、性别、出生日期、宿舍号年龄(通过计算得到)的管理;),具有数据的录入、显示、保存、查询(按学号查查询或姓名查询)、修改…

ASP.NET State Service服务无法启动解决方案

客户服务器ASP.NET State Service启动不起来,如下图所示: 在服务中右击属性查看基本信息,发现aspnet_state.exe在目录中不存在,如下图所示: 若想正常启动,需要重新指向有exe的目录中去,解决方案…

Linux之问件上传下载

目录 Linux之文件上传下载 sftp 定义 用法 常用操作 查看当前目的主机的路径 --- pwd 查看当前本地所在路径 --- lpwd 更改当前目的主机的路径 --- cd 更改当前本地所在路径 --- lcd 查看当前目的主机 --- ls ​编辑 查看当本地的主机目录 --- lls ​编辑 将Window…

08SQL基础知识

SQL知识点 1、SQL语言分类 SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL。 1. 数据查询语言DQL 数据查询语言DQL基本结构是由SELECT子句,FROM子句,WHERE子句组…

耗时122天,终于把牛客网点赞飙升的Java面试题(含答案)整理出来了

2023年就业形势不算好,大厂缩招裁员导致优质岗位竞争变得更加激烈,除了对面试者技术的要求变高,面试的深度和难度较去年也有所加大。为了让大家能够在 2023 金九银十跳槽黄金期脱颖而出,想拿个好 offer 说实话,现在准备…

企业上云,你做对了吗?

数字化转型是国家战略,各位估计眼睛看这几个字都看出茧了。所以,今天不聊数字化转型,今天聊企业上云。 随着云计算技术的日益成熟和云计算服务商的不断涌现,越来越多的企业将业务应用迁移到云端。但是,企业上云“坑”…

2023大唐杯学习笔记——人工智能与机器学习—决策树

决策树知识点 这个表也是一个数据集 问题:以什么作为划分呢?第一次是以年龄,还是以 工作 房子 信贷情况… 这里的熵与中文里的其他东西没有实际对应,就是一个定义H(p)1最大时,p0.5,这…

串口助手(串口发送接收数据, 定时, 清空, hex显示)

文章目录 前言一、串口接收数据1. 默认接收,换行,hex显示2. 清空接收区数据3. 保存接受区数据 二、串口发送数据1. 默认发送2. 定时发送 三、串口助手优化1. 设置组合框当前内容。2. 未检测到串口,弹出警告。3. 载入文件 总结 前言 这篇文章…

ESP32-S3 使用指定 key 来进行 secure boot 签名并进行 OTA 测试

文档说明 Secure Boot V2 测试准备: 硬件准备:ESP32-S3 开发板或模组软件准备:esp-idf v5.0 版本 SDK 测试步骤: 生成指定 secure boot 签名 key软件开启 secure boot 配置烧录被签名的固件对新的 app.bin 使用指定 key 进行…

【006 Linux内核】应用程序中open()在linux中执行过程中是如何从用户空间到内核空间?

一、前言 应用程序运行在用户空间,而 Linux 驱动运行于内核空间。当我们在用户空间想要实现对内核的操作,比如使用 open 函数打开/dev/led 这个驱动,由于用户空间不能直接对内核进行操作,因此必须使用一个叫做 “系统调用” 的方…

论文阅读 (90):Proposal-based Multiple Instance Learning (P-MIL, 2023CVPR)

文章目录 1 要点1.1 概述1.2 一些概念1.3 主要步骤 2 方法2.1 候选提案生成2.2 提案特征提取和分类2.2.1 周围对比特征提取2.2.2 分类头 2.3 提案微调2.3.1 提案完备性评估2.3.2 实例级秩一致性 2.4 网络训练和推理2.4.1 网络训练2.4.2推理 3 实验3.1 数据集即评估标准3.1.1 数…

一线大厂Java 面试题大全1100+ 面试题附答案详解(2023最新整理)

写在前面 今年的面试比往年要难得多,各个互联网企业对于 Java 岗位的要求越来越多,也越来越高,主要是初级岗位已经趋近饱和,但高级岗位又相对来说缺乏,这类的人才偏少,因此作为 Java 开发人员,…