STM32-笔记35-DMA(直接存储器访问)

一、什么叫DMA?

        DMA(Direct Memory Access,直接存储器访问)提供在外设与内存、存储器和存储器之间的高速数据传输使用。它允许不同速度的硬件装置来沟通,而不需要依赖于CPU,在这个时间中,CPU对于内存的工作来说就无法使用。

简单来说,就是一个数据的搬运工

而搬运的路径有三种方式:如下所示

  • 存储器→存储器(例如:复制某特别大的数据buf)
  • 存储器→外设 (例如:将某数据buf写入串口TDR寄存器)
  • 外设→存储器 (例如:将串口RDR寄存器写入某数据buf)

        存储器我们知道,就是内存,存储器到存储器之间的搬运,也就是从内存中一地方搬运到内存中另一个地方。

        那么这里的外设是指什么呢?

        外设指的是spi、usart、iic、adc 等基于APB1 、APB2或AHB时钟的外设,而这里的存储器包括 自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问地源或者目的

具体在参考手册中DMA框图中可以看见外设有哪些

 二、DMA存在的意义?

        代替 CPU 搬运数据,为 CPU 减负。

  • 1. 数据搬运的工作比较耗时间;
  • 2. 数据搬运工作时效要求高(有数据来就要搬走);
  • 3. 没啥技术含量(CPU 节约出来的时间可以处理更重要的事)。

三、搬运的流程

存储器→存储器

存储器→外设

外设→存储器

四、DMA控制器-通道

STM32F103 有 2 个 DMA 控制器,DMA1 有 7 个通道,DMA 2 有 5 个通道。
一个通道每次只能搬运一个外设的数据!! 如果同时有多个外设的 DMA 请求,则按照优先级进行响应。
STM32F103C8T6 只有 DMA1 !
DMA1有7个通道:

每个通道传输特定外设的数据

五、DMA优先级管理

优先级管理采用软件+硬件:
        软件: 每个通道的优先级可以在DMA_CCRx寄存器中设置,有4个等级
最高级>高级>中级>低级
        硬件: 如果2个请求,它们的软件优先级相同,则较低编号的通道比较高编号的通道有较高的优先权。
        比如:如果软件优先级相同,通道2优先于通道4

六、DMA传输方式

 

七、DMA寄存器及库函数介绍
 

八、小实验1:DMA内存到内存数据搬运

实验目的

使用DMA将一个大数组的数据搬运到另一个位置。

复制项目文件19-串口打印功能

重命名为40-DMA实验(内存到内存)

新建文件夹dma dma.c  dma.h

打开项目文件

加载文件

main.c

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "dma.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();//初始化led灯
    uart1_init(115200);
    dma_init();
    printf("hello word!\r\n");
    dma_transmit();
    
//    led1_ON();
//    led1_OFF();
    while(1)
    { 
        led1_ON();
        led2_OFF();
        delay_ms(500);
        led1_OFF();
        led2_ON();
        delay_ms(500);
    }
}

dma.c

#include "dma.h"
#include "stdio.h"
#define BUF_SIZE 16

uint32_t src_buf[BUF_SIZE] = {
    0x00000000,0x11111111,0x22222222,0x33333333,
    0x44444444,0x55555555,0x66666666,0x77777777,
    0x88888888,0x99999999,0xAAAAAAAA,0xBBBBBBBB,
    0xCCCCCCCC,0xDDDDDDDD,0xEEEEEEEE,0xFFFFFFFF
};
uint32_t dst_buf[BUF_SIZE] = {0};

DMA_HandleTypeDef dma_handle = {0};
//初始化dma函数
void dma_init(void)
{
    __HAL_RCC_DMA1_CLK_ENABLE();//使能DMA1
    dma_handle.Instance = DMA1_Channel1;//选择DMA1通道1(由于是内存传递内存所以不管哪一个通道都可以)
    dma_handle.Init.Direction = DMA_MEMORY_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_ENABLE;//外设增量模式启动
    
    dma_handle.Init.Mode = DMA_NORMAL;//DMA的模式:正常模式和循环模式
    dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;//DMA优先级:中级(只有一个DMA设置成什么无所谓)
    
    HAL_DMA_Init(&dma_handle);
}
//准备数据传输
void dma_transmit(void)
{
    //启动DMA传输
    HAL_DMA_Start(&dma_handle,(uint32_t)src_buf,(uint32_t)dst_buf,sizeof(uint32_t) * BUF_SIZE);
    //查询DMA传输状态
    while(__HAL_DMA_GET_FLAG(&dma_handle,DMA_FLAG_TC1) == RESET);
    //打印数据
    int i;
    for(i=0;i<BUF_SIZE;i++)
    {
        printf("buf[%d]:%X\r\n",i,dst_buf[i]);
    }
    
}

dma.h

#ifndef __DMA_H__
#define __DMA_H__

#include "sys.h"

void dma_init(void);
void dma_transmit(void);
    
#endif

九、小实验2:DMA内存到外设数据搬运

实验目的

使用DMA将一个大数组的数据通过串口1发送 。

内存通过DMA将数据搬运到外设中

USART1-TX负责将内存中的数据按照指定的格式和波特率发送到外部设备‌

复制项目文件40-DMA实验(内存到内存)

重命名项目文件41-DMA实验(内存到外设)

打开项目文件

main.c

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "dma.h"

uint8_t send_buf[1000] = {0};
extern UART_HandleTypeDef uart1_handle;

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();//初始化led灯
    uart1_init(115200);
    dma_init();
    //printf("hello word!\r\n");
    
    int i = 0;
    for(i=0;i<1000;i++)
    {
        send_buf[i] = 'A';
    }
    //串口句柄,发送的数据,发送的个数
    HAL_UART_Transmit_DMA(&uart1_handle,send_buf,1000);//以DMA的方式发送数据
    while(1)
    { 
        led1_ON();
        led2_OFF();
        delay_ms(500);
        led1_OFF();
        led2_ON();
        delay_ms(500);
    }
}

dma.c

#include "dma.h"
#include "stdio.h"

extern UART_HandleTypeDef uart1_handle;
DMA_HandleTypeDef dma_handle = {0};
//初始化dma函数
void dma_init(void)
{
    __HAL_RCC_DMA1_CLK_ENABLE();//使能DMA1
    dma_handle.Instance = DMA1_Channel4;//选择DMA1通道4,内存到外设通道4-以DMA的方式发送(tx)给串口1数据
    dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;//方向:内存到外设
    //内存的设置
    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.Mode = DMA_NORMAL;//DMA的模式:正常模式和循环模式
    dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;//DMA优先级:中级(只有一个DMA设置成什么无所谓)
    
    HAL_DMA_Init(&dma_handle);
    //链接:内存链接到串口1:外设的句柄,成员变量,dma的句柄
    __HAL_LINKDMA(&uart1_handle,hdmatx,dma_handle);
}

dma.h

#ifndef __DMA_H__
#define __DMA_H__

#include "sys.h"

void dma_init(void);
    
#endif

结果:

十、小实验3:DMA外设到内存数据搬运

实验目的

使用DMA接收串口1发的数据。

串口通过DMA将数据搬运到内存中

USART1-RX负责将外部设备‌中的数据按照指定的格式和波特率发送到内存,

也就是内存接收外部设备中的数据

所以这里的USART1-RX和USART1-TX是针对内存来讲(暂时先这么记)

复制项目文件41-DMA实验(内存到外设)

重命名项目文件42-DMA实验(外设到内存)

main.c

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "dma.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();//初始化led灯
    uart1_init(115200);
    dma_init();
    printf("hello word!\r\n");
    
    while(1)
    { 
        led1_ON();
        led2_OFF();
        delay_ms(500);
        led1_OFF();
        led2_ON();
        delay_ms(500);
    }
}

dma.c

#include "dma.h"
#include "stdio.h"
#include "uart1.h"

extern UART_HandleTypeDef uart1_handle;
DMA_HandleTypeDef dma_handle = {0};
extern uint8_t uart1_rx_buf[UART1_RX_BUF_SIZE];                                    /* UART1接收缓冲区 */
                                               

//初始化dma函数
void dma_init(void)
{
    __HAL_RCC_DMA1_CLK_ENABLE();//使能DMA1
    dma_handle.Instance = DMA1_Channel5;//选择DMA1通道5,外设到内存通道5-以DMA的方式发送(rx)给串口1数据
    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.Mode = DMA_NORMAL;//DMA的模式:正常模式和循环模式
    dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;//DMA优先级:中级(只有一个DMA设置成什么无所谓)
    
    HAL_DMA_Init(&dma_handle);
    //链接:内存链接到串口1:外设的句柄,成员变量,dma的句柄
    __HAL_LINKDMA(&uart1_handle,hdmarx,dma_handle);
    //串口通过DMA接收
    HAL_UART_Receive_DMA(&uart1_handle,uart1_rx_buf,UART1_RX_BUF_SIZE);//将数据接收到uart1_rx_buf缓冲区里面长度是UART1_RX_BUF_SIZE这么长
}

dma.h

#ifndef __DMA_H__
#define __DMA_H__

#include "sys.h"

void dma_init(void);
    
#endif

结果:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码管理助手-Git

前言 Git 是一个版本控制系统&#xff0c;可以帮助你记录文件的每一次修改。这样&#xff0c;如果你在编程时不小心把代码写错了&#xff0c;可以很容易地回退到之前的版本。最重要的是&#xff0c;Git 是完全免费的&#xff0c;用户可以在自己的计算机上安装和使用 Git&#x…

蓝耘:GPU算力云服务的技术探索与AIGC应用支持

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 一、蓝耘的核心优势 1. 行业领先的基础设施 …

Kubernetes Gateway API-4-TCPRoute和GRPCRoute

1 TCPRoute 目前 TCP routing 还处于实验阶段。 Gateway API 被设计为与多个协议一起工作&#xff0c;TCPRoute 就是这样一个允许管理TCP流量的路由。 在这个例子中&#xff0c;我们有一个 Gateway 资源和两个 TCPRoute 资源&#xff0c;它们按照以下规则分配流量&#xff1…

在不到 5 分钟的时间内将威胁情报 PDF 添加为 AI 助手的自定义知识

作者&#xff1a;来自 Elastic jamesspi 安全运营团队通常会维护威胁情报报告的存储库&#xff0c;这些报告包含由报告提供商生成的大量知识。然而&#xff0c;挑战在于&#xff0c;这些报告的内容通常以 PDF 格式存在&#xff0c;使得在处理安全事件或调查时难以检索和引用相关…

Unity学习之UGUI进阶

一、事件监听接口 1、作用 用于实现类型长按、双击、拖拽等基础控件无法实现的功能 所有控件都能够添加更多的事件监听来处理对应的逻辑 2、事件监听接口类型 &#xff08;1&#xff09;常用事件接口 &#xff08;2&#xff09;不常用事件接口 3、使用事件监听接口 &#…

Redis为 List/Set/Hash 的元素设置单独的过期时间

一.业务简介 我们知道&#xff0c;Redis 里面暂时没有接口给 List、Set 或者 Hash 的 field 单独设置过期时间&#xff0c;只能给整个列表、集合或者 Hash 设置过期时间。 这样&#xff0c;当 List/Set/Hash 过期时&#xff0c;里面的所有 field 元素就全部过期了。但这样并不…

【Notepad++】Notepad++如何删除包含某个字符串所在的行

Notepad如何删除包含某个字符串所在的行 一&#xff0c;简介二&#xff0c;操作方法三&#xff0c;总结 一&#xff0c;简介 在使用beyoundcompare软件进行对比的时候&#xff0c;常常会出现一些无关紧要的地方&#xff0c;且所在行的内容是变化的&#xff0c;不方便进行比较&…

APP上架之Android 证书 MD5 指纹

Android 证书 MD5 指纹 1. 什么是 Android 证书 MD5 指纹&#xff1f; Android 证书 MD5 指纹是对证书数据进行 MD5 哈希运算后得到的 128 位字符串。在 Android 开发中&#xff0c;每个证书在理论上都有一个唯一的 MD5 指纹&#xff0c;用于识别和验证证书的有效性。证书指纹…

软件安全性测试有哪些测试方法?

随着数字化进程的加速&#xff0c;软件在各个领域扮演着越来越重要的角色。软件的安全性测试作为保证软件质量和安全的重要环节&#xff0c;逐渐成为企业在开发和部署过程中不可或缺的一部分。 一、软件安全性测试的测试方法   1、静态分析法&#xff1a;通过分析源代码或二…

LabVIEW轴承性能测试系统

本文介绍了基于LabVIEW的高效轴承性能测试系统的设计与开发。系统通过双端驱动技术实现高精度同步控制&#xff0c;针对轴承性能进行全面的测试与分析&#xff0c;以提高轴承的可靠性和寿命。 项目背景 随着工业自动化程度的提高&#xff0c;对轴承的性能要求越来越高。传统的…

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景 实现效果 该案例实现了使用Three.js创建一个带有聚光灯和旋转立方体的3D场景。 知识点 WebGLRenderer&#xff08;WebGL渲染器&#xff09; THREE.WebGLRenderer 是 Three.js 中用于将场景渲染为 WebGL 内容的核…

如何使用vue引入three.js

在 Vue.js 项目中引入和使用 Three.js 是一个常见的需求&#xff0c;Three.js 是一个用于在浏览器中创建和显示动画 3D 计算机图形的 JavaScript 库。以下是一个基本的示例&#xff0c;展示如何在 Vue 项目中引入和使用 Three.js。 1. 创建 Vue 项目 如果你还没有一个 Vue 项…

9.4 visualStudio 2022 配置 cuda 和 torch (c++)

一、配置torch 1.Libtorch下载 该内容看了【Libtorch 一】libtorchwin10环境配置_vsixtorch-CSDN博客的博客&#xff0c;作为笔记用。我自己搭建后可以正常运行。 下载地址为windows系统下各种LibTorch下载地址_libtorch 百度云-CSDN博客 下载解压后的目录为&#xff1a; 2.vs…

【JavaEE进阶】获取Cookie/Session

&#x1f340;Cookie简介 HTTP协议自身是属于 "⽆状态"协议. "⽆状态"的含义指的是: 默认情况下 HTTP 协议的客⼾端和服务器之间的这次通信,和下次通信之间没有直接的联系.但是实际开发中,我们很多时候是需要知道请求之间的关联关系的. 例如登陆⽹站成…

oscp备考 oscp系列——Kioptix Level 1靶场 古老的 Apache Vuln

目录 前言 1. 主机发现 2. 端口扫描 3. 指纹识别 4. 目录扫描 5. 漏洞搜索和利用 前言 oscp备考&#xff0c;oscp系列——Kioptix Level 1靶场 Kioptix Level 1难度为简单靶场&#xff0c;主要考察 nmap的使用已经是否会看输出&#xff0c;以及是否会通过应用查找对应漏…

CSS——2.书写格式一

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><!--css书写中&#xff1a;--><!--1.css 由属性名:属性值构成--><!--style"color: red;font-size: 20px;&quo…

IT面试求职系列主题-人工智能(一)

想成功求职&#xff0c;必要的IT技能一样不能少&#xff0c;再从人工智能基础知识来一波吧。 1&#xff09;您对人工智能的理解是什么&#xff1f; 人工智能是计算机科学技术&#xff0c;强调创造能够模仿人类行为的智能机器。这里智能机器可以定义为能够像人一样行动、像人一…

Gitee图形界面上传(详细步骤)

目录 1.软件安装 2.安装顺序 3.创建仓库 4.克隆远程仓库到本地电脑 提交代码的三板斧 1.软件安装 Git - Downloads (git-scm.com) Download – TortoiseGit – Windows Shell Interface to Git 2.安装顺序 1. 首先安装git-2.33.1-64-bit.exe&#xff0c;顺序不能搞错2. …

js迭代器模式

以前JS原生的集合类型数据结构&#xff0c;只有Array&#xff08;数组&#xff09;和Object&#xff08;对象&#xff09;&#xff1b; 而ES6中&#xff0c;又新增了Map和Set。四种数据结构各自有着自己特别的内部实现&#xff0c;但我们仍期待以同样的一套规则去遍历它们&…

C语言初阶习题【25】strcpy的模拟实现

1. 首先先调用下库函数&#xff0c;看它实现了什么 2. 我们自己实现一个strcpy函数 3. 改进1 把*destnation和source 写上去&#xff0c;使用后置 4. 改进2 这里直接把赋值操作放到了while的判断条件里面&#xff0c;然后while循环语句什么都不做&#xff0c;放了一个空语句…