当前位置: 首页 > news >正文

STM32DMA数据传输

我估计大多数人学这么久连听说都没听说过DMA,更不用提知道它是干嘛的。其实DMA的本质就是一个数据的搬运工。平常的时候当我们没有配置的时候,一直都是CPU在搬运数据,但是这个活又累又没有技术含量,所以DMA的重要性还是有的。

目录

1.DMA的数据搬运:

1.DMA数据路径

2.DMA搬运模式

优先级的设定:

通道:

搬运是否循环: 

指针是否递增:

2.DMA的框架

3.DMA函数与配置

函数

配置:

内存-内存配置:

内存-外设的配置:

外设-内存(重点)

好了,祝你看完就会。


1.DMA的数据搬运:

1.DMA数据路径

简单来说,只有三种:

内存--内存               DMA_MEMORY_TO_MEMORY

外设--内存               DMA_PERIPH_TO_MEMORY

内存--外设                DMA_MEMORY_TO_PERIPH

这里的外设其实是指的STM32板子上的外设,比如GPIO口啊,串口啊等等。而所谓内存,从代码上来看其实就是一个变量。

2.DMA搬运模式

这里可配置的东西有:

优先级设定;指针是否递增;搬运模式是否循环;通道的选择。其实都没有什么难度,只不过看起来花里胡哨的,我依次讲解。

优先级的设定:

DMA的优先级采用的是硬件+软件,什么意思呢?其实本质是 通道号+软件优先级。在使用过程中,我们往往同时配置多个通道,当两个通道内的数据同时到达时,优先看软件优先级,再看通道号。注意:通道号越小优先级越。

通道:

DMA的通道其实和定时器的有点像,DMA通过通道连接各种外设,从而实现数据传输。在配置中,外设往往也配置了对应的DMA句柄来接应。所以这里对于通道只需要知道要按照表格对应来选择就行。
 注意:通常情况下芯片都只有DMA1没有DMA2.

搬运是否循环: 

DMA_Mode_Normal(正常模式):一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次 DMA_Mode_Circular(循环传输模式) :当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。 也就是多次传输。注意:当循环结束后假设给内存设定为了指针递增,此时指针会重置回到缓存最开始指向的地方。(假设缓存为arr[4]传输完成时指向arr[3],循环结束后指针会自动回归为arr[0])

指针是否递增:

数据源和目标缓存都有一个对应的指针来指向它从而使得数据知道存哪,在配置中也是分别配置是否递增的。不用想那么复杂,就一句话:数据来自或者要去内存则为递增,外设则不递增

解释:因为外设来源的数据往往放在xx寄存器里,数据一直是更新覆盖的;所以不用递增。内存就不一样了,内存往往是数组或者一个xxbuf,不递增的话就覆盖掉了。

另外还有一项配置叫数据对齐模式,其实都一般配置为:DMA_PDATAALIGN_BYTE

2.DMA的框架

3.DMA函数与配置

函数

__HAL_RCC_DMA1_CLK_ENABLE(…)        使能DMA时钟的

HAL_DMA_Init(…)                                           跟TIM的INIT用法一样

HAL_DMA_Start(…)                                        搬运函数。

__HAL_LINKDMA(…)                                      连接内存到外设数据通道的。

__HAL_DMA_GET_FLAG(…)                          获取DMA寄存器标志位的

配置:

基本的配置的步骤为:
          DMA时钟使能:__HAL_RCC_DMA1_CLK_ENABLE();
                                        |
DMA初始化(通道选择;优先级;指针递增;数据对齐;搬运模式:HAL_DMA_Init()
                                        |
DMA搬运:如果是和外设进行交互,那么这一步会变化,在代码中详解。
                                        |
                查询DMA数据是否传输正常完成

内存-内存配置:
DMA_HandleTypeDef hdma_handle = {0};
void DMA_INIT(){__HAL_RCC_DMA1_CLK_ENABLE();	//内存配置hdma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_handle.Init.MemInc = DMA_MINC_ENABLE;//外设配置(目标存储配置)hdma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_handle.Init.PeriphInc = DMA_PINC_ENABLE;//模式;优先级;转运方向配置hdma_handle.Init.Mode = DMA_NORMAL;hdma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;hdma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY;hdma_handle.Instance = DMA1_Channel1;	HAL_DMA_Init(&hdma_handle);}
void DMA_Transport(){HAL_DMA_Start(&hdma_handle,(uint32_t)Sroce_buf,(uint32_t)Target_buf,sizeof(uint32_t) * 16);while(__HAL_DMA_GET_FLAG(hdma_handle,DMA_FLAG_TC1) == RESET){int i = 0;for(i = 0;i<16;i++){printf("data[%d] = %X \r\n",i,Target_buf[i]);}}
}
内存-外设的配置:
#include "dma.h"
extern UART_HandleTypeDef uart1_handle;
DMA_HandleTypeDef hdma_handle = {0};
void DMA_INIT(){__HAL_RCC_DMA1_CLK_ENABLE();hdma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_handle.Init.MemInc = DMA_MINC_ENABLE;hdma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_handle.Init.PeriphInc = DMA_PINC_DISABLE;			//外设内存不可递增。hdma_handle.Init.Mode = DMA_NORMAL;hdma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;hdma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;		//内存到外设hdma_handle.Instance = DMA1_Channel4;HAL_DMA_Init(&hdma_handle);//链接函数,这里是吧DMA和外设连接起来,中间的参数是外设句柄中的DMA成员变量//可以理解为,每一个外设都配有DMA成员变量,为的就是和DMA连接。__HAL_LINKDMA(&uart1_handle,hdmatx,hdma_handle);
}在main中:DMA_INIT();	HAL_UART_Transmit_DMA(&uart1_handle,Send_buf,1024);

 这里注意 HAL_UART_Transmit_DMA(&uart1_handle,Send_buf,1024); 是使用了外设对应的API,利用传输过来的句柄进行传输。

外设-内存(重点)
#include "dma.h"
#include "stdio.h"
#include "uart1.h"extern UART_HandleTypeDef uart1_handle;
extern uint8_t uart1_rx_buf[UART1_RX_BUF_SIZE];
DMA_HandleTypeDef dma_handle = {0};
void dma_init(void)
{__HAL_RCC_DMA1_CLK_ENABLE();dma_handle.Instance = DMA1_Channel5;dma_handle.Init.Direction = DMA_PERIPH_TO_MEMORY;dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;dma_handle.Init.MemInc = DMA_MINC_ENABLE;dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;dma_handle.Init.Mode = DMA_NORMAL;HAL_DMA_Init(&dma_handle);__HAL_LINKDMA(&uart1_handle, hdmarx, dma_handle);HAL_UART_Receive_DMA(&uart1_handle, uart1_rx_buf, UART1_RX_BUF_SIZE);
}

基本配置中有两个重点,一个是extern外面串口的变量,另一个是链接到外设的函数,如果展开的来看的话,LINK函数内部是把该句柄赋值给了串口句柄中的成员变量DMA句柄

第二个重点是: HAL_UART_Receive_DMA该函数配置的是 串口句柄 目标缓存 传输大小,其中,传输大小最为重要,这里传输大小配置为了缓存区的长度大小。

void USART1_IRQHandler(void)
{if (__HAL_UART_GET_FLAG(&uart1_handle, UART_FLAG_IDLE) != RESET)        {                         __HAL_UART_CLEAR_IDLEFLAG(&uart1_handle);HAL_UART_DMAStop(&uart1_handle);uart1_rx_len = UART1_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(&dma_handle);printf("recv: %s, recv_len: %d\r\n", uart1_rx_buf, uart1_rx_len);uart1_rx_clear();HAL_UART_Receive_DMA(&uart1_handle, uart1_rx_buf, UART1_RX_BUF_SIZE);}
}

这里代码很短但是非常有机制可谈,其中长度的计算就非常有的说:
首先:DMA的传输长度被配置为了缓存器的长度
其次:DMA在传输过程中当没有传输足够配置的长度但数据源为空时会进入等待
然后:这里配置了HAL_UART_DMAStop函数使得DMA停止传输并保持了当前状态。
再然后:使用__HAL_DMA_GET_COUNTER会返回当前未传输任务中还未传输的长度
最后:使用缓存大小 - __HAL_DMA_GET_COUNTER的返回值 = 已传输的值。

我用数字再解释一遍:假设配置DMA传输长度为10,此时串口接收到了4,DMA传输进缓存区4的数据,此时数据源为空DMA进入等待;于此同时串口接收完成触发空闲中断,此时调用函数Stop使得DMA停止传输保持当前状态,GET_COUNTER返回的值为6,所以直接10 - 6 = 4也就是接收到的数据长度。

其中,Stop函数是必要的,因为如果长时间没有接收或者新的数据进入都会导致GET返回值变化。

好了,祝你看完就会。

相关文章:

STM32DMA数据传输

我估计大多数人学这么久连听说都没听说过DMA&#xff0c;更不用提知道它是干嘛的。其实DMA的本质就是一个数据的搬运工。平常的时候当我们没有配置的时候&#xff0c;一直都是CPU在搬运数据&#xff0c;但是这个活又累又没有技术含量&#xff0c;所以DMA的重要性还是有的。 目…...

Python学习笔记50:游戏篇之外星人入侵(十一)

前言 本篇文章接着之前的内容&#xff0c;继续对游戏功能进行优化&#xff0c;主要是优化游戏状态以及对应的处理。 状态 一个游戏包含多种状态&#xff0c;这个状态是一个可以很复杂也可以很简单的内容。条件所限&#xff0c;我们这个游戏的状态就比较简单&#xff1a; 未…...

vue3踩坑问题记录

//vue3element-plus //1、placeholder换行显示 const startTxt ref() const contentText ref<any>() startTxt.value "请描述问题内容、例如&#xff1a;" historyData.prompt.forEach((el:any)>{contentText.value \n${el.question}}) <ElInputv-mo…...

Python 爬虫实战:Scrapy 框架详解与应用

&#x1f6e0;️ Scrapy 框架基本使用 Scrapy 是一个强大的 Python 爬虫框架&#xff0c;提供了用于提取和处理网页数据的功能。以下是 Scrapy 的基本使用步骤&#xff1a; 安装 Scrapy pip install scrapy创建 Scrapy 项目 scrapy startproject myproject这将生成一个基础…...

60 函数参数——关键参数

关键参数主要指调用函数时的参数传递方式&#xff0c;与函数定义无关。 通过关键参数可以按参数名字传递值&#xff0c;明确指定哪个值传递给哪个参数&#xff0c;实参顺序可以和形参顺序不一致&#xff0c;但不影响参数值的传递结果&#xff0c;避免了用户需要牢记参数位置和…...

wps 最新 2019 专业版 下载安装教程,解锁全部功能,免费领取

文章目录 前言软件介绍软件下载安装步骤激活步骤小福利&#xff08;安卓APP&#xff09;软件介绍软件下载安装步骤 前言 本篇文章主要针对WPS2019专业版的安装下载进行详细讲解&#xff0c;软件已激活&#xff0c;可放心使用&#xff1b;并且可以进行账号登录&#xff0c;进行…...

前端(三):Ajax

一、Ajax Asynchronous JavaScript And XML&#xff0c;简称Ajax&#xff0c;是异步的JavaScript和XML。 作用&#xff1a;数据交换&#xff0c;通过Ajax可以给服务器发送请求&#xff0c;并获取服务器响应的数据。异步交互&#xff1a;可以在不重新加载整个页面的情况下&…...

启动 /使用/关闭 Redis 服务器

1. Linux 启动 Linux 系统启动 Redis 有两种方法&#xff0c;分别是前台启动&#xff0c;后台启动&#xff0c;两者各有差异&#xff1b; &#xff08;1&#xff09;前台启动 首先&#xff0c;需要进入 bin 路径(安装路径不同输入的命令也不同); 个人的命令&#xff08;一般…...

Linux系统中的高级SELinux安全策略定制技术

随着信息技术的发展&#xff0c;计算机系统的安全性变得越来越重要。在开源世界中&#xff0c;Linux作为一种广泛应用的操作系统&#xff0c;其安全性一直备受关注。其中&#xff0c;SELinux&#xff08;Security-Enhanced Linux&#xff09;作为Linux系统中的一个安全模块&…...

使用 Ansible Blocks 进行错误处理

注&#xff1a;机翻&#xff0c;未校。 How to Use Ansible Blocks Make your Playbooks more readable and maintainable using Blocks feature in Ansible. 使用 Ansible 中的块功能使 Playbook 更具可读性和可维护性。 Jul 15, 2024 — LHB Community How to Use Ansible…...

java中的静态变量和实例变量的区别

java中的静态变量和实例变量的区别 在Java中&#xff0c;静态变量&#xff08;也称为类变量&#xff09;和实例变量是两种不同类型的变量&#xff0c;它们在多个方面存在显著的区别。以下是它们之间的一些主要区别&#xff1a; 存储位置 静态变量&#xff1a;存储在方法区&am…...

【Effecutive C++】条款02 尽量以const, enum, inline替换 #define

Prefer consts, enums, and inline to #define. 这个条款或许改为“宁可以编译器替换预处理器”比较好&#xff0c;因为或许#define不被视为语言的一部分。那正是它的问题所在。当你做出这样的事情&#xff1a; #define ASPECT_RATIO 1.653记号名称ASPECT_RATIO也许从未被编译…...

leetcode-226. 翻转二叉树

题目描述 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#xff1a;[2,3,1]…...

用的到linux-tomcat端口占用排查-Day5

前言&#xff1a; 最近使用tomcat搭建了一套测试环境的应用&#xff0c;整个搭建过程也很简单&#xff0c;就是将部署包上传至服务器☞解压☞启动tomcat服务器&#xff0c;当然服务器也是成功启动了&#xff0c;但是发现前端应用报404&#xff0c;具体如下图所示。 一、现象及思…...

mqtt协议详解(0)初步认识mqtt

文章目录 1. 介绍2. 主要特性3. 架构1. 介绍 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种构建在TCP/IP协议之上的轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境,例如IOT。 MQTT 协议于 1…...

Java语言程序设计基础篇_编程练习题*16.7 (设置时钟的时间)

*16.7 (设置时钟的时间) 编写一个程序&#xff0c;显示一个时钟&#xff0c;并通过在三个文本域中输入小时、分钟和秒 钟来设置时钟的时间&#xff0c;如图16-38b 所示。使用程序清单14-21的ClockPane改变时钟大小使其居于面板中央 习题思路 实例化一个ClockPane(在程序清单1…...

YOLOv8新版本支持实时检测Transformer(RT-DETR)、SAM分割一切

原文:YOLOv8新版本支持实时检测Transformer(RT-DETR)、SAM分割一切 - 知乎 (zhihu.com) 一、SAM 分割任何模型 (Segment Anything Model - SAM) 是一种突破性的图像分割模型,可实现具有实时性能的快速分割。 项目地址 https://github.com/facebookresearch/segment-…...

【传输层协议】UDP和TCP协议

文章目录 UDP协议UDP特点UDP的缓冲区基于UDP的应用层协议 TCP协议6位标志位&#xff1a;确认应答机制超时重传机制连接管理机制&#xff08;握手和挥手&#xff09;服务端状态转换过程客户端状态转换过程TIME_WAIT状态CLOSE_WAIT状态 为什么是三次握手和四次挥手滑动窗口如果发…...

Java Excel复杂表头,表头合并单元格

Java Excel复杂表头&#xff0c;表头合并单元格 效果预览 一、maven依赖 <!--操作excel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.1</version><scope>test</…...

Java整合腾讯云发送短信实战Demo

简介 在现代应用开发中&#xff0c;短信服务是非常重要的功能之一。它可以用于用户验证、通知等各种场景。本文将介绍如何使用Java整合腾讯云短信服务&#xff0c;并提供一个完整的实战示例代码。 环境准备 在开始之前&#xff0c;确保你已经完成以下准备工作&#xff1a; 注…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...