STM32 DMA入门指导

什么是DMA

DMA,全称直接存储器访问(Direct Memory Access),是一种允许硬件子系统直接读写系统内存的技术,无需中央处理单元(CPU)的介入。下面是DMA的工作原理概述:
数据传输触发:DMA传输可以由CPU指令触发,也可以由硬件事件(如一个外设准备好数据)自动触发。
外设和内存之间的数据交换:一旦DMA传输开始,DMA控制器会将数据从源地址直接传送到目的地址。源地址常常是外设的数据寄存器,目的地址通常是内存中的一个缓冲区;反之亦然。
CPU解放:在没有DMA的情况下,CPU需要执行多个指令来完成数据的传送,包括数据的读取和写入操作。当使用DMA时,CPU只需初始化传输,之后DMA控制器将自动处理数据传送,CPU则可以执行其他任务。
传输完成中断:当所有数据都被传输至目的地之后,DMA控制器会向CPU发送一个中断信号。这个中断告知CPU数据已经成功传输完毕,CPU随后可以进行后续处理,比如停止DMA,处理数据,或重新初始化另一次DMA传输。
优先级和通道:DMA控制器可能有多个通道,每个通道可以独立配置并与特定的外设关联。在多通道DMA系统中,可能会有优先级设置,以决定哪个DMA请求被优先处理。
DMA是提高数据传输效率、减少CPU负荷、优化系统性能的有效手段,特别是在处理高速数据流或频繁数据传输时。在嵌入式系统和计算机架构中,有了DMA,CPU就可以更有效地处理逻辑计算和数据处理任务,而不是花费大量时间在数据移动上。

DMA可以用于哪些数据传输方式?

DMA 可以用于多种数据传输方式,包括:
1、内存到内存:数据可以直接从一个内存地址复制到另一个内存地址,无需CPU的介入。
2、外设到内存:数据从外设(如ADC,UART接收缓冲区,SPI等)直接传输到内存。这通常用于从外设读取数据时。
3、内存到外设:数据从内存直接传输到外设(如DAC,UART发送缓冲区,SPI等)。这通常在向外设写入数据时使用。
4、外设到外设:虽然不是所有DMA控制器都支持这个功能,但有些高级系统允许直接从一个外设到另一个外设的数据传输,不经过内存。
这些传输方式中,最常见的使用场景是外设到内存和内存到外设。因为这可以大幅度减轻CPU的工作负担,尤其是在数据流量较大时,如从网络接口接收数据包,或向图形处理器发送图像数据。 

DMA初始化的步骤有哪些?

DMA初始化的步骤通常如下所示:
1、DMA控制器时钟使能:
通过 RCC(Reset and Clock Control)模块使能 DMA 控制器的时钟。
2、DMA通道配置:
        a、为目标 DMA 通道配置传输方向(从内存到外设、从外设到内存或者内存到内存)。
        b、设置源地址和目的地址及其增量模式(地址在传输后是否递增)。
        c、配置数据大小(传输的数据宽度,一般为8位、16位或32位)。
        d、设定传输数据的数量(数据块大小)。
3、外设配置:
如果外设(如 ADC, UART, SPI)使用 DMA 进行数据传输,需要在外设的配置中使能相应的 DMA 传输请求。
4、中断配置(可选):
根据实际需要,可以配置并使能传输完成、半传输完成及传输错误中断。
5、DMA流控制(如果适用):
在某些情况下,特别是在使用双缓冲或循环模式时,可能需要配置 DMA 流控制。
6、启动DMA传输:
使用相应的库函数或直接通过控制寄存器启动 DMA 传输。

重要寄存器

STM32微控制器中的DMA(直接存储器访问)寄存器包括几组关键的控制和状态寄存器,用于管理和监控DMA的操作。具体的寄存器会根据STM32的不同系列及其内部架构的差异而有所不同,但一般而言,一个DMA通道会涉及以下几个主要寄存器:
1、DMA控制寄存器 (DMA_CCRx):
控制传输的基本配置,包括传输方向、传输模式(正常或循环模式)、优先级、内存和外设大小、内存增量模式、外设增量模式等。
2、DMA数量寄存器 (DMA_CNDTRx):
包含被传输数据的数量。一次DMA操作开始前,此寄存器需要被加载。
3、DMA外设地址寄存器 (DMA_CPARx):
保存外部外设的基地址。
4、DMA内存地址寄存器 (DMA_CMARx):
保存内存的基地址。这是数据要被传输到或从中传输出的内存位置。
5、DMA状态寄存器 (DMA_ISR):
表示每个通道的状态,包括传输完成、半传输、传输错误和全局中断标志。
6、DMA标志清除寄存器 (DMA_IFCR):
用于清除特定通道的中断标志位。

DMA的状态寄存器具体表示了哪些通道的状态?

DMA的状态寄存器提供了关于各通道传输状态的具体信息,主要包括:
1、传输完成(TC):指示相应DMA通道是否已经完成所配置的数据传输任务。
2、半传输(HT):指示相应DMA通道是否已经完成一半的数据传输(对于某些应用可能需要在传输一半时进行处理)。
3、传输错误(TE):如果DMA通道在传输过程中遇到错误,该标志会被置位。
这些状态可以用来触发中断服务程序(Interrupt Service Routines, ISRs), 允许软件响应DMA传输的完成或错误。开发者通常会在对应的中断处理函数中检查这些状态,以确定传输是否成功,或者是否需要采取措施来处理错误情况。

 
DMA的中断服务程序是如何触发的?

DMA的中断服务程序(ISR)是通过设置DMA控制寄存器中的中断使能位来触发的。具体触发步骤如下:
1、使能中断:在初始化DMA时,你需要在DMA通道的控制寄存器(DMA_CCRx)中使能传输完成中断、半完成中断和/或传输错误中断。
2、配置NVIC:在嵌套向量中断控制器(NVIC)中,你需要为对应的DMA通道中断配置优先级,并使能中断。
3、中断发生:
        a、当DMA传输完指定数量的数据后,如果启用了传输完成中断,DMA控制器将设置状态寄存器(DMA_ISR)的传输完成标志(TC)。
       b、 如果启用了半传输中断,当传输完成一半的数据量时,DMA控制器将设置状态寄存器的半传输完成标志(HT)。
        c、如果在传输过程中发生任何错误,如FIFO溢出或者总线错误等,DMA控制器将设置状态寄存器的传输错误标志(TE)。
4、中断处理:一旦相应的标志位被置位,如果NVIC中对应的中断已使能,CPU将暂停当前任务,跳转到对应的中断服务程序执行中断处理代码。
5、中断标志清除:在中断服务程序中,需要手动清除DMA的状态寄存器中的中断标志位,以防止重复进入中断服务程序。
通过以上步骤,STM32 中的DMA中断服务程序可以在特定的事件发生时被触发,以便进行如数据处理、错误处理等操作。

代码演示

下面是一个简单的STM32程序例子,用于演示如何使用DMA将数据从一个数组复制到另一个数组(内存到内存的DMA传输)

#include "stm32f4xx.h"
// 定义数组大小
#define ARRAYSIZE 5
// 定义源数组和目标数组
uint32_t srcArray[ARRAY_SIZE] = {1, 2, 3, 4, 5};
uint32_t destArray[ARRAY_SIZE] = {0, 0, 0, 0, 0};
void DMA_Config(void)
{// 手动使能DMA1时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);// 创建DMA初始化结构体并填入配置DMA_InitTypeDef DMA_InitStructure;DMA_DeInit(DMA1_Stream0);  // 将DMA Stream恢复到初始状态DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&srcArray;  // 设置DMA源地址DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&destArray;    // 设置DMA目标地址DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;  // 设置内存到内存模式DMA_InitStructure.DMA_BufferSize = ARRAY_SIZE;  // 传输的数据大小DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;   // 外设地址递增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;   // 内存地址递增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; // 32位数据宽度DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; // 32位数据宽度DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;   // 设置为正常模式DMA_InitStructure.DMA_Priority = DMA_Priority_Low; // 设置优先级为低DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;  // FIFO模式禁用DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; // FIFO阈值设置DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; // 单次突发模式DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // 单次突发模式// 初始化DMADMA_Init(DMA1_Stream0, &DMA_InitStructure);// 使能DMA流DMA_Cmd(DMA1_Stream0, ENABLE);// 如果都是定期的规律的检查传输状态,可以留空这里// 如果你需要传输完成的通知,可能需要使用中断和相应的服务函数
}
int main(void)
{// 系统初始化SystemInit();// 配置DMADMA_Config();// 在这里,我们假定系统只是简单地执行一次内存到内存的复制// 复制完后,可以添加代码检查destArray数组中的值// 这里以简单的检查第一个元素是否等于1为例if (destArray[0] == 1){// 如果传输成功,将会进入到这里}// 主循环,程序可以继续执行或者进入睡眠while (1){}
} 

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

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

相关文章

解决Java并发问题的常见思路

写在文章开头 近期对一些比较老的项目进行代码走查,碰到一些极端的并发编程恶习,所以笔者就基于此文演示这类问题以及面对并发编程时我们应该需要了解一些常见套路。 Hi,我是sharkChili,是个不断在硬核技术上作死的java coder&am…

基于 Amazon EKS 的 Stable Diffusion ComfyUI 部署方案

01 背景介绍 Stable Diffusion 作为当下最流行的开源 AI 图像生成模型在游戏行业有着广泛的应用实践,无论是 ToC 面向玩家的游戏社区场景,还是 ToB 面向游戏工作室的美术制作场景,都可以发挥很大的价值,如何更好地使用 Stable Dif…

scanf和cin的利弊

scanf和cin的利弊: scanf: 利:耗时短,写法方便输入固定格式,比如scanf(“%*d%d”,&a),可以直接忽略第一个输入,不用创建新对象,再比如scanf(“%1d”,&x[i]),输入3214&#x…

卡牌——二分

卡牌 题目分析 想一下前面题的特点,是不是都出现了“最大边长”,“最小的数”这种字眼,那么这里出现了“最多能凑出多少套牌”,我们可以考虑用二分。接下来我们要看一下他是否符合二段性,二分的关键在于二段性。 第…

续Java的执行语句、方法--学习JavaEE的day07

day07 一、特殊的流程控制语句 break(day06) continue 1.理解: 作用于循环中,表示跳过循环体剩余的部分,进入到下一次循环 做实验: while(true){ System.out.println(“111”); System.out.println(“222”); if(true){ conti…

编译链接实战(25)gcc ASAN、MSAN检测内存越界、泄露、使用未初始化内存等内存相关错误

文章目录 1 ASAN1.1 介绍1.2 原理编译时插桩模块运行时库2 检测示例2.1 内存越界2.2 内存泄露内存泄露检测原理作用域外访问2.3 使用已经释放的内存2.4 将漏洞信息输出文件3 MSAN1 ASAN 1.1 介绍 -fsanitize=address是一个编译器选项,用于启用AddressSanitizer(地址

基于SpringBoot的教师考勤管理系统(赠源码)

作者主页:易学蔚来-技术互助文末获取源码 简介:Java领域优质创作者 Java项目、简历模板、学习资料、面试题库 教师考勤管理系统是基于JavaVueSpringBootMySQL实现的,包含了管理员、学生、教师三类用户。该系统实现了班级管理、课程安排、考勤…

基于springboot的足球俱乐部管理系统的设计与实现

** 🍅点赞收藏关注 → 私信领取本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅** 一 、设计说明 1.1 课题…

2024.3.3每日一题

LeetCode 用队列实现栈 题目链接:225. 用队列实现栈 - 力扣(LeetCode) 题目描述 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty&…

如何取消ChatGPT 4.0的自动续费和会员订阅(chatgpt4.0自動續費嗎)

如何取消ChatGPT 4.0的自动续费和会员订阅 ChatGPT 4.0自动续费是否存在 是的,ChatGPT 4.0 Plus会员服务存在自动续费功能。 ChatGPT 4.0 Plus会员服务自动续费 ChatGPT Plus会员服务的自动续费机制用户在购买ChatGPT 4.0 Plus会员服务后,系统会自动…

npm ERR! code ERESOLVE

1、问题概述? 执行npm install命令的时候报错如下: tangxiaochuntangxiaochundeMacBook-Pro stf % npm install npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resol…

LeetCode102.二叉树的层序遍历

题目 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 示例 输入:root [3,9,20,null,null,15,7] 输出:[[3],[9,20],[15,7]]输入:root [1] 输出&am…

SpringCloud-MQ消息队列

一、消息队列介绍 MQ (MessageQueue) ,中文是消息队列,字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。消息队列是一种基于生产者-消费者模型的通信方式,通过在消息队列中存放和传递消息,实现了不同组件、服务或系统…

2024全新手机软件下载应用排行、平台和最新发布网站,采用响应式织梦模板

这是一款简洁蓝色的手机软件下载应用排行、平台和最新发布网站,采用响应式织梦模板。 主要包括主页、APP列表页、APP详情介绍页、新闻资讯列表、新闻详情页、关于我们等模块页面。 地 址 : runruncode.com/php/19703.html 软件程序演示图:…

最小高度树-力扣(Leetcode)

题目链接 最小高度树 思路:本质上是找到树中的最长路径。当最长路径上中间点(若路经长为偶数,则中间点仅有一个,否者中间点有两个)作为根时,此时树高最小。 Code: class Solution { public://拓扑排序int…

【深度优先搜索】【树】【C++算法】2003. 每棵子树内缺失的最小基因值

作者推荐 动态规划的时间复杂度优化 本文涉及知识点 深度优先搜索 LeetCode2003. 每棵子树内缺失的最小基因值 有一棵根节点为 0 的 家族树 ,总共包含 n 个节点,节点编号为 0 到 n - 1 。给你一个下标从 0 开始的整数数组 parents ,其中…

第二讲:用geth和以太坊交互

一:安装geth brew install ethereum geth github网址: https://github.com/ethereum/go-ethereum 二: 用geth连接以太坊 以太坊有主网络(Ethereum Mainnet),有测试网络(Sepolia、Goerli 等等…

设计模式学习笔记 - 设计原则 - 5.依赖反转原则(控制反转、依赖反转、依赖注入)

前言 今天学习 SOLID 中的最后一个原则,依赖反转原则。 本章内容,可以带着如下几个问题: “依赖反转” 这个概念指的是 “谁跟谁” 的 “什么依赖” 被反转了? “反转” 这两个字该如何理解。我们还经常听到另外两个概念&#…

【分块三维重建】【slam】LocalRF:逐步优化的局部辐射场鲁棒视图合成(CVPR 2023)

项目地址:https://localrf.github.io/ 题目:Progressively Optimized Local Radiance Fields for Robust View Synthesis 来源:KAIST、National Taiwan University、Meta 、University of Maryland, College Park 提示:文章用了s…

【Spring】20 解析Spring注解驱动的容器配置

文章目录 注解 vs. XMLJavaConfig选项注解配置注解注入顺序注解处理器实际运用总结 Spring 框架一直以 XML 配置为主导,然而随着注解驱动配置的引入,我们不禁思考:是注解配置优于 XML 呢,还是反之?本篇博客将介绍 Spri…