STM32—DMA直接存储器访问详解

news2024/11/28 0:46:42

DMA——直接存储器访问

DMA:Data Memory Access, 直接存储器访问。

DMA和我们之前学过的串口、GPIO都是类似的,都是STM32中的一个外设。串口是用来发送通信数据的,而DMA则是用来把数据从一个地方搬到另一个地方,而且不占用CPU。

举个例子:

我们如果要把一串数据发送给串口 ,CPU先要把这一串数据先一个一个取回来暂存在CPU中的寄存器中,然后再一个一个发送给串口。

这样就会导致CPU不能做其他事情,CPU一直处于被占用的状态。

当DMA出现后,CPU只需要给DMA发送一条命令,如将数据发送给串口,然后DMA就来完成这个上述需要CPU完成的工作了。这就节省了CPU的资源来完成其他操作。


上面我们解释完DMA是什么后,我们接着来看DMA具体有几种方式。

1.P->M(外设到存储器)

后面的ADC数据采集使用的是这一类

2.M->P(存储器到外设)

之前的串口发送实验属于这一类

3.M->M(存储器到存储器)

存储器到存储器的实验一会儿在后面讲

我们先来看一下DMA的功能框图

DMA功能框图讲解

请添加图片描述

我们先把DMA的功能框图分为三大主要部分来讲解:1.DMA请求。2.通道。3.仲裁器

DMA请求

通过上面的DMA框图我们可以看到,DMA请求通常是由外设发起的,例如串口、GPIO、ADC等等。

那么具体的外设是如何发送DMA请求的呢?

这里就要先提一下通道这个概念,不同的外设通过具体的通道向DMA控制器发送请求,然后DMA控制器再根据通道的优先权来处理请求。

DMA有DMA1和DMA2两个控制器,DMA1有7个通道,DMA2有5个通道,不同的DMA控制器的通道对应这不同的外设请求。

请添加图片描述

从上图可以看出,芯片的参考手册已经帮我们把不同的外设分别对应的通道分配好了,我们使用的时候只需要去查询这个表就行了。

仲裁器

虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能接收多个。

当多个通道同时向DMA控制器发送DMA请求的时候,谁可以先使用DMA控制器呢?这时就需要仲裁器来判断通道的优先级了。

仲裁器管理DMA通道请求分为两个阶段。

第一阶段属于软件阶段,可以在DMA_CCRx寄存器中设置,有4个等级:非常高四个优先级。见下图

请添加图片描述

第二阶段属于硬件阶段, 如果两个或以上的DMA通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高,比如通道0高于通道1。

DMA数据配置

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

从哪里来到那里去?

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

我们在使用固件库编程的时候,通常不会直接配置这三个寄存器,都是通过初始化结构体来配置的,这三个寄存器对应的结构体变量如下图:

请添加图片描述

配置内容对应寄存器
外设地址DMA_CPAR
存储器地址DMA_CMAR
传输方向DMA_CCR:DIR
外设到存储器

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

存储器到外设

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

存储器到存储器

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

数据要传多少,传的单位是什么?

请添加图片描述

配置内容对应寄存器
传输数目DMA_CNDTR
外设地址是否递增DMA_CCRx:PINC
存储器地址是否递增DMA_CCRx:MINC
外设数据宽度DMA_CCRx:PSIZE
存储器数据宽度DMA_CCRx:MSIZE

当我们配置好数据要从哪里来到哪里去之后,我们还需要知道我们要传输的数据是多少,数据的单位是什么。

以串口向电脑发送数据为例,我们可以一次性给电脑发送很多数据,具体多少由DMA_CNDTR配置, 这是一个32位的寄存器,一次最多只能传输65535个数据。

要想数据传输正确,源和目标地址存储的数据宽度还必须一致

串口数据寄存器是8位的, 所以我们定义的要发送的数据也必须是8位。

外设的数据宽度由**DMA_CCR的PSIZE[1:0]**配置, 可以是8/16/32位,

存储器的数据宽度由**DMA_CCR的MSIZE[1:0]**配置,可以是8/16/32位。

那么当PSIZE和MSIZE不相同时,也能传输,但是可能传输结果与你的预期不同,我们可以参照下表来查询:

请添加图片描述

在DMA控制器的控制下,数据要想有条不紊的从一个地方搬到另外一个地方,还必须正确设置两边数据指针的增量模式。

外设的地址指针由DMA_CCRx的PINC配置,存储器的地址指针由MINC配置。以串口向电脑发送数据为例,要发送的数据很多, 每发送完一个,那么存储器的地址指针就应该加1,而串口数据寄存器只有一个, 那么外设的地址指针就固定不变。具体的数据指针的增量模式由实际情况决定。

什么时候传输完成?

请添加图片描述

配置内容对应寄存器
模式选择(一次传输、循环传输)DMA_CCRx:CIRC
传输过半、传输完成、传输出错标志位DMA_ISR

数据什么时候传输完成,我们可以通过查询标志位或者通过中断的方式来鉴别。

每个DMA通道在DMA传输过半传输完成传输错误时都会有相应的标志位,如果使能了该类型的中断后,则会产生中断。

有关各个标志位的详细描述请参考DMA中断状态寄存器DMA_ISR的详细描述。

传输完成还分两种模式,是一次传输还是循环传输

一次传输很好理解,即是传输一次之后就停止,

要想再传输的话, 必须关断DMA使能后再重新配置后才能继续传输。

循环传输则是一次传输完成之后又恢复第一次传输时的配置循环传输, 不断的重复。

具体的由DMA_CCR寄存器的CIRC 循环模式位控制。

以上就是所有关于DMA的理论部分,下面我来进行程序编写。我先设计一个程序将存储器中的数据通过DMA的方式发送给串口。

我依然按照我上面讲DMA数据配置的顺序来写程序。

DMA(存储器到外设)实现代码

首先创建一个数组作为数据源,一会儿发送给串口

//准备将存储器中的这个数组中的数据发送到串口
u32 SourceBuffer[500];

然后开始配置DMA,上面我们讲DMA数据配置的时候已经说过了,我们配置DMA的时候是通过向DMA初始化结构体中填数据来配置的,所以我们先定义一个DMA初始化结构体,然后打开DMA外设的时钟信号。

//定义DMA初始化结构体
DMA_InitTypeDef DMA_initStruct;

//首先查询DMA挂载在哪根总线上,然后打开DMA时钟信号
RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1EN,ENABLE);

数据从哪里来,到哪里去?

配置外设基地址

存储器基地址

数据传输方向

//通过上一篇文章对串口(USART)介绍的文章,可以找到串口数据发送的寄存器是放在USART_DR中的
DMA_initStruct.DMA_PeripheralBaseAddr = USART1_BASE + 0x04;

//配置存储器的基地址,也就是数组名
DMA_initStruct.DMA_MemoryBaseAddr = (u32)SourceBuffer;

//配置DMA数据传输方向,从存储器到外设,所以是外设Destination
DMA_initStruct.DMA_DIR = DMA_DIR_PeripheralDST;

数据要传多少,传的单位是什么?

我就不赘述了,请看代码中的注释

//配置发送的数据大小为500,因为数组大小为500
DMA_initStruct.DMA_BufferSize = 500;

//外设地址不用自增,因为串口的发送寄存器只有一个字节这么大
DMA_initStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

//配置外设的数据宽度为字节
DMA_initStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

//由于数组是按顺序发送,所以存储器的地址可以自增
DMA_initStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;

//由于数组中的数据类型为u32,所以存储器的数据宽度配置为字
DMA_initStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;


什么时候传输完成?

//发送模式配置为发送一次,建议不要配置成循环发送,因为我的查看串口发送信息的工具会卡死
DMA_initStruct.DMA_Mode = DMA_Mode_Normal;

//优先级随便配置,没人跟你抢
DMA_initStruct.DMA_Priority = DMA_Priority_High;

//存储器到存储器的单独配置位,这里我们是存储器到外设,所以这个位为disable
DMA_initStruct.DMA_M2M = DMA_M2M_Disable;

上面配置好后,才算完成DMA初始化结构体的配置,接下来调用初始化函数。并给通道使能信号

//调用初始化函数
DMA_Init(DMA1_Channel4,&DMA_initStruct);

//DMA通道使能信号
DMA_Cmd(DMA1_Channel4,ENABLE);

DMA配置好了,下面来写main函数,注意,串口也是需要配置的。但是由于我在上一篇文章里已经详细讲述过串口的配置方法,在这里我就直接调用串口的配置函数了。

int main(){
	u16 i;
    //先用一个for循环向数组中填数据,一会儿这个数据会通过串口发送出去
	for(i=0; i<500; i++){
		SourceBuffer[i]=14;
	}
    
    //调用串口配置函数
	USART_GPIO_Config();
	USART_Config();
    
	//调用DMA配置函数
	DMA_Config();
    
    //串口1向DMA发出TX请求
	USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
	
}

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

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

相关文章

2024年经济发展、社会科学与贸易国际会议(ICEDSST2024)

2024年经济发展、社会科学与贸易国际会议(ICEDSST2024) 会议简介 2024年国际经济发展、社会科学与贸易会议&#xff08;ICEDSST2024&#xff09;将在中国深圳举行&#xff0c;主题为“经济发展、社科与贸易”。ICEDSST2024汇集了来自世界各地经济发展、社科与贸易领域的学者、…

Ubuntu无网络标识的解决方法

1.出现的情况的特点 2.解决办法 2.1 进入root并输入密码 sudo su 2.2 更新NetworkManager的配置 得先有gedit或者vim&#xff0c;两个随意一个&#xff0c;这里用的gedit&#xff0c;没有就先弄gedit&#xff0c;有的话直接下一步 apt-get install gedit 或者vim apt-get ins…

Vim:强大的文本编辑器

文章目录 Vim&#xff1a;强大的文本编辑器Vim的模式命令模式常用操作光标移动文本编辑查找和替换 底行命令模式常用操作Vim的多窗口操作批量注释与去注释Vim插件推荐&#xff1a;vimforcpp结论 Vim&#xff1a;强大的文本编辑器 Vim&#xff0c;代表 Vi IMproved&#xff0c;…

基于小程序实现的医院预约挂号系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

Android网络抓包--Charles

一、Android抓包方式 对Https降级进行抓包&#xff0c;降级成Http使用抓包工具对Https进行抓包 二、常用的抓包工具 wireshark&#xff1a;侧重于TCP、UDP传输层&#xff0c;HTTP/HTTPS也能抓包&#xff0c;但不能解密HTTPS报文。比较复杂fiddler&#xff1a;支持HTTP/HTTPS…

Swift Zulian Tiger

Swift Zulian Tiger 迅捷祖利安猛虎 16万金&#xff08;游戏币&#xff09; 1万金大概就能兑换460元~600元之间&#xff0c;6400元-9600元&#xff0c;汗颜 故事的一天刚打完BWL&#xff0c;才125金&#xff08;游戏币&#xff09; 本来想下线的结果他们说你太黑了&…

工控 modbusTCP 报文

Tx 发送报文:00 C9 00 00 00 06 01 03 00 00 00 02 Rx 接收报文:00 C9 00 00 00 07 01 03 04 01 4D 00 01 Tx 发送报文:00 C9 00 00 00 06 01 03 00 00 00 02 00 C9 事务处理标识符 2字节 00 00 协议标识符 2字节 固定 00 00 00 06 长度 2字节 表示之后的字节总数 &#xff08;…

贪心算法|968.监控二叉树

力扣题目链接 class Solution { private:int result;int traversal(TreeNode* cur) {// 空节点&#xff0c;该节点有覆盖if (cur NULL) return 2;int left traversal(cur->left); // 左int right traversal(cur->right); // 右// 情况1// 左右节点都有覆盖if (le…

MariaDB介绍和安装

MariaDB介绍和安装 文章目录 MariaDB介绍和安装1.MariaDB介绍2.MariaDB安装2.1 主机初始化2.1.1 设置网卡名和ip地址2.1.2 配置镜像源2.1.3 关闭防火墙2.1.4 禁用SELinux2.1.5 设置时区 2.2 包安装2.2.1 Rocky和CentOS 安装 MariaDB2.2.2 Ubuntu 安装 MariaDB 2.3 源码安装2.3.…

紫光展锐携手中国联通智慧矿山军团(山西)完成RedCap现网环境测试

近日&#xff0c;紫光展锐与中国联通智慧矿山军团&#xff08;山西&#xff09;在现网环境下成功完成了RedCap技术测试。此次测试对搭载紫光展锐RedCap芯片平台V517的模组注网速度和信号情况、Iperf打流测试上下行情况、ping包延时情况以及模组拨号入网压测等项目进行了全面验证…

【性能测试】接口测试各知识第3篇:Jmeter 基本使用流程,学习目标【附代码文档】

接口测试完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;接口测试&#xff0c;学习目标学习目标,2. 接口测试课程大纲,3. 接口学完样品,4. 学完课程,学到什么,5. 参考:,1. 理解接口的概念。学习目标&#xff0c;RESTFUL1. 理解接口的概念,2.什么是接口测试…

# Contrastive Learning(对比学习)--CLIP笔记(一)

Contrastive Learning&#xff08;对比学习&#xff09;–CLIP笔记&#xff08;一&#xff09; 参考&#xff1a;CLIP 论文逐段精读【论文精读】_哔哩哔哩_bilibili CLIP简介 CLIP是一种多模态预训练模型&#xff0c;由OpenAI在2021年提出&#xff0c;论文标题&#xff1a;L…

STM32 DCMI 的带宽与性能介绍

1. 引言 随着市场对更高图像质量的需求不断增加&#xff0c;成像技术持续发展&#xff0c;各种新兴技术&#xff08;例如3D、计算、运动和红外线&#xff09;的不断涌现。如今的成像应用对高质量、易用性、能耗效率、高集成度、快速上市和成本效益提出了全面要求。为了满足这些…

【自然语言】使用词袋模型,TF-IDF模型和Word2Vec模型进行文本向量化

一、任务目标 python代码写将 HarryPorter 电子书作为语料库&#xff0c;分别使用词袋模型&#xff0c;TF-IDF模型和Word2Vec模型进行文本向量化。 1. 首先将数据预处理&#xff0c;Word2Vec 训练时要求考虑每个单词前后的五个词汇&#xff0c;地址为 作为其上下文 &#xf…

数据结构的魅力

数据结构这块越学越敬佩 博大精深 统计大文件中相同年龄的人的个数 public static void main(String[] args) throws Exception {String str "";String fileName "";InputStreamReader isr new InputStreamReader(new FileInputStream(fileName), Stan…

OSCP靶场--Banzai

OSCP靶场–Banzai 考点(ftp爆破 webshell上传web1访问403web2可以访问webshell反弹mysql udf提权) 1.nmap扫描 ## nmap扫描一定要使用 -p- 否则容易扫不全端口 ┌──(root㉿kali)-[~/Desktop] └─# nmap -sV -sC 192.168.158.56 -Pn -p- --min-rate 2500Starting Nmap 7.…

ArcGIS Pro 3D建模简明教程

在本文中&#xff0c;我讲述了我最近一直在探索的在 ArcGIS Pro 中设计 3D 模型的过程。 我的目标是尽可能避免与其他软件交互&#xff08;即使是专门用于 3D 建模的软件&#xff09;&#xff0c;并利用 Pro 可以提供的可能性。 这个短暂的旅程分为三个不同的阶段&#xff1a;…

AI绘本生成解决方案,快速生成高质量的AI绘本视频

美摄科技凭借其深厚的技术积累和前瞻性的市场洞察力&#xff0c;近日推出了一款面向企业的AI绘本生成解决方案&#xff0c;旨在通过智能化、自动化的方式&#xff0c;帮助企业快速将文字内容转化为生动有趣的绘本视频&#xff0c;从而提升内容传播效率&#xff0c;增强品牌影响…

迁移docker部署的GitLab

目录 1. 背景2. 参考3. 环境4. 过程4.1 查看原docker启动命令4.2 打包挂载目录传至新宿主机并创建对应目录4.3 保存镜像并传至新宿主机下4.4 新宿主机启动GitLab容器 5 故障5.1 容器不断重启5.2 权限拒绝5.3 容器内错误日志 6 重启容器服务正常7 总结 1. 背景 最近接到一个任务…

Python的标准输入输出及强制类型转换

Python标准输入 input()是Python提供的标准输入函数&#xff0c;括号内为显示在终端的提示信息&#xff0c;其返回结果为字符型&#xff08;str&#xff09;。 Python标准输出 print()是Python提供的标准输出函数&#xff0c;可以将括号中的内容输出到终端中。 print()函数中有…