当前位置: 首页 > news >正文

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) {}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Linux】Linux常见指令以及权限理解(上)
  • 歌者PPT新功能速递!
  • 使用PowerShell自动化你的Windows开发工作流程
  • 【K8S实践笔记】Kubernetes(v1.28)集群搭建部署(1)
  • 【困难】 猿人学web第一届 第18题 jsvmp 洞察先机
  • 设计模式-行为型模式-观察者模式
  • MediaStream 的媒体流对象 (stream) 和流媒体轨道 (track) 详解
  • mysql多线程优化并行复制
  • Leetcode3259. 超级饮料的最大强化能量
  • 2024-pip install torch为CPU版本,GPU没有被使用的解决方法(windows和linux均适用)
  • uniapp动态页面API
  • 【生日视频制作】白色卡车行万里路车身改字1版AE模板修改文字软件生成器教程特效素材【AE模板】
  • 2.1概率统计的世界
  • SQL索引详解
  • 【百日算法计划】:每日一题,见证成长(010)
  • Android 控件背景颜色处理
  • Effective Java 笔记(一)
  • ES6 学习笔记(一)let,const和解构赋值
  • Java,console输出实时的转向GUI textbox
  • k8s如何管理Pod
  • October CMS - 快速入门 9 Images And Galleries
  • PHP 的 SAPI 是个什么东西
  • Redis的resp协议
  • Sublime text 3 3103 注册码
  • 服务器之间,相同帐号,实现免密钥登录
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 浅谈Golang中select的用法
  • 微信开放平台全网发布【失败】的几点排查方法
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 7行Python代码的人脸识别
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​iOS安全加固方法及实现
  • !!java web学习笔记(一到五)
  • "无招胜有招"nbsp;史上最全的互…
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • ###C语言程序设计-----C语言学习(3)#
  • #define,static,const,三种常量的区别
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (20050108)又读《平凡的世界》
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (39)STM32——FLASH闪存
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (PADS学习)第二章:原理图绘制 第一部分
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (算法)Game
  • (一)、python程序--模拟电脑鼠走迷宫
  • (一)WLAN定义和基本架构转
  • (一)基于IDEA的JAVA基础1
  • (转)大型网站架构演变和知识体系
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)