STM32HAL库--DMA实验(速记版)

news2024/10/6 14:30:42

本章利用 DMA 来实现串口数据传送,并在LCD 模块上显示当前的传送进度。

DMA 简介

        DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。
        STM32F429 最多有 2 个 DMA 控制器共 16 个数据流(每个控制器 8 个),每一个 DMA控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达 8 个通道(或称请求)。每个数据流通道都要一个仲裁器,用于处理 DMA 请求间的优先级。


        STM32F429 的 DMA 有以下一些特性:
① 双 AHB 主总线架构,一个用于存储器访问,另一个用于外设访问
② 仅支持 32 位访问的 AHB 从编程接口
③ 每个 DMA 控制器有 8 个数据流,每个数据流有多达 8 个通道(或称请求)
④ 每个数据流有单独的四级 32 位先进先出存储器缓冲区(FIFO),可用于 FIFO 模式或直接模式。
⑤ 通过硬件可以将每个数据流配置为:
1,支持外设到存储器、存储器到外设和存储器到存储器传输的常规通道
2,支持在存储器方双缓冲的双缓冲区通道
⑥ 8 个数据流中的每一个都连接到专用硬件 DMA 通道(请求)
⑦ DMA 数据流请求之间的优先级可用软件编程(4 个级别:非常高、高、中、低),在软件优先级相同的情况下可以通过硬件决定优先级(例如,请求 0 的优先级高于请求 1)
每个数据流也支持通过软件触发存储器到存储器的传输(仅限 DMA2 控制器)
⑨ 可供每个数据流选择的通道请求多达 8 个。此选择可由软件配置,允许几个外设启动 DMA 请求
⑩ 要传输的数据项的数目可以由 DMA 控制器或外设管理:
        1,DMA 流控制器:要传输的数据项的数目是 1 到 65535,可用软件编程
        2,外设流控制器:要传输的数据项的数目未知并由源或目标外设控制,这些外设通过硬件发出传输结束的信号。
⑪ 独立的源和目标传输宽度(字节、半字、字):源和目标的数据宽度不相等时,DMA 自动封装/解封必要的传输数据来优化带宽。这个特性仅在 FIFO 模式下可用。
⑫ 对源和目标的增量或非增量寻址
⑬ 支持 4 个、8 个和 16 个节拍的增量突发传输。突发增量的大小可由软件配置,通常等于外设FIFO 大小的一半。
⑭ 每个数据流都支持循环缓冲区管理
⑮ 5 个事件标志(DMA 半传输DMA 传输完成DMA 传输错误DMA FIFO 错误直接模式错误),进行逻辑或运算,从而产生每个数据流的单个中断请求。

DMA 框图

        STM32F429有两个 DMA控制器,DMA1和DMA2。每个 DMA 控制器有 8 个数据流,每个数据流有 8 个通道(或称请求)。DMA2 支持通过软件触发存储器到存储器的传输。

图中,我们标记了 6 处位置,起作用分别是:
① DMA 控制器的从机编程接口,通过该接口可以对 DMA 的相关控制寄存器进行设置,从而配置 DMA,实现不同的功能。
② DMA 控制器的外设接口,用于访问相关外设,特别的,当外设接口设置的访问地址是内存地址的时候,DMA 就可以工作在内存到内存模式了。
③ DMA 控制器的 FIFO 区,每个数据流(总共 8 个数据流)都有一个独立的 FIFO,可以实现存储器接口到外设接口之间的数据长度非对齐传输。
④ DMA 控制器的存储器接口,用于访问外部存储器,特别的当存储器地址是外设地址的时候,可以实现类似外设到外设的传输效果。
⑤ DMA 控制器的仲裁器,用于仲裁数据流 0~7 的请求优先级,保证数据有序传输。
⑥ DMA 控制器数据流多通道选择。

通过 DMA_SxCR 寄存器控制,每个数据流有多达 8 个通道请求可以选择,如图所示:

        外设的 8 个请求独立连接到每个通道,由 DMA_SxCR 控制数据流选择哪一个通道,每个数据流有 8 个通道可供选择,每次只能选择其中一个通道进行 DMA 传输。DMA1 各数据流通道映射具体见表 31.1.1.1,DMA2 各数据流通道映射具体见表 31.1.1.2。

DMA 寄存器

⚫ DMA 中断状态寄存器(DMA_LISR 和 DMA_HISR

        DMA 中断状态寄存器,该寄存器总共有 2 个:DMA_LISR 和 DMA_HISR,每个寄存器管理 4 数据流,DMA_LISR 寄存器用于管理数据流 0~3,而 DMA_HISR 用于管理数据流 4~7。这两个寄存器各位描述都完全一模一样,只是管理的数据流不一样。

        DMA 中断状态寄存器 LISR 和 HISR 用来存放对应 4 个数据流对应的 5 个传输状态对应的中断标志位,分别是 传输完成中断标志半传输中断标志传输错误中断标志直接模式错误中断标志FIFO 错误中断标志。注意此寄存器为只读寄存器,所以在这些位被置位之后,只能通过其他的寄存器来清除。DMA_HISR 寄存器各位描述通 DMA_LISR寄存器各位描述完全一样,只是对应数据流 4~7 。

⚫ DMA 中断标志清除寄存器(DMA_LIFCR 和 DMA_HIFCR

        DMA 中断标志清除寄存器, 该寄存器同样有 2 个:DMA_LIFCR 和 DMA_HIFCR,同样是每个寄存器控制 4 个数据流,DMA_LIFCR 寄存器用于管理数据流 0~3,而 DMA_ HIFCR 用于管理数据流 4~7。

        LIFCR 的各位就是用来清除 LISR 的对应位的,通过写1清除。在 LISR 被置位后,我们必须通过向该位寄存器对应的位写入 1 来清除。

⚫ DMA 数据流 x 配置寄存器(DMA_SxCR)(x=0~7,下同)

        该寄存器控制着 DMA 的很多相关信息,包括数据宽度、外设及存储器的宽度、优先级、增量模式、传输方向、中断允许、使能等都是通过该寄存器来设置的。所以 DMA_SxCR 是 DMA 传输的核心控制寄存器。

⚫ DMA 数据流 x 数据项数寄存器DMA_SxNDTR

        该寄存器控制 DMA 数据流 x 的每次传输所要传输的数据量。其设置范围为 0~65535。且该寄存器的值会随着传输的进行而减少,当该寄存器的值为 0 的时候就代表此次数据传输已经全部发送完成了。所以可以通过这个寄存器的值来知道当前 DMA 传输的进度。特别注意,这里是数据项数目,而不是指的字节数。比如设置数据位宽为 16 位,那么传输一次(一个项)就是 2 个字节。

DMA数据传输实验

例程:按下按键,串口以 DMA 方式发送数据,同时 LCD 上显示传输进度。

DMA 的 HAL 库驱动:
DMA 在 HAL 库中的驱动代码在 stm32f4xx_hal_dma.c 文件(及其头文件)中。

DMA 的初始化函数,其声明如下:
HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);
⚫ 函数描述:
用于初始化 DMA1,DMA2。
⚫ 函数形参:
形参 1 是 DMA_HandleTypeDef 结构体类型指针变量,其定义如下:

typedef struct __DMA_HandleTypeDef
{
 DMA_Stream_TypeDef *Instance; /* 寄存器基地址 */
 DMA_InitTypeDef Init; /* DAM 通信参数 */
 HAL_LockTypeDef Lock; /* DMA 锁对象 */
 __IO HAL_DMA_StateTypeDef State; /* DMA 传输状态 */
 void *Parent; /* 父对象状态,HAL 库处理的中间变量 */
void (*XferCpltCallback)( struct __DMA_HandleTypeDef *hdma);/*DMA 传输完成回调*/
 /* DMA 一半传输完成回调 */
void (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); 
 /* DMA 传输完整的 Memory1 回调 */
void (* XferM1CpltCallback)( struct __DMA_HandleTypeDef * hdma); 
/* DMA 传输半完全内存回调 */
void (* XferM1HalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); 
/*DMA 传输错误回调*/
void (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma);
/* DMA 传输中止回调 */
 void (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma);
 __IO uint32_t ErrorCode; /* DMA 存取错误代码 */
 uint32_t StreamBaseAddress;/* DMA 通道基地址 */
uint32_t StreamIndex; /* DMA 通道索引 */
}DMA_HandleTypeDef;

        Instance:是用来设置寄存器基地址,例如要设置的对象是串口 1 的发送,那么就要参考表 31.1.1,串口 1 的 DMA 传输需要用到的是 DMA2 的数据流 7,即 DMA2_Stream7。

        Parent:是 HAL 库处理中间变量,用来指向 DMA 通道外设句柄。

        StreamBaseAddress 和 StreamIndex 是数据流基地址和索引号,这个是 HAL 库处理的时候会自动计算,用户无需设置。
        其他成员变量是 HAL 库处理过程状态标识变量。

接下来我们重点介绍 Init,它是 DMA_InitTypeDef 结构体类型变量,该结构体定义如下:

typedef struct
{
 uint32_t Channel; /* 传输通道,例如:DMA_CHANEL_4 */ 
 uint32_t Direction; /* 传输方向,例如存储器到外设 DMA_MEMORY_TO_PERIPH */
 uint32_t PeriphInc; /* 外设(非)增量模式,非增量模式 DMA_PINC_DISABLE */ 
 uint32_t MemInc; /* 存储器(非)增量模式,增量模式 DMA_MINC_ENABLE */ 
 uint32_t PeriphDataAlignment;/* 外设数据大小:8/16/32 位 */
 uint32_t MemDataAlignment; /* 存储器数据大小:8/16/32 位 */
 uint32_t Mode; /* 模式:外设流控模式/循环模式/普通模式 */ 
 uint32_t Priority; /* DMA 优先级:低/中/高/非常高 */
 uint32_t FIFOMode; /* FIFO 模式开启或者禁止 */
 uint32_t FIFOThreshold; /* FIFO 阈值选择 */
 uint32_t MemBurst; /* 存储器突发模式:单次/4 个节拍/8 个节拍/16 个节拍 */ 
 uint32_t PeriphBurst; /* 外设突发模式:单次/4 个节拍/8 个节拍/16 个节拍 */ 
}DMA_InitTypeDef;

我们通过该结构体成配置 DMA_SxCR 寄存器和 DMA_SxFCR 寄存器的相应位。

DMA方式传输串口数据配置步骤

1)使能 DMA 时钟

        DMA 的时钟使能是通过 AHB1ENR 寄存器来控制的,这里我们要先使能时钟,才可以配置 DMA 相关寄存器。

__HAL_RCC_DMA1_CLK_ENABLE(); /* DMA1 时钟使能 */
__HAL_RCC_DMA2_CLK_ENABLE(); /* DMA2 时钟使能 */

2)初始化 DMA

        调用 HAL_DMA_Init 函数初始化 DMA 的相关参数,包括配置通道,外设地址,存储器地
址,传输数据量等。
        HAL 库为了处理各类外设的 DMA 请求,在调用相关函数之前,需要调用一个宏定义标识符,来连接 DMA 和外设句柄。例如要使用串口 DMA 发送,所以方式为:

__HAL_LINKDMA(&g_uart1_handle, hdmatx, g_dma_handle);

        其中 g_uart1_handle是串口初始化句柄,我们在 usart.c中定义过了。g_dma_handle是 DMA 初始化句柄。hdmatx 是外设句柄结构体的成员变量,实际就是 g_uart1_handle 的成员变量。

3)使能串口的 DMA 发送,启动传输

        串口 1 的 DMA 发送实际是串口控制寄存器 CR3 的位 7 来控制的,在 HAL 库中操作该寄存器来使能串口 DMA 发送的函数为 HAL_UART_Transmit_DMA。调用该函数后会开启相应的 DMA 中断。

4)查询 DMA 传输状态

查询通道3传输完成标志位

__HAL_DMA_GET_FLAG(&g_dma_handle, DMA_FLAG_TCIF3_7);

获取当前传输剩余数据量:
__HAL_DMA_GET_COUNTER(&g_dma_handle);

设置对应的 DMA 数据流传输的数据量大小,函数为:
__HAL_DMA_SET_COUNTER (&g_dma_handle, 1000);

5)DMA 中断使用方法

DMA 中断对于每个流都有一个中断服务函数。

HAL 库提供了通用 DMA 中断处理函数 HAL_DMA_IRQHandler,在该函数内部,会对 DMA 传输状态进行分析,然后调用相应的中断处理回调函数:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); /* 发送完成回调函数 */
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);/* 发送一半回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); /* 接收完成回调函数 */
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);/* 接收一半回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart); /* 传输出错回调函数 */

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

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

相关文章

微服务中不同服务使用openfeign 相互调用

首先 我们上文 已经知道了 nacos 的注册服务,现在 我们 在不同服务中相互调用就可以使用openfeign 直接调用,而不是 再写冗余的调用代码啦 首先 我们的微服务组件如下 因为我这个微服务是我在 员工登录demo 中 拆出来的,在userlogin模块中…

2024年不可错过的12个Web程序设计语言!

Web开发行业出现以来,通过各种形式和渠道不断发展壮大。随着5g时代的到来,Web开发在移动互联网领域不断出现新的开发场景,也是最受欢迎的技能之一。掌握Web程序设计语言是在Web开发领域大放异彩的必要条件之一。接下来,即时设计选…

[论文笔记]Mixture-of-Agents Enhances Large Language Model Capabilities

引言 今天带来一篇多智能体的论文笔记,Mixture-of-Agents Enhances Large Language Model Capabilities。 随着LLMs数量的增加,如何利用多个LLMs的集体专业知识是一个令人兴奋的开放方向。为了实现这个目标,作者提出了一种新的方法&#xf…

DCT-Net - 一键图片、视频转卡通动漫风格工具,本地一键整合包下载

只需要输入一张人物图像或者一段视频,就可以实现端到端全图卡、视频通化转换,生成二次元虚拟形象,返回卡通化后的结果图像或视频。 开发者叫menyi Fang,来自阿里巴巴通义实验室的的技术女大佬,国内大佬集成到webui&am…

mprpc框架的配置文件加载

目录 1.回顾测试 2.mprpc框架的配置文件加载 2.1 mprpcconfig.h 2.2 完善mprpcapplication.h 2.3 完善mprpcapplication.cc 2.4 mprpcconfig.cc 2.5 test.conf 2.6 测试运行 ​3.扩展问题 1.回顾测试 我们先把之前的项目代码工程编译好,然后进入bin里面&am…

用VScode打开keil下的文件中文编码乱码的问题,以及利用VScode转换字符编码的方法

目录 问题描述 解决方法 利用VScode转换字符编码的方法 问题描述 keil中默认的编码是ANIS如下图所示。 而VScode中默认的编码为UTF-8 ,打开后如下。 解决方法 建议另存后,再打开目标文件,防止误操作! 在VScode的最下方可以找…

计算预卷积特征

当冻结卷积层和训练模型时,全连接层或dense层(vgg.classifier)的输入始终是相同的。为了更好地理解,让我们将卷积块(在示例中为vgg.features块)视为具有了已学习好的权重且在训练期间不会更改的函数。因此,计算卷积特征并保存下来将有助于我们…

2024年上半年软件设计师上午真题及答案解析

1.在计算机网络协议五层体系结构中,( B )工作在数据链路层。 A.路由器 B.以太网交换机 C.防火墙 D.集线器 网络层:路由器、防火墙 数据链路层:交换机、网桥 物理层:中继器、集线器 2.软件交付之后&#xff…

引领AI新时代:深度学习与大模型的关键技术

文章目录 📑前言一、内容概述二、作者简介三、书籍特色四、学习平台与资源 📑前言 在数字化浪潮席卷全球的今天,人工智能(AI)和深度学习技术已经渗透到我们生活的方方面面。从智能手机中的智能语音助手,到…

音视频入门基础:H.264专题(5)——FFmpeg源码中 解析NALU Header的函数分析

一、引言 FFmpeg源码中 通过h264_parse_nal_header函数将H.264码流的NALU Header解析出来。下面对h264_parse_nal_header函数进行分析。 二、h264_parse_nal_header函数定义 h264_parse_nal_header函数定义在FFmpeg源码(下面演示的FFmpeg源码版本是5.0.3&#xff…

阅读笔记——《Large Language Model guided Protocol Fuzzing》

【参考文献】Meng R, Mirchev M, Bhme M, et al. Large language model guided protocol fuzzing[C]//Proceedings of the 31st Annual Network and Distributed System Security Symposium (NDSS). 2024.(CCF A类会议)【注】本文仅为作者个人学习笔记&a…

Geoserver源码解读四 REST服务

文章目录 文章目录 一、概要 二、前置知识点-FreeMarker 三、前置知识点-AbstractHttpMessageConverter 3.1 描述 3.2 应用 四、前置知识点-AbstractDecorator 4.1描述 4.2 应用 五、工作空间查询解读 5.1 模板解读 5.2 请求转换器解读 一、概要 关于geoserver的r…

2024最新算法:北极海鹦优化(Arctic puffin optimization,APO)算法求解23个函数,MATLAB代码

一、算法介绍 北极海鹦优化(Arctic puffin optimization,APO)算法是2024年提出一种智能优化算法。该算法模拟海鹦在空中飞行和水下觅食两个阶段的行为,旨在实现勘探与开发之间更好的平衡。该算法包括几个关键操作,包括…

Nginx开发【Nginx虚拟主机和域名解析】

03 【Nginx虚拟主机和域名解析】 虚拟主机使用特殊的软硬件技术,把一台运行在因特网上的服务器主机分成一台台“虚拟”的主机,每一台虚拟主机都具有独立的域名,具有完整的Internet服务器(WWW、FTP、Email等)功能&…

FFmpeg+javacpp+javacv使用

FFmpegjavacppjavacv使用 Bytedeco官网案例1、导入opencv、ffmpeg依赖包2、FFmpeg 数据结构2.1 AVFormatContext 格式化I/O上下文2.1.1 metadata2.1.2 Duration、start、bitrate等其他信息2.1.3 dump信息 Bytedeco GitHub:javacpp Bytedeco官网案例 FFmpeg – [示例…

C语言·动态内存管理

1. 为什么要有动态内存管理? 例1: //固定的向内存申请4个字节 int a 10;//申请连续的一块空间 int arr[10]; 这些数据一旦声明定义之后就会在内存中有一块空间,这些空间都是固定的,为了让内存使用更加灵活,这时我们…

【回溯算法题记录】组合总和题汇总

组合总和 39. 组合总和题目描述初始思路后续分析 40. 组合总和 II题目描述思路(参考代码随想录) 39. 组合总和 题目🔗 题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数…

开源网安参与编制的《代码大模型安全风险防范能力要求及评估方法》正式发布

​代码大模型在代码生成、代码翻译、代码补全、错误定位与修复、自动化测试等方面为研发人员带来了极大便利的同时,也带来了对安全风险防范能力的挑战。基于此,中国信通院依托中国人工智能产业发展联盟(AIIA),联合开源…

教你使用 Go 语言访问智谱 AI 大模型!

AI 大模型太火爆了!我在工作中经常使用它们,感觉已经离不开了! 最近测试了智谱 AI 大模型,实测下来感觉还挺不错的。 官方提供了体验包,注册并实名认证之后有 300 万 token,非常壕! 今天的股…