STM32入门学习之DMA

news/2024/9/20 2:04:36/ 标签: stm32, 学习, 嵌入式硬件, DMA, USART

1.直接存储访问DMA(Direct Memory Access):DMA传输不需要CPU的参与,直接在内存和I/O设备间开辟了一条新的数据传输通道,不仅提高数据传输的速率,还因为不需要CPU的干预,从而提高了CPU的利用率。(注:文中的资料参考于正点原子)

STM32最多有2个DMA通道(只有大容量的STM32才有DMA2)。DMA1有7个通道,DMA2有5个通道,每个通道用来管理一个或者多个外设对存储器的访问请求。还有一个通道用来仲裁协调各个DMA请求的优先级。STM32的DMA特性如下:

STM32F103RCT6的DMA1通道表如下:

每个通道同一时刻只能有一个外设使用DMA进行数据传输。比如DMA1的通道1中有三个外设(ADC1、TIM2_CH3、TIM4_CH1),同一时刻只能使用其中的一个外设进行DMA数据传输。本文是利用USART1进行数据传输,由表可知,需要使用的DMA1的通道4。

DMA配置的基本步骤:

(1)使能DMA的时钟,并配置DMA的初始结构体。

(2)开启DMA

(3)开启对应外设的DMA数据传输。

2.DMA相关的寄存器:

(1)DMA中断状态寄存器(DMA_ISR):当开启DMA_ISR的这些中断后,产生中断触发条件时会跳转到相应的中断服务函数。即使没有开启这些中断,也可以通过这些位来判断当前DMA的传输状态。比如可以用TCIFx来判断DMA是否传输完成。此寄存器为只读寄存器,所以当被置位之后,需要通过其他的操作来清除。

(2)DMA中断标志清除寄存器(DMA_IFCR):DMA_IFCR 的各位就是用来清除 DMA_ISR 的对应位的,通过写 0 清除。在 DMA_ISR 被置位后,必须通过向该位寄存器对应的位写入 0 来清除。

(3)DMA的其他寄存器:

3.DMA的初始化配置:

DMA的初始化函数为:void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)。参数1是DMA的通道号,参数2是一个结构体,其定义如下:

如下为DMA的一个配置实列:

初始化DMA后,然后需要使能外设的DMA功能:

最后,再使能DMA传输通道:

当需要查下DMA的状态时,可使用如下的函数:

4.代码:本文只展示DMA和main部分的代码,如果需要完整的代码,可以结合前面的文章来获取。

(1)dma.h:

#ifndef __DMA_H
#define __DMA_H#include "stm32f10x.h"//DMA_CHx:DMAͨµÀCHx
//cpar:ÍâÉèµØÖ·
//cmar:´æ´¢Æ÷µØÖ·
//cndtr:Êý¾Ý´«ÊäÁ¿ 
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr );#endif

(2)dma.c:

#include "dma.h"DMA_InitTypeDef DMA_InitStructure;
u16 DMA1_LEN;											//DMA´«ÊäµÄÊý¾Ý³¤¶Èvoid MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr )
{//1.ʹÄÜʱÖÓ£ºRCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//2.ÅäÖÃDMAµÄÏà¹Ø¼Ä´æÆ÷£ºDMA_DeInit(DMA_CHx);   			//½«DMAµÄͨµÀ1¼Ä´æÆ÷ÖØÉèΪȱʡֵDMA1_LEN = cndtr;DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;		//ÍâÉè»ùµØÖ·DMA_InitStructure.DMA_MemoryBaseAddr = cmar;			//´æ·ÅDMAÊý¾ÝµÄµØÖ·DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//DMA´«Êä·½ÏòDMA_InitStructure.DMA_BufferSize = cndtr;		//Ò»´Î´«ÊäµÄÊý¾ÝÁ¿DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	//ÍâÉèµØÖ·ÊÇ·ñµÝÔöDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;			//Êý¾Ý´«ÊäʱÄÚ´æµØÖ·ÊÇ·ñµÝÔöDMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;	//ÍâÉèÊý¾Ý¿í¶ÈDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;			//ÄÚ´æÊý¾Ý¿í¶ÈDMA_InitStructure.DMA_Mode = DMA_Mode_Normal;						//DMA¹¤×÷ģʽDMA_InitStructure.DMA_Priority = DMA_Priority_Medium;				//DMAÓÅÏȼ¶DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;					//ÉèÖÃÊÇ·ñÊÇ´æ´¢Æ÷µ½´æ´¢Æ÷µÄ´«ÊäģʽDMA_Init(DMA_CHx,&DMA_InitStructure);					//½«ÉÏÊöÅäÖÃÐÅϢдÈëDMAµÄ¼Ä´æÆ÷ÖÐ//¿ªÆôDMA£ºDMA_Cmd(DMA_CHx,DISABLE);													//Ïȸ´Î»Ò»ÏÂDMA_SetCurrDataCounter(DMA1_Channel4,DMA1_LEN);		//ÉèÖÃDMAͨµÀµÄDMA»º´æ´óСDMA_Cmd(DMA_CHx,ENABLE);
}

(3) main.c:

#include "led.h"
#include "usart.h"
#include "delay.h"
#include "lcd.h"
#include "dma.h"
#include "key.h"const u8 TEXT_TO_SEND[]={"hello world,there are many good things,so we should hold on,hold on"};
#define TEXT_LENGTH sizeof(TEXT_TO_SEND) - 1				//-1ÊDz»°üº¬½áÊø·û
u8 SendBuff[(TEXT_LENGTH+2)*100];int main(void)
{float pro = 0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);LED_Init();LCD_Init();usart_init(9600);KEY_Init();USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);			//¿ªÆô´®¿ÚµÄDMA//DMA1ͨµÀ4,ÍâÉèΪ´®¿Ú1,´æ´¢Æ÷ΪSendBuff,³¤(TEXT_LENTH+2)*100MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)SendBuff,(TEXT_LENGTH+2)*100);GPIO_SetBits(GPIOA,GPIO_Pin_8);GPIO_ResetBits(GPIOD,GPIO_Pin_2);while(1){//printf("test\r\n");POINT_COLOR=RED;	  if(KEY_2){LCD_ShowString(60,150,200,16,16,"Start Transimit....");LCD_ShowString(30,40,200,24,24,"hello world");LCD_ShowString(60,170,200,16,16,"   %");//ÏÔʾ°Ù·ÖºÅwhile(1){if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET)//µÈ´ýͨµÀ4´«ÊäÍê³É{DMA_ClearFlag(DMA1_FLAG_TC4);//Çå³ýͨµÀ4´«ÊäÍê³É±êÖ¾break; }pro=DMA_GetCurrDataCounter(DMA1_Channel4);//µÃµ½µ±Ç°»¹Ê£Óà¶àÉÙ¸öÊý¾Ýpro=1-pro/((TEXT_LENGTH+2)*100);//µÃµ½°Ù·Ö±È	  pro*=100;      //À©´ó100±¶LCD_ShowNum(60,170,pro,3,16);	  }LCD_ShowNum(60,170,100,3,16);//ÏÔʾ100%	  LCD_ShowString(60,150,200,16,16,"Transimit Finished!");//Ìáʾ´«ËÍÍê³Édelay_ms(1000);}}
}

5.运行结果:

6.总结:

本文介绍了DMA使用方法,并实验了串口的DMA功能。使用DMA的基本步骤是:

(1)开启时钟,并初始化DMA

(2)配置初始化的结构体信息,调用函数进行初始化

(3)开启DMA数据传输,并使能外设的MDA功能。

本文中理论部分介绍较多,下一节会利用DNM和ADC来进行实验。


http://www.ppmy.cn/news/1451994.html

相关文章

Jenkins自动化搭建记录

每一份努力都是有一份期盼,每一份付出都是为了有更多的收获。 本文记录一次搭建Jenkins自动参数化打包APK的实现过程和碰到的问题,实现了在Windows和Mac系统下的自动化打包流程。 因为Jenkins的安装过程在网上的教程很多,这里就不在赘述。 …

华为试题之删除最少字符

题目描述 删除字符串中出现次数最少的字符 如果多个字符出现次数一样则都删除 输入描述 输入只包含小写字母 输出描述 输出删除后剩余的字符 若删除后字符串长度为0,则输出empty 我的思路是将字符串中的字符对应的数量和key统计后放到对应的字典中, 对字…

python项目==一个web项目,配置模板指定文件清洗规则,调用模板规则清洗文件

代码地址 一个小工具。 一个web项目,配置模板指定文件清洗规则,调用模板规则清洗文件 https://github.com/hebian1994/csv-transfer-all 技术栈: SQLite python flask vue3 elementplus 功能介绍: A WEB tool for cleaning…

OpenWRT有线桥接部署教程

前言 之前咱们讲到OpenWRT部署WAN实现PPPoE拨号上网和自动获取IP模式上网的办法: OpenWRT设置PPPoE拨号教程 OpenWRT设置自动获取IP,作为二级路由器 这一次,咱们尝试用OpenWRT有线桥接上一级路由器的教程。 可能有小伙伴敏锐地发现了&am…

阿里云API网关 产品的使用笔记

阿里云的产品虽多,还是一如既往的一用一个看不懂,该模块的文档依旧保持“稳定”发挥,磕了半天才全部跑通。 用阿里云API网关的原因是,在Agent中写插件调用API的时候,需要使用Https协议,又嫌搞备案、证书等事…

《Mask2Former》算法详解

文章地址:《Masked-attention Mask Transformer for Universal Image Segmentation》 代码地址:https://github.com/facebookresearch/Mask2Former 文章为发表在CVPR2022的一篇文章。从名字可以看出文章像提出一个可以统一处理各种分割任务(…

望仙谷听谿涛

望仙谿涛 近来不知为何,染上喝咖啡的恶习,称为“恶”,是因为要花钱,而且非得是那种口感好的。 网络流行“人生无解,来杯拿铁”。 大抵是因为咖啡再苦,也比不过生活吧,至少咖啡可以加糖&#xff…

数据库管理-第179期 分库分表vs分布式(20240430

数据库管理179期 2024-04-30 数据库管理-第179期 分库分表vs分布式(20240430)1 分库分表1.1 分库1.2 分表1.3 组合1.4 问题 2 分布式3 常见分布式数据库4 期望总结 数据库管理-第179期 分库分表vs分布式(20240430) 作者&#xff1…

C++ 函数与指针

函数内部数据是地址需要传递给调用函数,返回的当然是指针了!当然,这个返回地址也可以通过函数参数返回! 函数的参数是指针可以输出函数多个结果,返回值本身就是返回数据,什么时候需要返回指针呢&#xff1f…

WebSocket 的封装

websocket 具体内容参考了 原文 import {ref, onUnmounted} from vue; import dayjs from "dayjs";class Socket {url;ws null;opts;reconnectAttempts 0;listeners {};heartbeatInterval null;constructor(url, opts {}) {this.url url;this.opts {// 心跳检…

Java image-processing 包依赖错误

错误的信息为: [ERROR] Failed to execute goal on project image-processing: Could not resolve dependencies for project com.ossez:image-processing:jar:0.0.2-SNAPSHOT: Failed to collect dependencies at org.openimaj:core-image:jar:1.3.10 -> org.op…

机器学习每周挑战——二手车车辆信息交易售价数据

这是数据集的截图 目录 背景描述 数据说明 车型对照: 燃料类型对照: 老规矩,第一步先导入用到的库 第二步,读入数据: 第三步,数据预处理 第四步:对数据的分析 第五步:模型建…

ES集群分布式查询原理

集群分布式查询 elasticsearch的查询分成两个阶段: scatter phase:分散阶段,coordinating node会把请求分发到每一个分片gather phase:聚集阶段,coordinating node汇总data node的搜索结果,并处理为最终结…

设计模式的原则与分类

一、设计模式的原则 1、单一职责原则 一个类只需要负责一种职责即可,一个类发生变化的原因,必然是所负责的职责发生变化 2、接口隔离原则 单一职责原则是接口隔离原则的基础,单一职责原则注重职责的划分,从职责角度进行类和接口…

使用docker创建rocketMQ主从结构,使用

1、 创建目录 mkdir -p /docker/rocketmq/logs/nameserver-a mkdir -p /docker/rocketmq/logs/nameserver-b mkdir -p /docker/rocketmq/logs/broker-a mkdir -p /docker/rocketmq/logs/broker-b mkdir -p /docker/rocketmq/store/broker-a mkdir -p /docker/rocketmq/store/b…

【数据结构与算法】力扣 347. 前 K 个高频元素

题目描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2]示例 2: 输入: nums [1], k 1 输出: [1]提示&#xff1a; 1 < nums.length < …

KIE关键信息抽取——SDMG-R

https://arxiv.org/pdf/2103.14470https://arxiv.org/pdf/2103.14470 1.概述 背景:传统的关键信息提取方法依赖于模板匹配,这使它们难以泛化到未见过的模板,且对文本识别错误不够鲁棒。SDMG-R方法:提出一种端到端的双模态图推理方法,通过构建双模态图(视觉和文本特征),…

多级留言/评论的功能实现——SpringBoot3后端篇

目录 功能描述数据库表设计后端接口设计实体类entity 完整实体类dto 封装请求数据dto 封装分页请求数据vo 请求返回数据 Controller控制层Service层接口实现类 Mapper层Mybatis 操作数据库 补充&#xff1a;返回的数据结构自动创建实体类 最近毕设做完了&#xff0c;开始来梳理…

【CTF MISC】XCTF GFSJ0512 give_you_flag Writeup(图像处理+QR Code识别)

give_you_flag 菜狗找到了文件中的彩蛋很开心&#xff0c;给菜猫发了个表情包 解法 图片的最后一帧好像闪过了什么东西。 用 Photoshop 打开&#xff0c;检查时间轴。 找到一张二维码&#xff0c;但是缺了三个角&#xff08;定位图案&#xff09;&#xff0c;无法识别。 找一…

《QT实用小工具·四十九》QT开发的轮播图

1、概述 源码放在文章末尾 该项目实现了界面轮播图的效果&#xff0c;包含如下特点&#xff1a; 左右轮播 鼠标悬浮切换&#xff0c;无需点击 自动定时轮播 自动裁剪和缩放不同尺寸图片 任意添加、插入、删除 单击事件&#xff0c;支持索引和自定义文本 界面美观&#xff0c;圆…