5、DMA Demo(STM32F407)

DMA简介

DMA 全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。 DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。

作用:为CPU减负。

DMA原理

STM32F4最多有2个DMA控制器,2个DMA控制器总共有16个数据流(每个控制器8个)。每个DMA控制器都用于管理一个或者多个外设的存储器访问请求。每个数据流总共可以有多达8个通道(或请求),每个通道都有一个仲裁器,用于处理DMA请求间的优先级。

DMA框图

 

DMA配置参数

  1.  通道
  2. 优先级
  3. 数据传输方向
  4. 存储器/外设 数据宽度
  5. 存储器/外设 地址是否增量
  6. 循环模式
  7. 数据传输量

程序源码

dma.h

#ifndef __DMA_H
#define	__DMA_H	   
#include "sys.h"

void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr);//配置DMAx_CHx
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr);	//使能一次DMA传输		   
#endif

dma.c

#include "dma.h"
#include "delay.h"

// DMAx的各通道配置
// 这里的传输形式是固定的,这点要根据不同的情况来修改
// 从存储器->外设模式/8位数据宽度/存储器增量模式
// DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
// chx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
// par:外设地址
// mar:存储器地址
// ndtr:数据传输量
void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx, u32 chx, u32 par, u32 mar, u16 ndtr)
{

  DMA_InitTypeDef DMA_InitStructure;

  if ((u32)DMA_Streamx > (u32)DMA2) // 得到当前stream是属于DMA2还是DMA1
  {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // DMA2时钟使能
  }
  else
  {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); // DMA1时钟使能
  }
  DMA_DeInit(DMA_Streamx);

  while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE)
  {
  } // 等待DMA可配置

  /* 配置 DMA Stream */
  DMA_InitStructure.DMA_Channel = chx;                                    // 通道选择
  DMA_InitStructure.DMA_PeripheralBaseAddr = par;                         // DMA外设地址
  DMA_InitStructure.DMA_Memory0BaseAddr = mar;                            // DMA 存储器0地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                 // 存储器到外设模式
  DMA_InitStructure.DMA_BufferSize = ndtr;                                // 数据传输量
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        // 外设非增量模式
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 // 存储器增量模式
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据长度:8位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         // 存储器数据长度:8位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                           // 使用普通模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                   // 中等优先级
  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(DMA_Streamx, &DMA_InitStructure);                          // 初始化DMA Stream
}
// 开启一次DMA传输
// DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
// ndtr:数据传输量
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx, u16 ndtr)
{

  DMA_Cmd(DMA_Streamx, DISABLE); // 关闭DMA传输

  while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE)
  {
  } // 确保DMA可以被设置

  DMA_SetCurrDataCounter(DMA_Streamx, ndtr); // 数据传输量

  DMA_Cmd(DMA_Streamx, ENABLE); // 开启DMA传输
}

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"
#include "dma.h"

#define SEND_BUF_SIZE 8200 // 发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.

u8 SendBuff[SEND_BUF_SIZE]; // 发送数据缓冲区
const u8 TEXT_TO_SEND[] = {"ALIENTEK Explorer STM32F4 DMA 串口实验"};

int main(void)
{
	u16 i;
	u8 t = 0;
	u8 j, mask = 0;
	float pro = 0;									// 进度
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置系统中断优先级分组2
	delay_init(168);								// 初始化延时函数
	uart_init(115200);								// 初始化串口波特率为115200
	LED_Init();										// 初始化LED
	LCD_Init();										// LCD初始化
	KEY_Init();										// 按键初始化
	// 配置DMA,使用DMA2的第7个数据流和第4个通道,将USART1的数据寄存器作为外设,SendBuff作为存储器,传输长度为SEND_BUF_SIZE
	MYDMA_Config(DMA2_Stream7, DMA_Channel_4, (u32)&USART1->DR, (u32)SendBuff, SEND_BUF_SIZE); // DMA2,STEAM7,CH4,外设为串口1,存储器为SendBuff,长度为:SEND_BUF_SIZE.
	POINT_COLOR = RED;
	LCD_ShowString(30, 50, 200, 16, 16, "Explorer STM32F4");
	LCD_ShowString(30, 70, 200, 16, 16, "DMA TEST");
	LCD_ShowString(30, 90, 200, 16, 16, "ATOM@ALIENTEK");
	LCD_ShowString(30, 110, 200, 16, 16, "2014/5/6");
	LCD_ShowString(30, 130, 200, 16, 16, "KEY0:Start");
	POINT_COLOR = BLUE; // 设置字体为蓝色
	// 显示提示信息
	j = sizeof(TEXT_TO_SEND);			// 获取TEXT_TO_SEND字符串的长度,并赋值给变量j
	for (i = 0; i < SEND_BUF_SIZE; i++) // 循环从0到SEND_BUF_SIZE-1,填充SendBuff数组
	{
		if (t >= j) // 加入换行符
		{
			if (mask)
			{
				SendBuff[i] = 0x0a; // 插入换行符
				t = 0;
			}
			else
			{
				SendBuff[i] = 0x0d; // 插入回车符
				mask++;
			}
		}
		else // 复制TEXT_TO_SEND语句
		{
			mask = 0;
			SendBuff[i] = TEXT_TO_SEND[t];
			t++;
		}
	}
	POINT_COLOR = BLUE; // 设置字体为蓝色
	i = 0;
	while (1)
	{
		t = KEY_Scan(0);	// 清除按键标记
		if (t == KEY0_PRES) // KEY0按下
		{
			printf("\r\nDMA DATA:\r\n");
			LCD_ShowString(30, 150, 200, 16, 16, "Start Transimit....");
			LCD_ShowString(30, 170, 200, 16, 16, "   %");  // 显示百分号
			USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // 使能串口1的DMA发送
			MYDMA_Enable(DMA2_Stream7, SEND_BUF_SIZE);	   // 启动一次DMA传输
			// 等待DMA传输完成,此时我们来做另外一些事,点灯
			// 实际应用中,传输数据期间,可以执行另外的任务
			while (1)
			{
				// 通过DMA_GetCurrDataCounter函数获取当前还剩余多少个数据未传输,然后计算传输的百分比
				if (DMA_GetFlagStatus(DMA2_Stream7, DMA_FLAG_TCIF7) != RESET) // 等待DMA2_Steam7传输完成
				{
					DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7); // 清除DMA2_Steam7传输完成标志
					break;
				}
				pro = DMA_GetCurrDataCounter(DMA2_Stream7); // 得到当前还剩余多少个数据
				pro = 1 - pro / SEND_BUF_SIZE;				// 得到百分比
				pro *= 100;									// 扩大100倍
				LCD_ShowNum(30, 170, pro, 3, 16);
			}
			LCD_ShowNum(30, 170, 100, 3, 16);							 // 显示100%
			LCD_ShowString(30, 150, 200, 16, 16, "Transimit Finished!"); // 提示传送完成
		}
		i++;
		delay_ms(10);
		if (i == 20)
		{
			LED0 = !LED0; // 提示系统正在运行
			i = 0;
		}
	}
}

实验效果

说明:

串口首先打印TFT屏的驱动IC(按下RESET键复位)

按下KEY0后,TFT屏显示“Transimit Finished!”并显示传输进度,串口重复打印“ALIENTEK Explorer STM32F4 DMA 串口实验”直至达到SEND_BUF_SIZE的值

DMA实验效果

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

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

相关文章

力扣295. 数据流的中位数(java,堆解法)

Problem: 295. 数据流的中位数 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 由于该题目的数据是动态的我们可以维护两个堆来解决该问题 1.维护一个大顶堆&#xff0c;一个小顶堆 2.每个堆中元素个数接近n/2&#xff1b;如果n是偶数&#xff0c;两个堆中的数据个数…

SpringCloud核心组件

Eureka 注册中心&#xff0c;服务的注册与发现 Feign远程调用 Ribbon负载均衡&#xff0c;默认轮询 Hystrix 熔断 降级 Zuul微服务网关&#xff08;这个组件负责网络路由&#xff0c;可以做统一的降级、限流、认证授权、安全&#xff09; Eureka 微服务的功能主要有以下几…

LLM之Agent(二):BabyAGI的详细教程

BabyAGI是一个 AI 支持的任务管理系统&#xff08;Python脚本&#xff09;&#xff0c;使用 OpenAI 和 Pinecone API 创建, 优先级排序和执行任务。该系统背后的主要思想是基于先前任务的结果和预定义的目标创建任务。脚本然后使用 OpenAI 的自然语言处理&#xff08;NLP&#…

数据结构学习笔记——二叉树的遍历和链式存储代码实现二叉树

目录 一、二叉树的遍历&#xff08;一&#xff09;二叉树的先序遍历&#xff08;DLR&#xff09;&#xff08;二&#xff09;二叉树的中序遍历&#xff08;LDR&#xff09;&#xff08;三&#xff09;二叉树的后序遍历&#xff08;LRD&#xff09;&#xff08;四&#xff09;二…

【古月居《ros入门21讲》学习笔记】07_创建工作空间和功能包

目录 说明&#xff1a; 1. 工作空间(workspace) 结构&#xff1a; 2. 创建工作空间和功能包 创建工作空间 编译工作空间 创建功能包 设置环境变量 3. 注意 同一个工作空间下&#xff0c;不能存在同名的功能包&#xff1b; 不同工作空间下&#xff0c;可以存在同名的功…

学习程序员必知必会的基础算法(收藏)

近年来学习python的程序员愈来愈多&#xff0c;有的同学选择了python培训机构&#xff0c;也有的人觉得自己天赋好选择了自学不管大家怎么去学习&#xff0c;在学习python基础的过程中&#xff0c;肯定离不开的就是基础算法&#xff0c;今天就为大家介绍几大学习中的基础算法。…

ffmpeg开发 环境配置

ffmpeg开发简图 1 下载ffmpeg开发包 https://ffmpeg.org/download.html 包含三个版本&#xff1a;Static、Shared以及Dev Static --- 包含3个应用程序&#xff1a;ffmpeg.exe , ffplay.exe , ffprobe.exe&#xff0c;体积都很大&#xff0c;相关的DLL已经被编译到exe里面去…

TDA4VM EVM开发板调试笔记

文章目录 1. 前言2. 官网资料导读3. 安装 Linux SDK4. 制作SD 启动卡5. 验证启动1. 前言 TDA4作为一般经典的车规级SOC芯片,基于它的低阶智驾方案目前成为各家智驾方案公司的量产首选,这也使得基于TDA4的开发需求陡增,开发和使用TDA4既要熟悉Linux驱应用开发,还要熟悉传统…

自建CA实战之 《0x02 Nginx 配置 https双向认证》

自建CA实战之 《0x02 Nginx 配置 https双向认证》 上一章节我们已经实现了Nginx上配置https单向认证&#xff0c;主要场景为客户端验证服务端的身份&#xff0c;但是服务端不验证客户端的身份。 本章节我们将实现Nginx上配置https双向认证&#xff0c;主要场景为客户端验证服…

基于Java SSM框架+Vue实现汉服文化平台网站项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架Vue实现汉服文化平台系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个汉服文化平台网站 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将…

在gazebo里搭建一个livox mid360 + 惯导仿真平台测试 FAST-LIO2

在gazebo里搭建一个livox mid360 惯导仿真平台测试 FAST-LIO2 前言立方体平台加入 livox mid360 激光雷达加入IMU模块调整底盘大小 并设计调用接口测试 Fast-Lio2 前言 livox mid360 在官网一直没有货&#xff0c;在gazebo里可以仿真该雷达形式的点云。 但是其只发布雷达的数…

【电源专题】DC/DC电源FB分压电阻设计注意事项

在DC/DC电源中我们不可避免的会遇到FB分压电阻的取值,PCB设计等问题。如下所示随意打开一份同步降压稳压器规格书TPS56320X,规格书中的简化电路原理图就已经存在VFB管脚上的两个分压电阻。 很多工程师朋友们会误认为分压电阻只是简单的将输出电压缩小到参考电压,通过此电压来…

电子学会C/C++编程等级考试2023年03月(三级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:和数(2023.3) 给定一个正整数序列,判断其中有多少个数,等于数列中其他两个数的和。 比如,对于数列1 2 3 4, 这个问题的答案就是2, 因为3 = 2 + 1, 4 = 1 + 3。 时间限制:10000 内存限制:65536输入 共两行,第一行是数列中…

【接口自动化】selenium库也有大用场(获取cookie)

相信有些童鞋在做接口、或者说接口自动化测试的过程中会遇到这样的场景&#xff1a;测试的接口&#xff0c;必须是需要登录后才能发起请求成功的。 那么怎么解决呢&#xff1f; 本着团队协作的精神&#xff0c;我们就去让开发同学开个后门&#xff0c;给你个“万能”值&#x…

AntDB“超融合+流式实时数仓”——颠覆50年未变的数据库内核

流式处理引擎&#xff0c;颠覆50年未变的数据库内核 流式处理的概念 2001年9月11日&#xff0c;美国世贸大楼被袭击&#xff0c;美国国防部第一次将“主动预警”纳入国防的宏观战略规划。而IBM作为当时全球最大的IT公司&#xff0c;承担了大量基础支撑软件研发的任务。其中200…

R语言单因素方差分析+差异显著字母法标注+逐行详细解释

R语言单因素方差分析 代码如下 df <- read.csv("data.csv",header TRUE,row.names 1) library(reshape2) df <- melt(df,idc()) names(df) <- c(trt, val) df aov1 <- aov(val~trt,datadf) summary(aov1)library(agricolae) data <- LSD.test(aov…

双指针算法总结

双指针算法分为两类&#xff1a;第一类指向一个序列&#xff08;更多的情况&#xff09;&#xff0c;第二类指向两个序列。 基本的代码框架是&#xff1a; for (i 0, j 0; i < n; i) {while (j < i && check(i, j)) j;// 每道题目的具体逻辑 } 核心思想&…

探索使用Quarkus和MicroProfile 构建Kubernetes原生微服务的秘诀!

Kubernetes Native Microservices with Quarkus and MicroProfile 是一个基于Kubernetes原生微服务的开发框架&#xff0c;它结合了Quarkus和MicroProfile的优点&#xff0c;提供了一个高效、可扩展、易于管理的微服务解决方案。 Quarkus是一个针对Java虚拟机&#xff08;JVM&…

代码demo-内部订单批量投料

为了简化用户操作&#xff0c;开发内部订单批量投料功能 用户可以批量上传&#xff0c;或者选择对应的物料&#xff0c;输入库位和内部订单号后进行过账操作 对用户选择的内部订单做校验&#xff0c;内部订单是否正确 内部订单的公司是否和工厂对应的公司一致等等 下面展示…

[NOIP2016 普及组] 回文日期

枚举好题&#xff0c;直接枚举答案 看看在不在范围内就行了 注意二月份 92200229是合法的~ 82200228也是合法的&#xff01; #include<bits/stdc.h> using namespace std;map<int,int>mp;int main() {mp[1] mp[3] mp[5] mp[7] mp[8] mp[10] mp[12] 31;mp[…