【STM32】DMA初步使用

news2024/10/7 12:29:21

DMA简介

DMA(Direct Memory Access)—直接存储器存取,是单片机的一个外设,它的主要功能
是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以干其他的事情。

以STM32F103单片机为例
F03有DMA1和DMA2两组DMA,其中DMA1有7个通道,DMA2有5个通道。

DMA 请求

外设需要使用DMA,则必须向DMA发送DMA请求,DMA收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到传输完毕。

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

DMA1 各个通道的请求映像
DMA1 各个通道的请求映像

DMA2 各个通道的请求映像
在这里插入图片描述

通道

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

仲裁器,优先级

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

DMA的几个要点

DMA 传输数据的方向有三个:从外设到存储器从存储器到外设从存储器到存储器,。具体的方向 DMA_CCR配置,这里面涉及到的外设地址由 DMA_CPAR 配置,存储器地址由 DMA_CMAR 配置。

传输方向

外设到存储器

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

存储器到外设

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

存储器到存储器

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

传输长度 单位 地址自加

传输长度

以串口向电脑发送数据为例,源地址为片上flash,目标地址为USART->DR,可以一次性给电脑发送很多数据,具体多少由DMA_CNDTR 配置,这是一个 32 位的寄存器,一次最多只能传输 65535 个数据。

目标和源的传输长度保持一致

要想数据传输正确,源和目标地址存储的数据宽度还必须一致,串口数据寄存器是 8位的,所以我们定义的要发送的数据也必须是 8 位。外设的数据宽度由 DMA_CCRx 的PSIZE[1:0]配置,可以是8/16/32位,存储器的数据宽度由DMA_CCRx的MSIZE[1:0]配置,可以是 8/16/32 位。

地址自动增加

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

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

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

传输完成,循环传输

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

DMA固件库

链接: DMA固件库函数

DMA配置流程

要点

1) 使能 DMA 时钟;

2) 配置 DMA 数据参数;

3) 使能 DMA,进行传输;

4) 等待传输完成,并对源数据和目标地址数据进行比较。

#DMA配置
void DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	// 开启 DMA 时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	// 源数据地址 aSRC_Const_Buffer是使用const定义在内部flash上的一块数组
	DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)aSRC_Const_Buffer;
	 // 目标地址,例:如果是通过串口发送数据那么目标地址可以设置为USART1->DR
	 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)aDST_Buffer;
	 
	 // 方向:外设到存储器(这里的外设是内部的 FLASH),方向都是相对的,要看目标和源怎么设置了
	 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	 
	 // 传输大小
	 DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
	 
	 // 外设,前文设置的外设地址(内部的 FLASH)地址递增
	 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
	 
	 // 内存地址递增
	 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	 
	 // 外设数据单位
	 DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_Word;
	 
	 // 内存数据单位
	 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
	 
	 // DMA 模式,一次或者循环模式
	 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	 //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
	 
	 // 优先级:高
	 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	 
	 // 使能内存到内存的传输
	 DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
	 
	 // 配置 DMA 通道
	 DMA_Init(DMA1_Channel6, &DMA_InitStructure);
	 
	 // 使能 DMA
	 DMA_Cmd(DMA1_Channel6, ENABLE);
}

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

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

相关文章

项目总结知识点记录-文件上传下载(三)

(1)文件上传 代码: RequestMapping(value "doUpload", method RequestMethod.POST)public String doUpload(ModelAttribute BookHelper bookHelper, Model model, HttpSession session) throws IllegalStateException, IOExcepti…

windows如何更改/禁用系统更新

提示:首先说明这属于将更新时间更改,不过你可以的将更新时间更改为十年一百年 废话不多说开始正文: 1.首先:winR打开运行,输入regedit,进入注册表编辑器 2.进入编辑器后依次点击:HKEY_LOCAL_MACHINE\SOFT…

Clion 使用ffmpeg 学习1 开发环境配置

Clion 使用ffmpeg 学习1 开发环境配置 一、准备工作1. 准备环境2. 下载FFmpeg 二、操作步骤1. Clion 新建一个C项目2. 修改 CMakeLists.txt3. 修改配置4. 运行测试5. 打印rtsp 流信息的 demo 一、准备工作 在视频处理和多媒体应用程序开发中,FFmpeg 是一个强大的开…

学生辅导反馈

1 密西根大学 这个留学生了一个A。 他的C课程比较简单,属于入门级,大部分自己都可以搞定,只不过如果有人带一下就会彻底理解,自信心也就上来了。 基本上都是一对一,他写代码,我看着。 不过他后面想选他们…

系统调用与函数地址动态寻找(详解版)

双机调试 F9,进入程序领空,搜索所有用户模块的跨模块调用,F2下断点 x64Dbg:F7单步步入,F8单步步过 进入内核的方式: int 2E(比较早期)sysenter(x86)sysca…

Python入门教程 | Python3 列表(List)

Python3 列表 序列是 Python 中最基本的数据结构。 序列中的每个值都有对应的位置值,称之为索引,第一个索引是 0,第二个索引是 1,依此类推。 Python 有 6 个序列的内置类型,但最常见的是列表和元组。 列表都可以进…

CPU彪高排序顺序

简单总结 这类问题分为两大类 代码问题JVM自身问题 我们首先要做的就是先保证代码无bug,排查顺序就是 进程 -> 线程 -> jstack 分析,最后在做JVM的分析。 具体操作 对于Java后台程序CPU使用率高的排查,可以按以下步骤操作&#xf…

解决:burpsuite——Connection refused: no further information

出现该问题的原因是开启了SOCKS proxy;关闭该选项即可正常抓包。 具体操作:

Windows安装配置Rust(附CLion配置与运行)

Windows安装配置Rust(附CLion配置与运行) 前言一、下载二、安装三、配置标准库!!!四、使用 CLion 运行 rust1、新建rust项目2、配置运行环境3、运行 前言 本文以 windows 安装为例,配置编译器为 minGW&…

flutter plugins插件【一】【FlutterJsonBeanFactory】

1、FlutterJsonBeanFactory 在Setting->Tools->FlutterJsonBeanFactory里边自定义实体类的后缀,默认是entity 复制json到粘贴板,右键自己要存放实体的目录,可以看到JsonToDartBeanAction Class Name是实体名字,会默认加上…

Python入门教程32:计算程序运行的时间

★★★★★博文原创不易,我的博文不需要打赏,也不需要知识付费,可以白嫖学习编程小技巧,喜欢的老铁可以多多帮忙点赞,小红牛在此表示感谢。★★★★★ #我的Python教程 #官方微信公众号:wdPythonPython中可…

stable diffusion实践操作-CLIP

系列文章目录 stable diffusion实践操作 文章目录 系列文章目录前言一、CLIP是什么?1.1 定义:1.2 作用 二、使用步骤2.1 设置使用2.1 跳过层对比图: 三、总结 前言 学习本章之前,先看SD生图原理 stable diffusion实践操作-SD原理…

看看985高校的《数据结构》教材能差到什么程度

网上下了一本教材,看看其内容,不禁开始吃鲸起来。我们的国家的栋梁之材就天天学习这样的教材。 国内外教材但凡多参考也不至于差到如此地步。清华严蔚敏的那本参考一下也不至于写出这么差的教材。 而且用C实现。C被误导,误教,不…

【回溯法-附模板和例题分析】

回溯法 适用于: 组合问题:N个数里面按一定规则找出k个数的集合切割问题:一个字符串按一定规则有几种切割方式子集问题:一个N个数的集合里有多少符合条件的子集排列问题:N个数按一定规则全排列,有几种排列…

LeetCode 面试题 02.08. 环路检测

文章目录 一、题目二、C# 题解 一、题目 给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。若环不存在,请返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了…

接口测试系列 —— POSTMAN的简单使用

postman的基本使用 概述 我相信对于postman的介绍,网上一搜肯定很多很多。下面我就不打算跟大家普及postman了。只看应该怎么用postman进行接口测试。好了,下面咱们直接进入正文吧。 环境 postman之前是作为chrome插件形式存在的。后面变成了独立的应…

【zip密码】zip压缩包删除密码方法

Zip压缩包设置设置了密码,想要删除密码,除了将压缩包解压出来之后再将文件压缩为不带密码的压缩文件以外,还有一种删除密码的方法。设置方法如下: 右键点击zip文件,找到打开方式,以Windows资源管理器方式打…

【STM32】学习笔记(OLED)

调试方式 OLED简介 硬件电路 驱动函数 OLED.H #ifndef __OLED_H #define __OLED_Hvoid OLED_Init(void); void OLED_Clear(void); void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char); void OLED_ShowString(uint8_t Line, uint8_t Column, char *String); void OL…

aarch64-linux交叉编译libcurl带zlib和openssl

交叉编译libcurl需要依赖zlib和openssl 需要先用aarch64工具链编译zlib和openssl aarch64-linux环境搭建 下载工具链 gcc用于执行交叉编译 gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnusysroot是交叉版本的库文件集合 sysroot-glibc-linaro-2.25-2019.12-aarch64-lin…

仿`gRPC`功能实现像调用本地方法一样调用其他服务器方法

文章目录 仿gRPC功能实现像调用本地方法一样调用其他服务器方法 简介单体架构微服务架构RPCgPRC gRPC交互逻辑服务端逻辑客户端逻辑示例图 原生实现仿gRPC框架编写客户端方法编写服务端方法综合演示 仿 gRPC功能实现像调用本地方法一样调用其他服务器方法 简介 在介绍gRPC简介…