DMA直接内存访问,STM32实现高速数据传输使用配置

1、DMA运用场景

        随着智能化、信息化的不断推进,嵌入式设备的数据处理量也呈现指数级增加,因此对于巨大的数据量处理的情况时,必须采取其它的方式去替CPU减负,以保证嵌入式设备性能。例如SD卡存储器和音视频、网络高速通信等其它情景使用时,如果仅靠CPU去处理,将会消耗大量的系统资源,并且可能不能满足设备实时性的要求,对于嵌入式等一众资源受限的设备中,这是致命的。因此有必要采取一种特殊的方式,使得在执行大量数据处理过程中,CPU依然去执行正常的嵌入式系统任务。

        在嵌入式系统中,常用DMA去解决这一问题。DMA(Direct Memory Access),直接存储器访问)是一种特殊的硬件功能,用于数据传输而不需要CPU的干预DMA主要用于高速数据传输,可以提高系统性能和效率

        ①数据传输:DMA可以在外设和存储器之间进行高速数据传输,例如将数据从外设(如传感器、音频设备、网络接口等)直接传输到存储器中,或者从存储器中直接传输到外设中。这样可以减少CPU的负载,并提高数据传输的速度和效率。

        ②音视频处理:在多媒体应用中,DMA可以用于将音频、视频等数据从外设传输到存储器中进行处理,或者从存储器传输到外设进行播放。通过使用DMA,系统可以实现高质量的音视频数据传输和处理,同时降低对CPU的负担。

        ③存储器处理:DMA可以用于将存储器中的数据备份到外部存储设备(如硬盘、闪存等),或从外部存储设备中恢复数据到存储器中。这样可以提高数据备份和恢复的速度,并降低对CPU的负载。

        ④高速通信:DMA可以用于在嵌入式系统中实现高速通信,例如通过网络接口卡(如以太网)、串行接口(如UART、SPI)等传输数据。DMA可以在数据传输时,绕过CPU直接在外设和存储器之间进行传输,提高数据传输的速度和效率。

2、STM32 DMA基础

在STM32F4xx官方参考手册文档中,有对DMA控制器的讲解说明,内容十分的丰富,在这一部分中将其中较为核心基础的内容进行了梳理。

直接存储器访问 (DMA) 用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。

DMA搬运的三种模式:

①、内存--->内存

②、内存--->外设

③、外设--->内存

DMA1:外设--->内存,内存--->外设

DMA2:外设--->内存,内存--->外设,内存--->内存

DMA2比DMA1多了一个内存到内存的处理功能,因此,如果需要实现内存到内存的DMA搬运模式,必须使用DMA2。

流:是数据传输的一条链路,每个DMA控制器有8条独立的数据流,每次传输的最大数据量为65535,如果数据单位为字的话,可以一次传输256KB。

通道:每个数据流有8个通道选择,每个通道对应不同的DMA请求。

同一个数据流只能使用一个通道,同一个DMA控制器可以使用多个数据流。

仲裁器:仲裁器为两个 AHB 主端口(存储器和外设端口)提供基于请求优先级的 8 个 DMA 数据流请求管理,并启动外设/存储器访问序列。

仲裁器优先级管理分为软件优先级管理和硬件优先级管理。多个数据流到来时,仲裁器会分为两个阶段进行仲裁,第一个阶段为软件优先级管理,在其编程时设置数据流的优先级第二个阶段为硬件阶段,由数据流的硬件编号决定。

FIFO:源和目标之间的一个数据中转站。FIFO模式下,可以将要传输的多个数据(或字节)累计存储在FIFO缓冲器中,然后在FIFO缓冲器中设置存储阈值,当到达阈值时,FIFO会自动把所有存储的数据一次性的发送到目标地址。

一个FIFO为4个字的大小,每个数据流有4字的FIFO,DMA配置为存储器---存储器模式时,FIFO由硬件开启,软件控制无效。且DMA配置为存储器到存储器模式时,不能设置为循环传输。

如图所示可知,DMA1、DMA2控制器挂载在AHB1总线下

由STM32F4xx官方参考手册可知,对于STM32F407系列,其嵌入式SRAM的起始映射的地址0x2000 0000开始。

由STM32F4xx官方参考手册可知,对于STM32F407系列,其嵌入式FLASH的起始映射的地址0x0800 0000开始。

3、STM32 编程实现DMA

在这一部分的讲解梳理中,将DMA配置为了内存--->内存模式,如果是要配置为内存--->外设外设--->内存,修改 DMA结构体的DMA_InitStructure.DMA_DIR参数即可其它参数的配置的思路大致相同。

//STM32F407中const修饰的全局存储到FLASH中
const uint32_t src_const_buf[32] = {0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80};
uint32_t dst_buf[32] = {0};

因为DMA配置结构体中,需要填入外设/内存的地址信息,所以通过打印数组的内存地址,查看数据的存储位置,以确定外设/内存的地址。由上述STM32F4xx的官方参考手册嵌入式FLASH和SRAM部分说明和打印出来的内存地址可知,const修饰的全局变量被存储于嵌入式FLASH中。

DMA数据传输测试,DMA内存到内存模式代码实现效果如下图所示,通过打印的数据也可确定,DMA高速存储成功且数据无误。

实现DMA存储器到存储器,高速数据传输模式的参考代码Demo如下:

#include "stm32f4xx.h"
#include "stm32f4xx_dma.h"
#include <stdio.h>//const修饰的全局存储到FLASH中
const uint32_t src_const_buf[32] = {0xAAAAAAAA,0xBBBBBBBB,0xCCCCCCCC,0xDDDDDDDD,0xEEEEEEEE,0xFFFFFFFF,0x10000000,0x11111111,0x22222222,0x33333333,0x44444444,0x55555555,0x66666666,0x77777777,0x88888888,0x99999999,0x10000000,0x10000000,0x10000000,0x10000000,0x11111111,0x11111111,0x11111111,0x11111111,0x22222222,0x22222222,0x22222222,0x22222222,0x33333333,0x33333333,0x33333333,0x33333333};
uint32_t dst_buf[32] = {0};void DMA_Config(void);
int8_t buf_cmp(uint32_t *pbuf1, uint32_t *pbuf2, int len);int main(void)
{NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );USART1_Init(115200);printf("starting...\r\n");printf("const addr:%X\r\n", (uint32_t)src_const_buf);printf("addr:%X\r\n", (uint32_t)dst_buf);     DMA_Config();while(DMA_GetCmdStatus(DMA2_Stream0) != DISABLE);    //传输完成后,DMA会进行复位if(buf_cmp((uint32_t *)src_const_buf, dst_buf, 32)==0){printf("DMA传输完成,且数据无误...\r\n");printf("src:\r\n");for(int i = 0; i<32; i++){printf("%0X\t", src_const_buf[i]);}printf("\r\n");printf("dst:\r\n");for(int i = 0; i<32; i++){printf("%0X\t", dst_buf[i]);}printf("\r\n");return 0;}else{printf("DMA数据传输故障...\r\n");    return -1;}}void DMA_Config(void)
{DMA_InitTypeDef DMA_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;volatile uint32_t  Timeout = 10000;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);//内存到内存的传送,使用DMA2DMA_DeInit(DMA2_Stream0);    //初始化DMA的寄存器到复位状态while(DMA_GetCmdStatus(DMA2_Stream0) != DISABLE);    //确保DMA复位完成//配置DMA流DMA_InitStructure.DMA_Channel = DMA_Channel_0;    //启用DMA通道0DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)src_const_buf; //FLASH中的数据地址DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dst_buf;
//SRAM的数据地址DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;    //存储器到存储器模式DMA_InitStructure.DMA_BufferSize = (uint32_t)32;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;    //FLASH地址自增使能DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;            //SRAM地址自增//SRAM地址自增使能DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA2_Stream0, &DMA_InitStructure);    //DMA初始化DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);DMA_Cmd(DMA2_Stream0, ENABLE);        //DMA使能while(DMA_GetCmdStatus(DMA2_Stream0) != ENABLE && (Timeout-->0));if(Timeout == 0){while(1);}NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}int8_t buf_cmp(uint32_t *pbuf1, uint32_t *pbuf2, int len)
{int cnt = 0;for(int i=0; i<len; i++){if(pbuf1[i] != pbuf2[i]){return -1;}}return 0;
}void DMA2_Stream0_IRQHandler(void)
{    //DMA2通道0数据流传输完成中断 if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) == SET){//清除DMA传输完成中断标志位DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);//在此可根据项目需求增加DMA处理完时的操作}}

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

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

相关文章

Vue中 常用的修饰符有哪些

Vue是一款建立在JavaScript框架上的开源前端库&#xff0c;已经成为当今前端开发人员最喜爱的选择之一。它的简洁语法和强大的功能使得开发者可以轻松地构建交互性的网页应用程序。在Vue中&#xff0c;修饰符是一个重要的概念&#xff0c;它们可以帮助我们更好地控制和定制DOM元…

【数据结构】二叉树的顺序结构及链式结构

目录 1.树的概念及结构 1.1树的概念 1.2树的相关概念 ​编辑 1.3树的表示 1.4树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 2.二叉树概念及结构 2.1二叉树的概念 2.2现实中的二叉树 ​编辑 2.3特殊的二叉树 2.4二叉树的性质 2.5二叉树的存储结…

c++新特性override和final

override 作用: 在子类中重写父类的虚函数&#xff0c;我们可以在子类的虚函数声明后加上override。 上图就在重写eat()的时候&#xff0c;加上override。 作用: 1. 可以提示读者&#xff0c;这个函数是重写自父类中的。 2. 加上override之后&#xff0c;我们在重…

数据库管理-第148期 最强Oracle监控EMCC深入使用-05(20240208)

数据库管理148期 2024-02-08 数据库管理-第148期 最强Oracle监控EMCC深入使用-05&#xff08;20240208&#xff09;1 性能主页2 ADDM Spotlight3 实时ADDM4 数据库的其他5 主机总结 数据库管理-第148期 最强Oracle监控EMCC深入使用-05&#xff08;20240208&#xff09; 作者&am…

实例分割论文阅读之:FCN:《Fully Convolutional Networks for Semantica Segmentation》

论文地址:https://openaccess.thecvf.com/content_cvpr_2015/papers/Long_Fully_Convolutional_Networks_2015_CVPR_paper.pdf 代码链接&#xff1a;https://github.com/pytorch/vision 摘要 卷积网络是强大的视觉模型&#xff0c;可以产生特征层次结构。我们证明&#xff0c…

Python解决SSL不可用问题

参考&#xff1a;https://blog.csdn.net/weixin_44894162/article/details/126342591 一、问题描述&#xff1a; 报错概述&#xff1a; WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available. ## 警告:pip配…

Project 2019下载安装教程,保姆级教程,附安装包和工具

前言 Project是一款项目管理软件&#xff0c;不仅可以快速、准确地创建项目计划&#xff0c;而且可以帮助项目经理实现项目进度、成本的控制、分析和预测&#xff0c;使项目工期大大缩短&#xff0c;资源得到有效利用&#xff0c;提高经济效益。软件设计目的在于协助专案经理发…

ubuntu原始套接字多线程负载均衡

原始套接字多线程负载均衡是一种在网络编程中常见的技术&#xff0c;特别是在高性能网络应用或网络安全工具中。这种技术允许应用程序在多个线程之间有效地分配和处理网络流量&#xff0c;提高系统的并发性能。以下是关于原始套接字多线程负载均衡技术的一些介绍&#xff1a; …

交通 | 共乘出行(下):基于图结构的动态多时空供需网络的均衡度量方法

博客&#xff1a;Alex Chin, & Tony Qin. (2023.02.25). Quantifying Efficiency in Ridesharing Marketplaces. Link: https://eng.lyft.com/quantifying-efficiency-in-ridesharing-marketplaces-affd53043db2 论文&#xff1a;Chin, Alex, and Zhiwei Qin. “A Unified…

Springboot根据环境读取application配置文件

目录 1. 首先创建两个不同配置文件 2. pom.xml 配置文件 3. 指定环境 4. 最后启动测试 1. 首先创建两个不同配置文件 分别为开发环境和生产环境 application-dev.properties 和 application-prod.properties application-dev.properties 配置为 1931 端口 application-pro…

CAN通讯协议详解

阅读引言&#xff1a; 本篇博文想给需要的人介绍一下CAN总线&#xff0c; 这个也算是我从B站学习记得笔记分享吧也算是。简单的介绍了CAN总线的大致内容&#xff0c; 简述支持CAN功能的STM32的简单使用例程。本视频的中的图片内容均来自B站爱上半导体博主的内容。 CAN高质量教学…

问题:在填制记账凭时,应注意以下几个方面:( ) #知识分享#其他

问题&#xff1a;在填制记账凭时&#xff0c;应注意以下几个方面&#xff1a;&#xff08; &#xff09; A:记账凭证各项内容必须完整 B:必须以审核无误的原始凭证为依据 C:记账凭证应连续编号 D:记账凭证的书写应清楚、规范。 参考答案如图所示

C++算法之双指针、BFS和图论

一、双指针 1.AcWing 1238.日志统计 分析思路 前一区间和后一区间有大部分是存在重复的 我们要做的就是利用这部分 来缩短我们查询的时间 并且在使用双指针时要注意对所有的博客记录按时间从小到大先排好顺序 因为在有序的区间内才能使用双指针记录两个区间相差 相当于把一个…

Leecode之随机链表的复制

一.题目及剖析 https://leetcode.cn/problems/copy-list-with-random-pointer/ 这个题目的意思就是拷贝一份复杂链表,难点在于它的random指针所指向的空间与拷贝下来的链表之间缺少一种联系,当然可以用遍历链表的方式通过value去找那块空间,不过时间复杂度太高. 二.思路引入 …

Redis Centos7 安装到启动

文章目录 安装Redis启动redis查看redis状况连接redis服务端 安装Redis 1.下载scl源 yum install centos-release-scl-rh2.下载redis yum install rh-redis5-redis 3. 创建软连接 1.cd /usr/bin 2. In -s /opt/rh/rh-redis5/root/usr/bin/redis-server ./redis-server 3. …

Ajax+JSON学习一

AjaxJSON学习一 文章目录 前言一、Ajax简介1.1. Ajax基础1.2. 同源策略 二、Ajax的核心技术2.1. XMLHttpRequest 类2.2. open指定请求2.3. setRequestHeader 设置请求头2.4. send发送请求主体2.5. Ajax取得响应 总结 前言 一、Ajax简介 1.1. Ajax基础 Ajax 的全称是 Asynchron…

雾计算:去中心化计算的未来之旅

雾计算是去中心化计算的基石&#xff0c;它将重塑我们的数字格局。通过使计算和存储更接近数据源&#xff0c;它改变了我们处理物联网生成数据的方式。通过雾计算探索未来&#xff0c;揭示了减少延迟、增强隐私和高效网络利用等好处。 随着传感器和可穿戴设备等物联网设备的数…

5.常量和数据类型(数字类型,字符串类型,模板字符串,布尔类型undefined,null检测数据类型),类型转化

什么是常量 常量就是不能改变的量&#xff0c;就是向计算机内存要一款空间然后存储的东西不能改变用const声明并且一定要初始化值 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-C…

基于LightGBM的回归任务案例

在本文中&#xff0c;我们将学习先进的机器学习模型之一&#xff1a;Lightgbm。在对XGB模型进行了越来越多的改进以获得更好的性能之后&#xff0c;XGBoost是一种极限梯度提升机器&#xff0c;但通过lightgbm&#xff0c;我们可以在没有太多计算的情况下实现类似或更好的结果&a…

【C++修行之道】(引用、函数提高)

目录 一、引用 1.1引用的基本使用 1.2 引用注意事项 1.3 引用做函数参数 1.4 引用做函数返回值 1.5 引用的本质 1.6 常量引用 1.7引用和指针的区别 二、函数提高 2.1 函数默认参数 2.2函数占位参数 2.3 函数重载 2.4函数重载注意事项 一、引用 1.1引用的基本使用 …