STM32H7的MDMA、DMA2D和通用DMA性能比较

news2024/9/21 1:29:59

STM32H7的MDMA、DMA2D和通用DMA性能比较

  • MDMA测试
    • 初始化MDMA
    • 数据传输(DWT单位2.5n)
  • DMA2D
    • DMA2D初始化
    • 数据传输
  • DMA
  • 最终结论(参考armfly)

MDMA,DMA2D 和每个都测试了四种情况:
◆ 64 位带宽的 AXI SRAM 内部做 64KB 数据传输。
◆ 32 位带宽的 D2 域 SRAM1 内部 64KB 数据传输。
◆ AXI SRAM 向 SDRAM 传输 64KB 的数据传输。
◆ 32 位带宽的 SDRAM 内部做 64KB 数据传输。
MDMA:
在 D1 域,支持 64 位带宽的 DMA 数据传输。
DMA2D:
在 D1 域,主要用图形 2D 加速。
DMA1 和 DMA2:
在 D2 域,支持 32 位带宽的 DMA 数据传输。

MDMA测试

采用块传输,源地址和目的地址都是 64bit 数据传输,并设置 16beat 突发,也就是
连续传输 16 组 64bit 数据。

初始化MDMA

	__HAL_RCC_MDMA_CLK_ENABLE();  

	MDMA_Handle.Instance = MDMA_Channel0;  

	/* MDMA配置 **********************************************************************/
	__HAL_RCC_MDMA_CLK_ENABLE();  

	MDMA_Handle.Instance = MDMA_Channel0;  

	MDMA_Handle.Init.Request              = MDMA_REQUEST_SW;         /* 软件触发 */
	MDMA_Handle.Init.TransferTriggerMode  = MDMA_BLOCK_TRANSFER;     /* 块传输 */
	MDMA_Handle.Init.Priority             = MDMA_PRIORITY_HIGH;      /* 优先级高*/
	MDMA_Handle.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE; /* 小端 */
	MDMA_Handle.Init.SourceInc            = MDMA_SRC_INC_DOUBLEWORD;         /* 源地址自增,双字,即8字节 */
	MDMA_Handle.Init.DestinationInc       = MDMA_DEST_INC_DOUBLEWORD;        /* 目的地址自增,双字,即8字节 */
	MDMA_Handle.Init.SourceDataSize       = MDMA_SRC_DATASIZE_DOUBLEWORD;    /* 源地址数据宽度双字,即8字节 */
	MDMA_Handle.Init.DestDataSize         = MDMA_DEST_DATASIZE_DOUBLEWORD;   /* 目的地址数据宽度双字,即8字节 */
	MDMA_Handle.Init.DataAlignment        = MDMA_DATAALIGN_PACKENABLE;       /* 小端,右对齐 */                    
	MDMA_Handle.Init.SourceBurst          = MDMA_SOURCE_BURST_16BEATS;      /* 源数据突发传输,SourceBurst*SourceDataSize <  BufferTransferLength*/
	MDMA_Handle.Init.DestBurst            = MDMA_DEST_BURST_16BEATS;        /* 目的数据突发传输,DestBurst*DestDataSize < BufferTransferLength */

	MDMA_Handle.Init.BufferTransferLength = 128;    /* 每次传输128个字节 */

	MDMA_Handle.Init.SourceBlockAddressOffset  = 0; /* 用于block传输,地址偏移0 */
	MDMA_Handle.Init.DestBlockAddressOffset    = 0; /* 用于block传输,地址偏移0 */

	/* 初始化MDMA */
	if(HAL_MDMA_Init(&MDMA_Handle) != HAL_OK)
	{
		 Error_Handler(__FILE__, __LINE__);
	}
	/* 设置传输完成回调和中断及其优先级配置 */
	HAL_MDMA_RegisterCallback(&MDMA_Handle, HAL_MDMA_XFER_CPLT_CB_ID, MDMA_TransferCompleteCallback);
	HAL_NVIC_SetPriority(MDMA_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(MDMA_IRQn);  
	//配置中断
	void MDMA_IRQHandler(void)
{
	HAL_MDMA_IRQHandler(&MDMA_Handle);
}
static void MDMA_TransferCompleteCallback(MDMA_HandleTypeDef *hmdma)
{
	TransferCompleteDetected = 1;
}

需要注意的是
◆ 第 1 行,务必优先初始化 MDMA 时钟,测试发现没有使能时钟的情况下就配置 MDMA 很容易失败。
◆ 第 14-15 行,突发传输的配置非常考究,每次突发传输的总数据大小不能超过 128 字节。
对于源地址就是 SourceBurst * SourceDataSize <= BufferTransferLength。
对于目的地址就是 DestBurstDestDataSize <= BufferTransferLength。
比如当前的程序配置:
SourceBurst * SourceDataSize = 16
8 =128 字节
DestBurstDestDataSize = 168 =128 字节
这里要特别注意一点,如果实际应用中最好小于 BufferTransferLength,防止不稳定。

数据传输(DWT单位2.5n)

    /* AXI SRAM的64KB数据传输测试 ***********************************************/
	TransferCompleteDetected = 0;
	HAL_MDMA_Start_IT(&MDMA_Handle, 
				      (uint32_t)0x24000000, 
				      (uint32_t)(0x24000000 + 64*1024), 
				      64*1024, 
				      1);


	start = DWT_CYCCNT;
	while(TransferCompleteDetected == 0) {}
	end = DWT_CYCCNT;
	cnt = end - start;
 
	//64*1024/(cnt/400/1000/1000)/1024/1024 = 64*1000*1000*400/1024/cnt = 25000000/cnt
	printf("MDMA---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
		
    /* D2域SRAM1的64KB数据传输测试 ***********************************************/
	TransferCompleteDetected = 0;
	HAL_MDMA_Start_IT(&MDMA_Handle, 
				      (uint32_t)0x30000000, 
				      (uint32_t)(0x30000000 + 64*1024), 
				      64*1024, 
				      1);

	start = DWT_CYCCNT;
	while(TransferCompleteDetected == 0) {}
	end = DWT_CYCCNT;
	cnt = end - start;

	printf("MDMA---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
		
	/* AXI SRAM向SDRAM的64KB数据传输测试 ***********************************************/
	TransferCompleteDetected = 0;
	HAL_MDMA_Start_IT(&MDMA_Handle, 
				      (uint32_t)0x24000000, 
				      (uint32_t)0xC0000000, 
				      64*1024, 
				      1);

	start = DWT_CYCCNT;
	while(TransferCompleteDetected == 0) {}
	end = DWT_CYCCNT;
	cnt = end - start;

	printf("MDMA---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
		
	/* SDRAM的64KB数据传输测试 ***********************************************/
	TransferCompleteDetected = 0;
	HAL_MDMA_Start_IT(&MDMA_Handle, 
				      (uint32_t)0xC0000000, 
				      (uint32_t)(0xC0000000 + 64*1024), 
				      64*1024, 
				      1);


	start = DWT_CYCCNT;
	while(TransferCompleteDetected == 0) {}
	end = DWT_CYCCNT;
	cnt = end - start;

	printf("MDMA---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);

DMA2D

DMA2D初始化

配置 DMA2D 采用存储器到存储器模式,前景区和输出区都采用 ARGB8888 格式,传输 64256 次,每次 4 字节,即 64256*4 = 64KB 数据。

	__HAL_RCC_DMA2D_CLK_ENABLE();  
	
	/* DMA2D采用存储器到存储器模式, 这种模式是前景层作为DMA2D输入 */  
	DMA2D->CR      = 0x00000000UL;
	DMA2D->FGOR    = 0;
	DMA2D->OOR     = 0;
	
	/* 前景层和输出区域都采用的RGB565颜色格式 */
	DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_ARGB8888;
	DMA2D->OPFCCR  = LTDC_PIXEL_FORMAT_ARGB8888;
	
	DMA2D->NLR     = (uint32_t)(64 << 16) | (uint16_t)256;

数据传输

 /* AXI SRAM的64KB数据传输测试 ***********************************************/
	DMA2D->FGMAR = (uint32_t)0x24000000;
	DMA2D->OMAR  = (uint32_t)(0x24000000 + 64*1024);
	DMA2D->CR   |= DMA2D_CR_START;   
	
	start = DWT_CYCCNT;
	/* 等待DMA2D传输完成 */
	while (DMA2D->CR & DMA2D_CR_START) {} 
	end = DWT_CYCCNT;
	cnt = end - start;
	
	printf("DMA2D---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
		
    /* D2域SRAM1的64KB数据传输测试 ***********************************************/
	DMA2D->FGMAR = (uint32_t)0x30000000;
	DMA2D->OMAR  = (uint32_t)(0x30000000 + 64*1024);
	DMA2D->CR   |= DMA2D_CR_START;  
	
	start = DWT_CYCCNT;
	/* 等待DMA2D传输完成 */
	while (DMA2D->CR & DMA2D_CR_START) {} 
	end = DWT_CYCCNT;
	cnt = end - start;
		
	printf("DMA2D---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
		
	/* AXI SRAM向SDRAM的64KB数据传输测试 ***********************************************/
	DMA2D->FGMAR = (uint32_t)0x24000000;
	DMA2D->OMAR  = (uint32_t)0xC0000000;
	DMA2D->CR   |= DMA2D_CR_START;  
	
	start = DWT_CYCCNT;
	/* 等待DMA2D传输完成 */
	while (DMA2D->CR & DMA2D_CR_START) {} 
	end = DWT_CYCCNT;
	cnt = end - start;
		
	printf("DMA2D---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);	

	/* SDRAM的64KB数据传输测试 ***********************************************/
	DMA2D->FGMAR = (uint32_t)0xC0000000;
	DMA2D->OMAR  = (uint32_t)(0xC0000000 + 64*1024);
	DMA2D->CR   |= DMA2D_CR_START;
	
	start = DWT_CYCCNT;
	/* 等待DMA2D传输完成 */
	while (DMA2D->CR & DMA2D_CR_START) {} 
	end = DWT_CYCCNT;
	cnt = end - start;	
		
	printf("DMA2D---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);	

DMA

程序代码如下,采用存储区到存储区传输方式,源地址和目的地址都是 32bit 数据传输,并设置 4beat突发,也就是连续传输 4 组 32bit 数据。

	__HAL_RCC_DMA1_CLK_ENABLE();

	DMA_Handle.Instance                 = DMA1_Stream1;
	DMA_Handle.Init.Request             = DMA_REQUEST_MEM2MEM;  
	DMA_Handle.Init.Direction           = DMA_MEMORY_TO_MEMORY;
	DMA_Handle.Init.PeriphInc           = DMA_PINC_ENABLE;
	DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;
	DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
	DMA_Handle.Init.MemDataAlignment    = DMA_PDATAALIGN_WORD;
	DMA_Handle.Init.Mode                = DMA_NORMAL;
	DMA_Handle.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
	DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
	DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
	DMA_Handle.Init.MemBurst            = DMA_MBURST_INC4;     /*WORD方式,仅支持4次突发 */
	DMA_Handle.Init.PeriphBurst         = DMA_PBURST_INC4;      /*WORD方式,仅支持4次突发 */
	DMA_Handle.XferCpltCallback         = DMA_TransferCompleteCallback;

	HAL_DMA_Init(&DMA_Handle);
	HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
	void DMA1_Stream1_IRQHandler(void)
	{
	 HAL_DMA_IRQHandler(&DMA_Handle);
	}
	static void DMA_TransferCompleteCallback(DMA_HandleTypeDef *hdma)
	{
	TransferCompleteDetected = 1;
	}

第 1 行,务必优先初始化 DMA 时钟,测试发现没有使能时钟的情况下就配置 DMA 很容易失败。
第 14-15 行,突发传输的配置非常考究,这里要特别注意数据位宽,FIFO 以及突发的配置。
在这里插入图片描述

	HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x24000000, (uint32_t)(0x24000000 + 64*1024), 64*256);

	start = DWT_CYCCNT;
	while(TransferCompleteDetected == 0) {}
	end = DWT_CYCCNT;
	cnt = end - start;
 
	//64*1024/(cnt/400/1000/1000)/1024/1024 = 64*1000*1000*400/1024/cnt = 25000000/cnt
	printf("DMA1---AXI SRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
		
	/* D2域SRAM1的64KB数据传输测试 ***********************************************/
	TransferCompleteDetected = 0;
	HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x30000000, (uint32_t)(0x30000000 + 64*1024), 64*256);

	start = DWT_CYCCNT;
	while(TransferCompleteDetected == 0) {}
	end = DWT_CYCCNT;
	cnt = end - start;

	printf("DMA1---D2域SRAM1内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
		
		
	/* AXI SRAM向SDRAM的64KB数据传输测试 ***********************************************/
	TransferCompleteDetected = 0;
	HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0x24000000, (uint32_t)0xC0000000, 64*256);

	start = DWT_CYCCNT;
	while(TransferCompleteDetected == 0) {}
	end = DWT_CYCCNT;
	cnt = end - start;

	printf("DMA1---AXI SRAM传输64KB数据到SDRAM耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);
		
	/* SDRAM的64KB数据传输测试 ***********************************************/
	TransferCompleteDetected = 0;
	HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)0xC0000000, (uint32_t)(0xC0000000 + 64*1024), 64*256);	

	start = DWT_CYCCNT;
	while(TransferCompleteDetected == 0) {}
	end = DWT_CYCCNT;
	cnt = end - start;

	printf("DMA1---SDRAM内部互传64KB数据耗时 =  %dus %dMB/S\r\n", cnt/400, 25000000/cnt);

最终结论(参考armfly)

在这里插入图片描述

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

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

相关文章

STM32F401VET6 PROTEUS8 ILI9341 驱动显示及仿真

stm32cubemx新建工程代码&#xff0c;并生成工程 设置gpio 设置SPI 其他的参考stm32默认设置 然后编辑驱动代码 ili9341.h #ifndef ILI9341_H #define ILI9341_H#include <stdbool.h> #include <stdint.h>#include "glcdfont.h" #include "stm32…

rv1126物体检测 rkmedia、opencv……

整体码流流向&#xff1a; 因此代码也分为这几部分&#xff1a; VI&#xff1a;采集视频 配置视频采集信息 模型推理线程&#xff1a;获取VI码流、载入模型、进行模型推理、保存推理结果 画框线程&#xff1a;获取VI码流、获取推理结果、显示推理结果、输出码流到VENC VENC…

w30-python02-pytest入门

代码如下&#xff1a; import pytest class Test_Obj:"""测试类"""#用例级别前后置def setup(self):print(用例级别------的前置处理)def teardown(self):print("用例级别--------的后置处理")# 用例def test_case1(self):print(&quo…

Photoshop(PS) 抠图简单教程

目录 快速选择 魔棒 钢笔 橡皮擦 蒙版 通道 小结 可以发现&#xff0c;ps逐渐成为必备基础的办公软件。本文让ps新手轻松学会抠图。 快速选择 在抠图之前&#xff0c;先了解下选区的概念。ps中大多数的抠图操作都是基于选区的&#xff0c;先选区再Ctrl J提取选区。而快…

android13 Settings动态显示隐藏某一项

总纲 android13 rom 开发总纲说明 目录 1.前言 2.确定目标设置项 3.修改参考 3.1 方法1 3.2 方法2 4.编译测试 5.彩蛋 1.前言 在Android 13系统中,动态显示或隐藏Settings应用中的某一项通常涉及到对Settings应用的内部逻辑进行修改。由于Settings应用是一个系统应用…

Fine-BI学习笔记

官方学习文档&#xff1a;快速入门指南- FineBI帮助文档 FineBI帮助文档 (fanruan.com) 1.零基础入门 1.1 功能简介 完成四个流程&#xff1a;新建分析主题、添加数据、分析数据、分享协作。 示例数据获取&#xff1a;5分钟上手FineBI - FineBI帮助文档 (fanruan.com) 1.2 …

Vue--解决error:0308010C:digital envelope routines::unsupported

原文网址&#xff1a;Vue--解决error:0308010C:digital envelope routines::unsupported_IT利刃出鞘的博客-CSDN博客 简介 本文介绍如何解决node.js在运行Vue项目时的报错&#xff1a;error:0308010C:digital envelope routines::unsupported。 问题描述 使用node.js运行Vu…

Zabbix监控TiDB数据库教程

作者 乐维社区&#xff08;forum.lwops.cn&#xff09; 许远 1概述 TiDB数据库是一个常见的开源分布式关系型数据库&#xff0c;通过使用分布式事务、分布式 SQL 引擎和分布式存储引擎来实现高可用性和横向扩展性。而 Docker 则是一个开源的容器化平台&#xff0c;它可以帮助开…

服务端渲染中的数据获取:结合 useRequestHeaders 与 useFetch

title: 服务端渲染中的数据获取&#xff1a;结合 useRequestHeaders 与 useFetch date: 2024/7/24 updated: 2024/7/24 author: cmdragon excerpt: 摘要&#xff1a;本文介绍Vue服务端渲染中使用useRequestHeaders获取请求头部信息&#xff0c;如cookie和authorization&…

入门 PyQt6 看过来(案例)07~ 文件选择

本文实现一个图片和文本文件选择器的案例&#xff0c;效果如下&#xff1a; ​ 文件选择查看功能很简单&#xff0c;只需要设计好图片文件和文本文件的选择函数就可以了。 1 图片文件选择 #图片文件选择槽函数&#xff0c;支持png ico jpg格式文件def imgFile(self):fname, _tm…

paraFoam 运行 报错 usr/lib/x86_64-linux-gnu/libQt5Core.so 已解决

在日常项目开发中。使用ubuntu 视图开发的时候。报错 缺少 libQt5Core 核心组件&#xff01; whereis libQt5Core.so.5sudo strip --remove-section.note.ABI-tag /usr/lib/x86_64-linux-gnu/libQt5Core.so.5 完美解决&#xff0c;并且能正常打开&#xff0c;前提是&#xff0c…

嵌入式MCU固件的几种Flash划分方式详解

通过OTA远程等方式下载的程序,其实还需要提前下载bootloader程序,才能进一步下载APP程序。 今天就来说说通过OTA方式升级固件时,几种flash划分方式。 独立型 所谓独立型就是专门划出一部分闪存(Flash)空间用来存储引导程序(BootLoader)。 如下图: BootLoader:引导…

如何正确选择叉车防撞系统?不可忽视的五大关键要素!

在繁忙的工业环境中&#xff0c;叉车防撞系统的选择是一项至关重要的任务。一个高效、可靠的防撞系统&#xff0c;不仅能够减少事故发生率&#xff0c;还能保障员工的安全和设备的完好。然而&#xff0c;市场上的叉车防撞系统种类繁多&#xff0c;如何正确选择&#xff0c;避免…

SQL注入万字详解,基于sqli-labs(手注+sqlmap)

目录 一、什么是SQL 1.什么是SQL 2.SQL的作用 3.MySQL基础知识 4.SQL增、删、改语句 *5.SQL查询语句 二、什么是SQL注入 1.SQL注入原理&#xff1a; 2.SQL注入&#xff1a; 3.SQL注入危害&#xff1a; 4.SQL注入技术分类&#xff1a; 5.防御方法&#xff1a;使用参…

图形编辑器基于Paper.js教程09:鼠标拖动画布,以鼠标点为缩放中心进行视图的缩放

如何使用Paper.js实现画布的缩放与拖动功能 在Web开发中&#xff0c;利用Paper.js库进行图形的绘制和交互操作是一种常见的实践。Paper.js是一个强大的矢量图形库&#xff0c;可以让开发者通过简洁的API完成复杂的图形操作。在本文中&#xff0c;我们将详细探讨如何使用Paper.…

electron安装及快速创建

electron安装及快速创建 electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 详细内容见官网&#xff1a;https://www.electronjs.org/zh/docs/latest/。 今天来记录下练习中的安装过程和hello world的创建。 创建项目文件夹&#xff0c;并执行npm 初始化命…

【MetaGPT系列】【MetaGPT完全实践宝典——如何定义单一行为多行为Agent】

目录 前言一、智能体1-1、Agent概述1-2、Agent与ChatGPT的区别 二、多智能体框架MetaGPT2-1、安装&配置2-2、使用已有的Agent&#xff08;ProductManager&#xff09;2-3、拥有单一行为的Agent&#xff08;SimpleCoder&#xff09;2-3-1、定义写代码行为2-3-2、角色定义2-3…

增材制造与智能制造关系

在撰写的增材制造技术与装备书籍中有着明确的描述&#xff0c;增材制造是智能制造的典型范例&#xff0c;是智能制造“类”的实例化过程。这种借助于计算机编程面向对象思想的解释可以更全面的理解增材制造和智能制造的关系。增材制造实例具备了智能制造类的属性&#xff0c;智…

第4章 .NET 8.0 ASP.NET Core图书管理系统 :项目布局

第1章 框架学习的基石与实战策略 第2章 大话ASP.NET Core 入门 第3章 创建最小&#xff08;Minimal APIs&#xff09;API应用程序 第4章 .NET 8.0 ASP.NET Core图书管理系统 &#xff1a;项目布局 在第3章中&#xff0c;我们利用ASP.NET Core的“空”模板创建了BookQueryS…

2、springboot3 vue3开发平台-后端-基础数据准备,MybatisPlus整合

文章目录 1. 基础数据准备2. 整合MybatisPlus3. MybatisPlus 配置3.1 数据源配置3.2 mybatis-plus 分页插件配置3.3 mybatis-plus 自动填充3.4 代码生成器 1. 基础数据准备 直接拿前辈做的表结构使用。 /*Navicat Premium Data TransferSource Server : localhost_my…