基于STM32 + DMA介绍,应用和步骤详解(ADC多通道)

前言

        本篇博客主要学习了解DMA的工作原理和部分寄存器解析,针对ADC多通道来对代码部分,应用部分作详细讲解,掌握代码编程原理。本篇博客大部分是自己收集和整理,如有侵权请联系我删除。

本次博客开发板使用的是正点原子精英版,芯片是STM32F103ZET6,需要资料可以@我拿取。

交流群:717237739

本博客内容原创,创作不易,转载请注明
————————————————

一 . DMA的基本介绍

  • DMA(Direct Memory Access)直接存储器存取
  • DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
  • DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。
  • DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。

作用:为CPU减负。

因此:转移数据(尤其是转移大量数据)是可以不需要CPU参与。比如希望外设A的数据拷贝到外设B,只要给两种外设提供一条数据通路,直接让数据由A拷贝到B 不经过CPU的处理

二 . DMA的特性

  • 12个独立的可配置的通道(请求)DMA17个通道,DMA25个通道
  • 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
  • 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推)

        在相等的优先级下,DMA1通道2的优先级是 大于 DMA1通道4,通道越低优先级越高。

  • 独立数据源和目标数据区的 传输宽度(字节、半字、全字) ,模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
  • 支持循环的缓冲器管理
  • 每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志
  • 逻辑或成为一个单独的中断请求。
  • 存储器和存储器间的传输
  • 外设和存储器、存储器和外设之间的传输
  • 闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标
  • 可编程的数据传输数目:最大为65535

三. 存储器映像

四 . DMA功能框图 

1.功能描述

DMA控制器和Cortex™-M3核心共享系统数据总线,执行直接存储器数据传输。
        当CPU DMA 同时访问相同的目标(RAM 或外设 ) 时, DMA 请求会暂停 CPU 访问系统总线达若干个周期,总线仲裁器执行循环调度,以保证CPU 至少可以得到一半的系统总线 ( 存储器或外设 ) 带宽。

1DMA2仅存在于大容量产品和互联型产品。
2SPI/I2S3UART4TIM5TIM6TIM7DACDMA请求仅存在于大容量产品和互联型产品。
3ADC3SDIOTIM8DMA请求仅存在于大容量产品。

 2.DMA仲裁器

3.DMA通道 

1.DMA1 控制器 

从外设 (TIMx[x=1 2 3 4] ADC1 SPI1 SPI/I2S2 I2Cx[x=1 2] USARTx[x=1 2 3])
产生的 7 个请求,通过逻辑或输入到 DMA1 控制器,这意味着同时只能有一个请求有效。
外设的 DMA 请求,可以通过设置相应外设寄存器中的控制位,被独立地开启或关闭。

2.DMA 1 各通道一览:

3.DMA 2 控制器

从外设 (TIMx[5 6 7 8] ADC3 SPI/I2S3 UART4 DAC 通道 1 2 SDIO) 产生的 5 个请
求,经逻辑或输入到 DMA2 控制器,这意味着同时只能有一个请求有效。

4.DMA 2 各通道一览:

5.DMA传输方式


        DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节,主要涉及四种情况的数据传输,但本质上是一样的,都是从内存的某一区域传输到内存的另一区域(外设的数据寄存器本质上就是内存的一个存储单元)。四种情况的数据传输如下:

  • 外设到内存

  • 内存到外设

  • 内存到内存

  • 外设到外设

6 .DMA传输参数


  我们知道,数据传输,首先需要的是

1 数据的源地址

2 数据传输位置的目标地址

3 传递数据多少的数据传输量

4 进行多少次传输的传输模式 DMA所需要的核心参数

        当用户将参数设置好,主要涉及源地址、目标地址、传输数据量这三个,DMA控制器就会启动数据传输,当剩余传输数据量为0时 达到传输终点,结束DMA传输 ,当然,DMA 还有循环传输模式 当到达传输终点时会重新启动DMA传输。
  
也就是说只要剩余传输数据量不是0,而且DMA是启动状态,那么就会发生数据传输。

6. stm32中DMA的circle和normal模式的区别

 

在STM32系列微控制器上,DMA(Direct Memory Access,直接内存访问)是一种用于高效数据传输的重要功能。DMA的Circle(循环)模式和Normal(普通)模式是两种常见的DMA传输模式,它们在数据传输方面有一些区别。

Circle(循环)模式:

  • 在Circle模式下,DMA传输可以循环执行,即在完成一次传输后会自动重新开始下一次传输,形成一个循环。这种模式适用于需要连续、循环传输数据的场景。
  • 在循环模式下,DMA传输会持续不断地从源地址读取数据,并将数据写入目标地址,直到达到设定的传输长度或触发停止条件。
  • 循环模式下的DMA传输通常用于周期性的数据传输,如音频、视频流等连续数据流的传输。

Normal(普通)模式:

  • 在Normal模式下,DMA传输只会执行一次,传输完毕后就会停止。这种模式适用于单次数据传输的场景。
  • 在普通模式下,DMA传输会从源地址读取数据,并将数据写入目标地址,直到达到设定的传输长度或触发停止条件,然后传输停止。
  • 普通模式下的DMA传输适用于需要一次性传输数据的情况,如初始化数据、配置信息等。

需要注意的是,循环模式和普通模式都可以设置传输长度、源地址和目标地址等参数,区别主要在于传输的执行方式和传输结束后是否重新开始。

在使用DMA时,需要根据具体的应用需求选择适合的模式。

如果需要连续、循环传输数据,可以选择循环模式;

如果只需进行单次传输,可以选择普通模式。

同时,还需要注意设置适当的传输长度和停止条件,以确保传输的准确性和可靠性。
 

五 . DMA 的配置和应用

1.DMA运作过程图解:

下面看有与没有DMA的情况下,ADC采集的数据是怎样存放到SRAM中的?

没有DMA

1.如果没有DMA,CPU传输数据还要以内核作为中转站,比如要将ADC采集的数据转移到到SRAM中,这个过程是这样的:

内核通过DCode经过总线矩阵协调,从获取AHB存储的外设ADC采集的数据,

然后内核再通过DCode经过总线矩阵协调把数据存放到内存SRAM中。

 

参考博客链接:https://blog.csdn.net/as480133937/article/details/104927922

2.DMA数据流(仅存在于STM32F4 /M4 内核上)了解即可

在设置了DMA的通道之后,还要选择通道对应外设的数据流

3.指针增量

存储器到存储器:源和目标的指针都需要设置为增量模式

存储器到外设 存储器地址设置为增量模式外设地址设置为非增量模式。

4.通道配置过程:

0 .开DMA时钟

1. DMA_CPARx寄存器中设置外设寄存器的地址。发生外设数据传输请求时,这个地址将
是数据传输的源或目标。
2. DMA_CMARx寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数
据将从这个地址读出或写入这个地址。
3. DMA_CNDTRx寄存器中设置要传输的数据量。在每个数据传输后,这个数值递减。
4. DMA_CCRx寄存器的PL[1:0]位中设置通道的优先级。
5. DMA_CCRx寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、
设和存储器的数据宽度 ---CCRX存器
6. 设置DMA_CCRx寄存器的ENABLE位,启动该通道。

5 .DMA中断

 每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断。为应用的灵活性考虑,通过设置寄存器的不同位来打开这些中断。

 六. DMA配置过程

这个部分我们结合ADC来进行讲解使用:

DMA配置参数包括:通道地址、优先级、数据传输方向、存储器/外设数据宽度、存储器/外设地址是否增量、循环模式、数据传输量。

 ADC+DMA多通道框图:

ADC详解在另一个博客:ADC 讲解

配置初始化代码:

#include "stm32f10x.h"                  // Device headeruint16_t AD_Value[4];void AD_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//开启对应通道ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);ADC_InitTypeDef ADC_InitStructure;			ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;								//ADC工作模式:ADC1和ADC2工作在独立模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;							//数据右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;									//模数转换工作在循环转换模式ADC_InitStructure.ADC_ScanConvMode = ENABLE;												//模数转换工作在多通道模式ADC_InitStructure.ADC_NbrOfChannel = 4;															//顺序进行规则转换的ADC通道的数目ADC_Init(ADC1, &ADC_InitStructure);										//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;							// ADC- DMA外设基地址DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	//半字传输,数据宽度为16位DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;						//外设地址不自增DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;									//存储器数据存储地址  数组DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;					//半字传输,数据宽度为16位DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;											//存储器内存地址寄存器递增DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;													//数据传输方向,从外设读取发送到存储器DMA_InitStructure.DMA_BufferSize = 4;																				//扫描通道:4个DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;															//循环模式DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;																//DMA通道x没有设置为内存到内存传输DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;												//DMA通道 x拥有中优先级 DMA_Init(DMA1_Channel1, &DMA_InitStructure);DMA_Cmd(DMA1_Channel1, ENABLE);									//使能DMAADC_DMACmd(ADC1, ENABLE);												//使能ADC_DMA传输ADC_Cmd(ADC1, ENABLE);													//使能ADCADC_ResetCalibration(ADC1);													//使能复位校准  while (ADC_GetResetCalibrationStatus(ADC1) == SET);	//等待复位校准结束ADC_StartCalibration(ADC1);													//开启AD校准while (ADC_GetCalibrationStatus(ADC1) == SET);			//等待校准结束ADC_SoftwareStartConvCmd(ADC1, ENABLE);							//使能指定的ADC1的软件转换启动功能
}

 库函数讲解,摘自群友的笔记:

 

总结:


      DMA的使用并不复杂,搞清楚数据的方向,还是是否自增就行了,多使用多实践,大家如果对我的博客有疑问或者错误,可以@我修改,大家相互交流。

交流群:717237739

如果觉得有用点赞关注收藏三连,多谢支持

  点赞收藏关注博主,不定期分享单片机知识,互相学习交流。
————————————————

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot_java养老院老年人问诊服务预约系统ssm

系统的目标是为管理员,服务者,医生和用户搭建一个网上沟通平台,保证四方的安全,并使四方的利益最大化。 .用户: (1)用户注册登入页面:用户进行操作时需要是已注册登入用户 &#xff…

WireShark监控浏览器登录过程网络请求

软件开发中经常前后端扯皮。一种是用Chrome浏览器的开发者工具 来看网络交互,但是前提是 网络端口的确是通的。 WireShark工作在更低层。 这个工具最大的好处,大家别扯皮,看网络底层的log,到底 你的端口开没开, 数据…

结合ColorUI组件开发微信小程序

1.自定义组件生命周期函数: Component({data: {},attached() {console.log("自定义组件生命周期函数 attached--先执行");this.getPos();},ready() {console.log("ready生命周期函数---在attached之后执行")},methods: {getPos() {var that th…

uniapp 使用 $emit和$on——$on中无法为data中的变量赋值

问题在于this的指向&#xff0c; 解决办法是使用变量保存$on&#xff0c;其次再为data中的值赋值 以下是具体代码&#xff1a; 1、html代码&#xff1a; <view class"form_picker" click"selePositionFun()"><view class""><inp…

基于remix+metamask+ganache的智能合约部署调用

在我们部署合约时为了让它更接近真实区块链去中心化体验&#xff0c;我们需要调用小狐狸&#xff08;Metamask&#xff09;来进行真实交易&#xff0c;而metamask里没有内置虚拟测试币&#xff0c;我们需要进行调用Ganache来添加带有虚拟测试币的账号。以上就是三者的关系&…

PHP基础 - 输入输出

在 PHP 中,有多种方法可以用来输出内容。下面是其中的几种: 1、echo: 这是最常见的输出语句之一,可以输出一个或多个字符串。它是一个语言结构,可以省略括号。使用示例如下: <?php // 使用 echo 语句输出一个字符串 echo "Hello, world!\n";// 可以使用…

面向对象中的单例模式

1、什么是设计模式 设计模式就是前人根据实际的问题提出的问题解决方案&#xff0c;我们把这种就称之为设计模式。 2、单例模式 单例模式是一种常见的设计模式&#xff01; 所谓的设计模式&#xff0c;不是一种新的语法&#xff0c;而是人们在实际的应用中&#xff0c;面对…

数据结构之哈希表

数据结构之哈希表 文章目录 数据结构之哈希表一、哈希概念二、哈希冲突三、哈希函数常见哈希函数 四、哈希冲突解决闭散列闭散列的思考线性探测线性探测的实现 二次探测 开散列开散列概念开散列的思考开散列实现 五、开散列与闭散列比较 一、哈希概念 顺序结构以及平衡树中&am…

2023-12-05 Qt学习总结2

点击 <C 语言编程核心突破> 快速C语言入门 Qt学习总结 前言五 Hello Qt!六 Qt控件和事件七 Qt信号和槽八 Qt自定义信号和槽总结 前言 要解决问题: 学习qt最核心知识, 多一个都不学. 五 Hello Qt! 现在我们已经有了一个空窗口工程, 传统上, 我们要实现一个"Hello …

2023最新八股文前端面试题

第一章 Css 1.说一下CSS的盒模型。 在HTML页面中的所有元素都可以看成是一个盒子盒子的组成:内容content、内边距padding、边框border、外边距margin盒模型的类型: 标准盒模型 margin border padding content IE盒模型 margin content(border padding) 控制盒模型的模式…

linux下部署frp客户端服务端-内网穿透

简介 部署在公司内部局域网虚拟机上的服务需要在外网能够访问到&#xff0c;这不就是内网穿透的需求吗&#xff0c;之前通过路由器实现过&#xff0c;现在公司这块路由器不具备这个功能了&#xff0c;目前市面上一些主流的内网穿透工具有&#xff1a;Ngrok&#xff0c;Natapp&…

金融银行业更适合申请哪种SSL证书?

在当今数字化时代&#xff0c;金融行业的重要性日益增加。越来越多的金融交易和敏感信息在线进行&#xff0c;金融银行机构必须采取必要的措施来保护客户数据的安全。SSL证书作为一种重要的安全技术工具&#xff0c;可以帮助金融银行机构加密数据传输&#xff0c;验证网站身份&…

Uncle Maker: (Time)Stamping Out The Competition in Ethereum

目录 笔记后续的研究方向摘要引言贡献攻击的简要概述 Uncle Maker: (Time)Stamping Out The Competition in Ethereum CCS 2023 笔记 本文对以太坊 1 的共识机制进行了攻击&#xff0c;该机制允许矿工获得比诚实同行更高的挖矿奖励。这种名为“Uncle Maker”的攻击操纵区块时间…

机器视觉相机镜头光源选型

镜头选型工具 - HiTools - 海康威视 Hikvisionhttps://www.hikvision.com/cn/support/tools/hitools/cl8a9de13648c56d7f/ 海康机器人-机器视觉产品页杭州海康机器人股份有限公司海康机器人HIKROBOT是面向全球的机器视觉和移动机器人产品及解决方案提供商&#xff0c;业务聚焦于…

【Python】 生成二维码

创建了一个使用 python 创建二维码的程序。 下面是生成的程序的图像。 功能描述 输入网址&#xff08;URL&#xff09;。 输入二维码的名称。 当单击 QR 码生成按钮时&#xff0c;将使用 QRname 中输入的字符将 QR 码生成为图像。 程序代码 import qrcode import tkinterd…

<习题集><LeetCode><链表><61/83/82/86/92>

目录 61. 旋转链表 83. 删除排序链表中的重复元素 82. 删除排序链表中的重复元素 II 86. 分隔链表 92. 反转链表 II 61. 旋转链表 https://leetcode.cn/problems/rotate-list/ public ListNode rotateRight(ListNode head, int k) {//k等于0&#xff0c;或者head为空&…

【数据结构】单调栈与单调队列算法总结

单调栈 知识概览 单调栈最常见的应用是找到每一个数离它最近的且比它小的数。单调栈考虑的方式和双指针类似&#xff0c;都是先想一下暴力做法是什么&#xff0c;然后再挖掘一些性质如单调性&#xff0c;最终可以把目光集中在比较少的状态中&#xff0c;从而达到降低时间复杂…

Java LeetCode篇-深入了解二叉树的经典解法(多种方式实现:构造二叉树)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 从前序与中序遍历序列来构造二叉树 1.1 实现从前序与中序遍历序列来构造二叉树思路 1.2 代码实现从前序与中序遍历序列来构造二叉树 2.0 从中序与后序遍历序…

Qt/C++音视频开发58-逐帧播放/上一帧下一帧/切换播放进度/实时解码

一、前言 逐帧播放是近期增加的功能&#xff0c;之前也一直思考过这个功能该如何实现&#xff0c;对于mdk/qtav等内核组件&#xff0c;可以直接用该组件提供的接口实现即可&#xff0c;而对于ffmpeg&#xff0c;需要自己处理&#xff0c;如果有缓存的数据的话&#xff0c;可以…

HXDSP2441-Demo板

板卡图示 下图为HXDSP2441DEMO板&#xff0c;HXDSP2441DEMO板是围绕HXDSP2441构建的芯片演示验证平台。 板卡简介 除了为HXDSP2441芯片提供供电、时钟、储存、网络及调试电路&#xff0c;来实现芯片最基本的功能&#xff0c;也添加了相关模块以搭建HXDSP2441的典型应用场景…