ARM32开发——DMA内存到内存

🎬 秋野酱:《个人主页》
🔥 个人专栏:《Java专栏》《Python专栏》

⛺️心若有所向往,何惧道阻且长

文章目录

    • 需求
    • 数据交互流程
    • 开发流程
      • 依赖引入
      • DMA初始
      • DMA传输请求
      • 完整代码
    • 关心的内容
      • DMA初始化
      • DMA初始化
      • DMA数据传输请求
      • 完整代码
    • DMA中断
      • 开启中断
      • 中断函数实现
    • 完整代码

需求

#define ARR_LEN 1024
char src[ARR_LEN] = "hello\0";
char dst[ARR_LEN] = {0};

将src这个数组的值,赋值到dst这个数组中,不可以采取直接赋值的方式,需要通过DMA将数据进行传递。

数据交互流程

在这里插入图片描述

开发流程

依赖引入

添加标准库中的gd32f4xx_dma.c文件

DMA初始

/***************** DMA m2m *******************/
// 时钟
rcu_periph_clock_enable(RCU_DMA1);
// 重置dma
dma_deinit(DMA1, DMA_CH0);dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = DMA_MEMORY_TO_MEMORY;	
// 外设(作为内存到内存拷贝的源)
dsdps.periph_addr = (uint32_t)src;
dsdps.periph_inc = DMA_PERIPH_INCREASE_ENABLE;
// 内存
dsdps.memory0_addr = (uint32_t)dst;
dsdps.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
// 数据长度
dsdps.number = ARR_LEN;
// 数据宽度
dsdps.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_single_data_mode_init(DMA1, DMA_CH0, &dsdps);
  1. 配置时钟
  2. 初始化dma通道

DMA传输请求

dma_channel_enable(DMA1, DMA_CH0);
while(RESET == dma_flag_get(DMA1, DMA_CH0, DMA_FLAG_FTF));
dma_flag_clear(DMA1, DMA_CH0, DMA_FLAG_FTF);

● dma_channel_enable: 请求dma数据传输
● DMA_FLAG_FTF:为传输完成标记

完整代码

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "Usart0.h"#define ARR_LEN 1024
char src[ARR_LEN] = "hello\0";
char dst[ARR_LEN] = {0};void Usart0_recv(uint8_t* data, uint32_t len) {printf("recv: %s\r\n", data);dma_channel_enable(DMA1, DMA_CH0);while(RESET == dma_flag_get(DMA1, DMA_CH0, DMA_FLAG_FTF));dma_flag_clear(DMA1, DMA_CH0, DMA_FLAG_FTF);printf("dst: %s\n", dst);
}static void DMA_config() {/***************** DMA m2m *******************/// 时钟rcu_periph_clock_enable(RCU_DMA1);// 重置dmadma_deinit(DMA1, DMA_CH0);dma 配置dma_single_data_parameter_struct dsdps;dma_single_data_para_struct_init(&dsdps);// 方向dsdps.direction = DMA_MEMORY_TO_MEMORY;	// 外设(作为内存到内存拷贝的源)dsdps.periph_addr = (uint32_t)src;dsdps.periph_inc = DMA_PERIPH_INCREASE_ENABLE;// 内存dsdps.memory0_addr = (uint32_t)dst;dsdps.memory_inc = DMA_MEMORY_INCREASE_ENABLE;// 数据长度dsdps.number = ARR_LEN;// 数据宽度dsdps.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;dma_single_data_mode_init(DMA1, DMA_CH0, &dsdps);//		// 中断配置//		nvic_irq_enable(DMA1_Channel0_IRQn, 2, 2);//		// 中断使能//		dma_interrupt_enable(DMA1, DMA_CH0, DMA_CHXCTL_FTFIE);//		// 开启DMA通道// dma_channel_enable(DMA1, DMA_CH0);
}//void DMA1_Channel0_IRQHandler() {
//		// 判断中断标记
//		if(SET == dma_interrupt_flag_get(DMA1, DMA_CH0, DMA_INT_FLAG_FTF)) {
//				printf("dst: %s\n", dst);
//		}
//		// 清理标记位
//		dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_FTF);
//}int main(void)
{nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);systick_config();Usart0_init();DMA_config();while(1) {}
}

关心的内容

uint32_t dmax = DMA1;
uint32_t dmax_rcu = RCU_DMA1;
uint32_t dmax_ch = DMA_CH0;uint32_t dmax_dirction = DMA_MEMORY_TO_MEMORY;uint32_t dmax_src = (uint32_t)src;
uint32_t dmax_src_inc = DMA_PERIPH_INCREASE_ENABLE;
uint32_t dmax_src_width = DMA_PERIPH_WIDTH_8BIT;
uint32_t dmax_src_len = ARR_LEN;uint32_t dmax_dst = (uint32_t)dst;
uint32_t dmax_dst_inc = DMA_MEMORY_INCREASE_ENABLE;
/***************** DMA m2m *******************/
// 时钟
rcu_periph_clock_enable(dmax_rcu);
// 重置dma
dma_deinit(dmax, dmax_ch);dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = dmax_dirction;	
// 内存
dsdps.memory0_addr = dmax_dst;
dsdps.memory_inc = dmax_dst_inc;
// 外设
dsdps.periph_addr = dmax_src;
dsdps.periph_inc = dmax_src_inc;
// 数据长度
dsdps.number = dmax_src_len;
// 数据宽度
dsdps.periph_memory_width = dmax_src_width;
dma_single_data_mode_init(dmax, dmax_ch, &dsdps);

在这里插入图片描述

DMA初始化

uint32_t dmax = DMA1;
uint32_t dmax_rcu = RCU_DMA1;
uint32_t dmax_ch = DMA_CH0;uint32_t dmax_dirction = DMA_MEMORY_TO_MEMORY;//uint32_t dmax_src = (uint32_t)src;
uint32_t dmax_src_inc = DMA_PERIPH_INCREASE_ENABLE;
uint32_t dmax_src_width = DMA_PERIPH_WIDTH_8BIT;
//uint32_t dmax_src_len = ARR_LEN;uint32_t dmax_dst = (uint32_t)dst;
uint32_t dmax_dst_inc = DMA_MEMORY_INCREASE_ENABLE;
/***************** DMA m2m *******************/
// 时钟
rcu_periph_clock_enable(dmax_rcu);
// 重置dma
dma_deinit(dmax, dmax_ch);dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = dmax_dirction;	
// 内存
dsdps.memory0_addr = dmax_dst;
dsdps.memory_inc = dmax_dst_inc;
// 外设
//dsdps.periph_addr = dmax_src;
dsdps.periph_inc = dmax_src_inc;
// 数据长度
//dsdps.number = dmax_src_len;
// 数据宽度
dsdps.periph_memory_width = dmax_src_width;
dma_single_data_mode_init(dmax, dmax_ch, &dsdps);

DMA初始化

初始化时,不再初始化源地址和要传输的长度。
DMA数据传输请求

uint32_t dmax = DMA1;
uint32_t dmax_rcu = RCU_DMA1;
uint32_t dmax_ch = DMA_CH0;uint32_t dmax_dirction = DMA_MEMORY_TO_MEMORY;//uint32_t dmax_src = (uint32_t)src;
uint32_t dmax_src_inc = DMA_PERIPH_INCREASE_ENABLE;
uint32_t dmax_src_width = DMA_PERIPH_WIDTH_8BIT;
//uint32_t dmax_src_len = ARR_LEN;uint32_t dmax_dst = (uint32_t)dst;
uint32_t dmax_dst_inc = DMA_MEMORY_INCREASE_ENABLE;
/***************** DMA m2m *******************/
// 时钟
rcu_periph_clock_enable(dmax_rcu);
// 重置dma
dma_deinit(dmax, dmax_ch);dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = dmax_dirction;	
// 内存
dsdps.memory0_addr = dmax_dst;
dsdps.memory_inc = dmax_dst_inc;
// 外设
//dsdps.periph_addr = dmax_src;
dsdps.periph_inc = dmax_src_inc;
// 数据长度
//dsdps.number = dmax_src_len;
// 数据宽度
dsdps.periph_memory_width = dmax_src_width;
dma_single_data_mode_init(dmax, dmax_ch, &dsdps);

DMA数据传输请求

dma_periph_address_config(DMA1, DMA_CH0,(uint32_t)data);
dma_transfer_number_config(DMA1, DMA_CH0, len);dma_channel_enable(DMA1, DMA_CH0);
while(RESET == dma_flag_get(DMA1, DMA_CH0, DMA_FLAG_FTF));
dma_flag_clear(DMA1, DMA_CH0, DMA_FLAG_FTF);

请求数据传输前,进行动态配置:
● 在此需要注意的是,要分清楚当前是否是调用源的地址配置

完整代码

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "Usart0.h"#define ARR_LEN 1024
char dst[ARR_LEN] = {0};void Usart0_recv(uint8_t* data, uint32_t len) {printf("recv: %s\r\n", data);dma_periph_address_config(DMA1, DMA_CH0,(uint32_t)data);dma_transfer_number_config(DMA1, DMA_CH0, len);dma_channel_enable(DMA1, DMA_CH0);while(RESET == dma_flag_get(DMA1, DMA_CH0, DMA_FLAG_FTF));dma_flag_clear(DMA1, DMA_CH0, DMA_FLAG_FTF);dst[len] = '\0';printf("dst: %s\n", dst);
}static void DMA_config() {uint32_t dmax = DMA1;uint32_t dmax_rcu = RCU_DMA1;uint32_t dmax_ch = DMA_CH0;uint32_t dmax_dirction = DMA_MEMORY_TO_MEMORY;//uint32_t dmax_src = (uint32_t)src;uint32_t dmax_src_inc = DMA_PERIPH_INCREASE_ENABLE;uint32_t dmax_src_width = DMA_PERIPH_WIDTH_8BIT;//uint32_t dmax_src_len = ARR_LEN;uint32_t dmax_dst = (uint32_t)dst;uint32_t dmax_dst_inc = DMA_MEMORY_INCREASE_ENABLE;/***************** DMA m2m *******************/// 时钟rcu_periph_clock_enable(dmax_rcu);// 重置dmadma_deinit(dmax, dmax_ch);dma 配置dma_single_data_parameter_struct dsdps;dma_single_data_para_struct_init(&dsdps);// 方向dsdps.direction = dmax_dirction;	// 内存dsdps.memory0_addr = dmax_dst;dsdps.memory_inc = dmax_dst_inc;// 外设//dsdps.periph_addr = dmax_src;dsdps.periph_inc = dmax_src_inc;// 数据长度//dsdps.number = dmax_src_len;// 数据宽度dsdps.periph_memory_width = dmax_src_width;dma_single_data_mode_init(dmax, dmax_ch, &dsdps);
}int main(void)
{nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);systick_config();Usart0_init();DMA_config();while(1) {}
}

DMA中断

通常,dma数据传输完成,我们也是可以知道的。可以通过中断的方式获取。

开启中断

// 中断配置
nvic_irq_enable(DMA1_Channel0_IRQn, 2, 2);
// 中断使能
dma_interrupt_enable(DMA1, DMA_CH0, DMA_INT_FTF);
// 开启DMA通道
dma_channel_enable(DMA1, DMA_CH0);

● DMA_CHXCTL_FTFIE: 表示中断数据传输完成标记

中断函数实现

void DMA1_Channel0_IRQHandler() {// 判断中断标记if(SET == dma_interrupt_flag_get(DMA1, DMA_CH0, DMA_INT_FLAG_FTF)) {printf("INT dst: %s\n", dst);// 清理标记位dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_FTF);}
}

● DMA_INT_FLAG_FTF: 表示中断传输完成标记,需要在标记触发时做业务逻辑
● 同时,需要配合寄存器,清除标记

完整代码

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "Usart0.h"#define ARR_LEN 1024
char src[ARR_LEN] = "hello\0";
char dst[ARR_LEN] = {0};void Usart0_recv(uint8_t* data, uint32_t len) {printf("recv: %s\r\n", data);memcpy(src, data, len);src[len] = '\0';dma_channel_enable(DMA1, DMA_CH0);printf("dst: %s\n", dst);
}static void DMA_config() {uint32_t dmax = DMA1;uint32_t dmax_rcu = RCU_DMA1;uint32_t dmax_ch = DMA_CH0;uint32_t dmax_dirction = DMA_MEMORY_TO_MEMORY;uint32_t dmax_src = (uint32_t)src;uint32_t dmax_src_inc = DMA_PERIPH_INCREASE_ENABLE;uint32_t dmax_src_width = DMA_PERIPH_WIDTH_8BIT;uint32_t dmax_src_len = ARR_LEN;uint32_t dmax_dst = (uint32_t)dst;uint32_t dmax_dst_inc = DMA_MEMORY_INCREASE_ENABLE;/***************** DMA m2m *******************/// 时钟rcu_periph_clock_enable(dmax_rcu);// 重置dmadma_deinit(dmax, dmax_ch);dma 配置dma_single_data_parameter_struct dsdps;dma_single_data_para_struct_init(&dsdps);// 方向dsdps.direction = dmax_dirction;	// 内存dsdps.memory0_addr = dmax_dst;dsdps.memory_inc = dmax_dst_inc;// 外设dsdps.periph_addr = dmax_src;dsdps.periph_inc = dmax_src_inc;// 数据长度dsdps.number = dmax_src_len;// 数据宽度dsdps.periph_memory_width = dmax_src_width;dma_single_data_mode_init(dmax, dmax_ch, &dsdps);// 配置中断nvic_irq_enable(DMA1_Channel0_IRQn, 2, 2);dma_interrupt_enable(dmax, dmax_ch, DMA_INT_FTF);
}void DMA1_Channel0_IRQHandler() {// 判断中断标记if(SET == dma_interrupt_flag_get(DMA1, DMA_CH0, DMA_INT_FLAG_FTF)) {printf("INT dst: %s\n", dst);// 清理标记位dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_FTF);}
}int main(void)
{nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);systick_config();Usart0_init();DMA_config();while(1) {}
}

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

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

相关文章

vue3实现拖拽移动位置,拖拽过程中鼠标松开后元素还吸附在鼠标上并随着鼠标移动

发现问题 拖拽元素移动的时候&#xff0c;偶尔会出现拖拽过程中鼠标松开后元素还吸附在鼠标上并随着鼠标移动&#xff0c;要再按一下元素才会被放置下来。但是有时就正常。 问题分析 出现该问题的原因是&#xff1a;这个过程会触发H5原生的拖拽事件&#xff0c;并且不会监听…

.NET 8月份红队武器库和资源集合

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

MacBook真的不能打游戏吗?Mac打游戏会损坏电脑吗?苹果电脑怎么玩游戏

MacBook从来都是高端的代名词&#xff0c;超强的性能搭配顶尖的系统&#xff0c;不光处理大型文件时举重若轻&#xff0c;长期使用也不会有明显卡顿。但很多人在需要MacBook一流的生产力同时&#xff0c;也希望能在空闲时体验游戏的乐趣。在大多人的印象里&#xff0c;Mac电脑对…

【MIT 6.5840/6.824】In Search of an Understandable Consensus Algorithm 学习笔记

In Search of an Understandable Consensus Algorithm 1 Introduction2 Replicated state machines3 What’s wrong with Paxos?4 Designing for understandability5 The Raft consensus algorithm5.1 Raft basics5.2 Leader election5.3 Log replication5.4 Safety5.4.1 Elec…

服务器数据恢复—Raid磁盘阵列故障类型和常见故障原因

出于尽可能避免数据灾难的设计初衷&#xff0c;RAID解决了3个问题&#xff1a;容量问题、IO性能问题、存储安全(冗余)问题。从数据恢复的角度讨论RAID的存储安全问题。 常见的起到存储安全作用的RAID方案有RAID1、RAID5及其变形。基本设计思路是相似的&#xff1a;当部分数据异…

【渗透测试专栏】1.2认证和授权类-越权访问(水平/垂直越权)

该系列专栏旨在让漏洞检测变得更简单&#xff0c;只用于学习用途 靶机环境请看专栏前言专栏前言-WooYun漏洞库环境搭建-CSDN博客 目录 该系列专栏旨在让漏洞检测变得更简单&#xff0c;只用于学习用途 一、漏洞描述 1、水平越权 2、垂直越权 二、漏洞级别 三、漏洞检测…

PyTorch 创建数据集

图片数据和标签数据准备 1.本文所用图片数据在同级文件夹中 ,文件路径为train/’ 2.标签数据在同级文件&#xff0c;文件路径为train.csv 3。将标签数据提取 train_csvpd.read_csv(train.csv)创建继承类 第一步&#xff0c;首先创建数据类对象 此时可以想象为单个数据单元的…

信创实践(3):基于x2openEuler将CentOS升级成openEuler,享受其带来的创新和安全特性

引言&#xff1a; 在当前的 IT 行业中&#xff0c;创新和安全性是两大关键趋势。随着 CentOS 停止维护&#xff0c;许多用户正在寻找替代方案&#xff0c;以保持其系统的更新和安全。openEuler 作为一个强大的开源操作系统&#xff0c;成为了理想的迁移目标。本教程将指导您如…

Java线程池的优化策略与最佳实践

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云/阿里云/华为云/51CTO&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互…

LiveQing视频点播流媒体RTMP推流服务功能-支持大疆等无人机RTMP推流支持OBS推流一步一步搭建RTMP视频流媒体服务示例

LiveQing支持大疆等无人机RTMP推流支持OBS推流一步一步搭建RTMP视频流媒体服务示例 1、流媒体服务搭建2、推流工具准备3、创建鉴权直播间4、获取推流地址5、配置OBS推流6、推流及播放7、获取播放地址7.1 页面查看视频源地址7.2 接口查询 8、相关问题8.1、大疆无人机推流花屏 9、…

感知机模型

一、概述 感知机模型(Perceptron Model)也叫做神经元模型&#xff0c;设计灵感即来自于生物神经元的运行机制&#xff0c;依次完成信息接收、处理、输出的过程。当前大放异彩的各种人工神经网络模型即由一个个人工神经元构成&#xff0c;因此&#xff0c;本文介绍的感知机模型&…

【Python123题库】#2019慈善排行 #酒店评价数据分析

禁止转载&#xff0c;原文&#xff1a;https://blog.csdn.net/qq_45801887/article/details/140087686 参考教程&#xff1a;B站视频讲解——https://space.bilibili.com/3546616042621301 有帮助麻烦点个赞 ~ ~ Python123题库 2019慈善排行酒店评价数据分析 2019慈善排行 描…

Hugging Face Offline Mode 离线模式

Hugging Face Offline Mode 离线模式 1. 缓存管理2. 遥测日志 在使用 Hugging Face 的库时&#xff0c;缓存和遥测日志是两个重要的功能。本文将介绍如何管理缓存、启用离线模式以及如何关闭遥测日志。 1. 缓存管理 在使用 Hugging Face 模型时&#xff0c;权重和文件通常会从…

详解 MQ 消息队列

谈起消息队列&#xff0c;内心还是会有些波澜。 消息队列&#xff0c;缓存&#xff0c;分库分表是高并发解决方案三剑客&#xff0c;而消息队列是我最喜欢&#xff0c;也是思考最多的技术。 我想按照下面的四个阶段分享我与消息队列的故事&#xff0c;同时也是对我技术成长经…

使用Fign进行客户端远程调用和SpringFormEncoder的使用

1、引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> 2、启动类加上注解 EnableFeignClients SpringBootApplication public class FeignTe…

0成本实现.NET Web API 8.0项目内网映射

1.背景 最近在学习CICD&#xff0c;里面会有用到内网映射的使用场景。为了加深对内网映射实操的记忆。我实操了下基于.Net 8.0的内网映射&#xff0c;并支持互联网访问。本文主要介绍了在win11下安装路由侠&#xff0c;并将.net 8.0发布到win11&#xff0c;项目运行、路由侠配…

vue基于sockjs-client+stompjs实现websocket客户端

在之前的一欸文章中&#xff0c;介绍了好几种前端实现websocket客户端与服务端通信的方式。本章主要采用的是socketjs的方式。 SockJS 是一个浏览器 JavaScript 库&#xff0c;提供类似 WebSocket 的对象。它为浏览器提供了紧密遵循 HTML5 WebSockets API 的 JavaScript API&am…

【学习笔记】5G-A时代物联网应用及策略研究

摘要 海量物联网通信是5G典型应用场景之一&#xff0c;为了实现蜂窝网的全场景物联能力&#xff0c;需要更多的场景化技术&#xff0c;5G-A引入了RedCap&#xff08;5G Reduced Capability&#xff09;和Passive IoT。其中&#xff0c;RedCap降低了设备复杂性及成本&#xff0…

mybatis @Param 注解

在 MyBatis 中&#xff0c;Param 注解用于将方法参数绑定到 SQL 查询语句中的参数上。具体来说&#xff0c;当你在 Mapper 接口中定义方法时&#xff0c;Param 注解可以帮助你指定参数的名称&#xff0c;以便在 SQL 映射文件中使用这些名称。 使用 Param 注解的原因 当你在 M…

weblogic漏洞——CVE-2020-14882

一、基本信息 靶机&#xff1a;IP&#xff1a;192.168.100.40 二、攻击过程 进入 vulhub 靶场相关目录&#xff0c;并启动环境 cd master/weblogic/CVE-2020-14882 docker-compose up -d 绕过登录验证 http://192.168.100.40:7001/console/css/%252e%252e%252fconsole.por…