首页 > 其他分享 >玩转STM32-直接存储器DMA(详细-慢工出细活)

玩转STM32-直接存储器DMA(详细-慢工出细活)

时间:2024-05-24 19:58:37浏览次数:27  
标签:慢工 DMA 总线 STM32 传输 寄存器 外设 通道

文章目录

一、DMA介绍

1.1 DMA简介

DMA用来提供外设与外设之间、外设与存储器之间、存储器与存储器之间的高速数据传输,无需CPU干预,数据可以通过DMA快速传输,节省CPU的资源。
在实现DMA传输时,由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移的问题,即DMA传输前,CPU把总线控制权交给DMA控制器,在结束DMA传输后,DMA控制器立即把总线控制权交回CPU。
一个完整的DMA传输过程包括DMA请求、DMA响应、DMA传输、DMA结束等4个步骤。
(1)DMA请求:CPU对DMA控制器初始化,并向IO接口发出操作命令,IO接口提出DMA请求。
(2)DMA响应:DMA控制器对DMA请求判别优先级及屏蔽,向总线裁决逻辑提出总线请求。当CPU执行完当前总线周期即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示DMA已经响应,通过DMA控制器通知IO接口开始DMA传输。
(3)DMA传输:DMA控制器获得总线控制权后,CPU即刻挂起或只执行内部操作,由DMA控制器输出读写命令,直接控制RAM与IO接口进行DMA传输。在DMA控制器的控制下,CPU只要提供传送数据的起始位置和数据长度,然后存储器和外设之间直接进行数据传输,CPU不参与传送过程。
(4)DMA结束:当完成规定的成批数据传送后,DMA控制器释放总线控制权,并向IO接口发出结束信号。当IO接口收到结束信号后,一方面停止IO设备的工作,另一方面向CPU提出中断请求,CPU响应中断,执行一段检查本次DMA传输操作正确性的代码。最后,带着本次操作结果及状态继续执行原来程序。

1.2 DMA结构

STM32最多拥有两个DMA控制器,DMA1控制器拥有7个独立的可配置通道,DMA2有5个独立的可配置通道,每个通道用来管理来自一个或多个外设对存储器访问的请求。
DMA是AHB总线上的设备,它有2个AHB端口:一个是从端口,用于配置DMA;一个是主端口,用于设备间数据传输。两个AHB/APB桥在AHB和两个APB总线间提供同步连接。APB1操作速度限于36MHz,APB2操作速度限于72MHz。STM32F103的DMA结构图如下所示:
来自STM32F103手册
STM32的Cortex-M3核心和DMA控制器通过总线矩阵连接到Flash控制总线、SRAM总线和AHB总线,进而通过AHB总线连接到APB总线服务外设。
总线矩阵有两个主要特征:循环优先调度、多层结构和总线挪用。

  1. 循环优先调度
    NVIC和Cortex-M3处理器实现了高性能低延时中断调度。所有的Cortex-M3指令即可以在单周期内执行,也可以在总线周期上被中断。循环优先级调度能够确保CPU在必要时每两个总线周期就去访问其他总线。
  2. 多层结构和总线挪用
    多层结构允许两个主设备并行执行数据传输。使用总线挪用存取机制,CPU访问和DMA通过APB总线存取外设可以并行工作。DMA总线挪用机制使得总线利用效率更高。

DMA功能的是通过操作两类寄存器实现的:
一类是具有DMA功能的相关外设寄存器,主要来自外设开启DMA功能,例如在通用定时器中的DMA/中断使能寄存器、DMA控制寄存器和连续式的DMA地址寄存器。
另一类是DMA相关寄存器,用来设置DMA的具体工作方式,DMA相关寄存器包括DMA中断状态寄存器(DMA_ISR)、DMA中断标志清除寄存器(DMA_IFCR)等。

二、DMA相关寄存器(了解)

  1. DMA中断状态寄存器——DMA_ISR
    该寄存器保存着DMA中断的状态。
    在这里插入图片描述
    在这里插入图片描述

  2. DMA中断标志清除寄存器——DMA_IFCR
    该寄存器用来清除DMA中断标志。
    在这里插入图片描述

  3. DMA通道x配置寄存器——DMA_CCRx
    该寄存器用来配置DMA工作模式。
    在这里插入图片描述
    在这里插入图片描述

  4. DMA通道x传输数量寄存器——DMA_CNDTRx
    该寄存器用来配置DMA传输数据量。
    在这里插入图片描述

  5. DMA通道x外设地址寄存器——DMA_CPARx
    该寄存器用来配置DMA通道外设地址。
    在这里插入图片描述

  6. DMA通道x存储器地址寄存器——DMA_CMARx
    该寄存器用来配置DMA通道存储器地址。
    在这里插入图片描述

三、DMA的工作过程(掌握)

1. DMA传送
当发生一个事件后,外设发送一个时间请求信号到DMA控制器,DMA控制器根据通道的优先权来处理请求。当DMA控制器开始访问外设时,DMA控制器首先向外设发送一个应答信号;外设得到应答信号后立即撤销请求;外设撤销请求后,DMA控制器同时撤销应答信号。如果载磁发生请求,外设则可以启动下次传送。每个DMA传送由以下3个操作组成;
(1) 从外设数据寄存器或由DMA_CMARx寄存器指定地址的存储单元执行加载操作。(取数据)
(2)存储数据到外设数据寄存器或存数据到DMA_CMARx寄存器指定地址的存储单元。(存储)
(3)执行依次DMA_CNDTRx寄存器的递减操作,该寄存器内容为完成的传输内容数量。
2. 仲裁器
仲裁器根据通道请求的优先级来启动外设/存储器的访问。优先权管理分2个阶段:
(1)软件:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级: 最高优先级、高优先级 、中等优先级 、低优先级。
(2)硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。举个例子,通道2优先于通道4。
3. DMA通道
每个通道都可以在有固定地址的外设寄存器和存储器地址之间执行DMA传输。DMA传输的数据量是可编程的,最大达到65535。包含要传输的数据项数量的寄存器,在每次传输后递减。
(1)传输的数据量
外设和存储器的传输数据量可以通过DMA_CCRx寄存器中的PSIZE和MSIZE位编程。
(2)指针自增
通过设置DMA_CCRx寄存器中的PINC和MINC标志位,外设和存储器的指针在每次传输后可以有选择地完成自动增量。当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值,增量值取决与所选的数据宽度为1、2或4。第一个传输的地址是存放在DMA_CPARx /DMA_CMARx寄存器中地址。
(3)通道配置过程
下面是配置DMA通道x的过程(x代表通道号):
①在DMA_CPARx寄存器中设置外设寄存器的地址。发生外设数据传输请求时,这个地址将是数据传输的源或目标。
② 在DMA_CMARx寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数据将从这个地址读出或写入这个地址。
③ 在DMA_CNDTRx寄存器中设置要传输的数据量。在每个数据传输后,这个数值递减。
④ 在DMA_CCRx寄存器的PL[1:0]位中设置通道的优先级。
⑤ 在DMA_CCRx寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、外设和存储器的数据宽度、传输一半产生中断或传输完成产生中断。
⑥ 设置DMA_CCRx寄存器的ENABLE位,启动该通道。
⑦一旦启动了DMA通道,它既可响应连到该通道上的外设的DMA请求。
⑧当传输一半的数据后,半传输标志(HTIF)被置1,当设置了允许半传输中断位(HTIE)时,将产生一个中断请求。在数据传输结束后,传输完成标志(TCIF)被置1,当设置了允许传输完成中断位(TCIE)时,将产生一个中断请求。
(4)循环模式
循环模式用于处理循环缓冲区和连续的数据传输(如ADC的扫描模式)。在DMA_CCRx寄存器中的CIRC位用于开启这一功能。当启动了循环模式,数据传输的数目变为0时,将会自动地被恢复成配置通道时设置的初值,DMA操作将会继续进行。
(5)存储器到存储器模式
DMA通道的操作可以在没有外设请求的情况下进行,这种操作就是存储器到存储器模式。 当设置了DMA_CCRx寄存器中的MEM2MEM位之后,在软件设置了DMA_CCRx寄存器中的EN位启动DMA通道时,DMA传输将马上开始。当DMA_CNDTRx寄存器变为0时,DMA传输结束。存储器到存储器模式不能与循环模式同时使用。
4. 错误管理
读写一个保留的地址区域,将会产生DMA传输错误。当在DMA读写操作时发生DMA传输错误时,硬件会自动地清除发生错误的通道所对应的通道配置寄存器(DMA_CCRx)的EN位,该通道操作被停止。此时,在DMA_IFR寄存器中对应该通道的传输错误中断标志位(TEIF)将被置位,如果在DMA_CCRx寄存器中设置了传输错误中断允许位,则将产生中断。
5. DMA请求映射
从外设(TIMx[x=1、2、3、4]、ADC1、SPI1、SPI/I2S2、I2Cx[x=1、2]和USARTx[x=1、2、3])产生的7个请求,通过逻辑或输入到DMA1控制器,这意味着同时只能有一个请求有效。
在这里插入图片描述

四、DMA应用实例

4.1 DMA常用库函数

函数名称功能
DMA_DeInit将DMA的通道x寄存器重设为缺省值
DMA_Init根据DMA_InitStruct中指定的参数初始化DMA通道x寄存器
DMA_StructInit把DMA_InitStruct中的每一个参数按缺省值填入
DMA_Cmd使能或使能指定的通道x
DMA_ITConfig使能或是能指定的通道x中断
DMA_GetCurrDataCounte返回当前DMA通道x剩余的待传输数据数目
DMA_GetFlagStatus检查指定的DMA通道x标志位设置与否
DMA_ClearFlag清除DMA通道x待处理标志位
DMA_GetITStatus检查指定的DMA通道x中断发生与否
DMA_ClearITPendingBit清除DMA通道x中断待处理标志位

4.2 实例程序

  1. 实例介绍: 利用DMA将Flash中的32位数据缓冲区的内容传送到RAM中所定义的缓冲区内。传输完成后产生传输完成中断,最后将源缓冲区中数据与目的缓冲区中数据对比来检测所有数据是否传输正确。
  2. 实例
    (1)DMA初始化
void DMADriver_Init(void)
{
		DMA_InitTypeDef DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	// 外设基地址, 源地址
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SRC_Const_Buffer;
	// RAM基地址, 目的地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DST_Buffer;
	// 传输方向,外设为源地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	// 缓冲区大小, 0~65536
	DMA_InitStructure.DMA_BufferSize = BufferSize;
	// 外设地址自增1
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
	// RAM地址自增1
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	// 外设数据宽度
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;  // 字,4个字节
	// RAM数据宽度
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
	// 传输模式 一次传送
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	// 优先级
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	//内存到内存传输
	DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);
	// 传输完成中断
	DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);
	// 开始传输前数据量
	CurrDataCounterBegin = DMA_GetCurrDataCounter(DMA1_Channel1);
	// 开启DMA
	DMA_Cmd(DMA1_Channel1,ENABLE);
}

(2)中断处理函数

void DMA1_Channel1_IRQHandler(void)
{
	// 检测DMA1通道1传输完成中断
	if(DMA_GetITStatus(DMA1_IT_TC1))
	{
		// 传输完成后得到当前计数
		CurrDataCounterEnd = DMA_GetCurrDataCounter(DMA1_Channel1);
		// 清除标志位
		DMA_ClearITPendingBit(DMA1_IT_TC1);
	}
}

(3)串口初始化在前几章有写过,这里就不介绍了

// 定义存储大小
#define BufferSize   32

uint32_t CurrDataCounterBegin = 0;
uint32_t CurrDataCounterEnd = 0x01;
const uint32_t SRC_Const_Buffer[BufferSize] = {
0x01022231,0x19234012,0x02348192,0x19384910,
0x01022231,0x19234012,0x02348192,0x19384910,
0x01022231,0x19234012,0x02348192,0x19384910,
0x01022231,0x19234012,0x02348192,0x19384910,
0x01022231,0x19234012,0x02348192,0x19384910,
0x01022231,0x19234012,0x02348192,0x19384910,
0x01022231,0x19234012,0x02348192,0x19384910,
0x01022231,0x19234012,0x02348192,0x19384910};
uint32_t DST_Buffer[BufferSize];


void main()
{
	UsartDriver_Init();
	DMADriver_Init();
	Delay_ms(10);
	
	while(CurrDataCounterEnd  != 0);
	printf("Complete transfer!\r\n")
	
}

标签:慢工,DMA,总线,STM32,传输,寄存器,外设,通道
From: https://blog.csdn.net/2301_81355360/article/details/139143070

相关文章

  • STM32读取GPIO状态的代码优化
    最近看到新的读取GPIO状态引脚状态的代码伪代码如图:优势:读取消抖前第一次的GPIO状态,与引脚先前状态进行对比;如果电平状态一致则跳过延时消抖的流程,可以节约时间,减少裸机工作循环一轮所用时间​staticu8ReadIOPort(GPIO_TypeDef*GPIOx,u16PortNum,u8prePortStatus){......
  • 基于STM32的电子秤毕业论文
    撰写基于STM32的电子秤毕业论文,你需要围绕系统设计、实现、测试和结论几个核心部分展开。下面是一个基本的大纲和每个部分的概览,帮助你组织和撰写论文。论文标题:基于STM32的高精度电子秤设计与实现摘要:简述电子秤设计的背景、目的、主要技术特点、实现的功能以及研究的重......
  • 基于STM32的环境质量监测系统
    基于STM32的环境质量监测系统是一个集成了微控制器技术、传感器技术、数据通信和人机交互界面的综合应用项目。以下是一个简要的论文提纲,旨在指导你如何撰写关于这一主题的研究或设计报告。**标题:**基于STM32的智能环境质量监测系统设计与实现**摘要:**简要介绍研究背景、系......
  • 基于STM32的环境检测温湿度大气参数上传阿里云的论文
    基于STM32的环境检测温湿度大气参数上传阿里云的论文可以从多个方面来展开,以下是一个论文的概要结构及其内容的建议:一、引言介绍环境检测在现代化生活中的重要性和应用场景。阐述STM32微控制器在环境检测系统中的优势。简述阿里云物联网平台的特点和其在环境检测数据管理中的......
  • STM32在不支持5V输入IO口输入5V电平带来的奇怪现象
    今天在使用stm32单片机的时候,发现了一个奇怪的现象,调试器经常识别不到单片机,给单片机重新上电后有时就正常,但重新下载又无法识别。刚开始以为是调试器坏了,于是更换了调试器,但没有换调试器的杜邦线,还是相同的问题,因此把调试器故障排除了。然后又尝试了降低SW频率、更换调试线,问......
  • CubeMX离线安装stm32f1固件包
    一.打开CubeMX软件点击Help选择Manageembededsoftwarepackages二、找到STM32F1版本最新的固件包,点击install 三、登录账号 四、等待下载完成五、下载完成......
  • 「云渲染课堂」3dmax渲染影响时间的原因有哪些
    在3dsMax使用过程中经验丰富的用户普遍了解,渲染大型场景往往需要消耗更多的时间,尤其是在硬件配置相同的情况下。但有时候,我们可能会遇到一个反直觉的现象:在相同的硬件配置下,渲染小型场景所需的时间竟然超过了大型场景。这种现象背后的原因是多方面的,3dsMax渲染时间的几个关键因......
  • 「云渲染课堂」3dmax地砖材质参数怎么让画面更加真实?
    在3DMAX中,地砖材质的渲染需要细致的调整,因为不同材质的地砖在反射和折射参数上各不相同。为了使地砖材质更加逼真,以下简要说明了一些设置方法,希望对大家有所帮助!3dmax地砖材质参数如何设置1、打开材质编辑器,添加一个VRay标准材质并点击【确定】后选择对象。2.将材质赋予对象......
  • Android查看apk安装包的AndroidManifest.xml文件
    Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解`Android查看apk安装包的AndroidManifest.xml文件日期:2020-4-19阿珏折腾代码浏览:946次评论:5条起因上周在做安卓系统的厂家推送功......
  • 嵌入式Linux中的LED驱动控制(以野火STM32MP157开发板为例)
    在嵌入式Linux系统中,由于从硬件到软件都是自己定制的,所以很多时候需要对自己定义的设备编写驱动程序。本例就以野火STM32MP157开发板为例,讨论如何控制开发板上三个LED的亮灭。先来看一下LED部分的电路原理图,如下所示。从上图中可以看到,三个RGB颜色的二极管采用共阳接法,因此在......