STM32复习笔记 | DMA
文章目录
DMA
DMA的概念&作用
DMA(Direct Memory Access,直接内存访问) .
DMA既可以指内存和外设直接存取数据这种内存访问的计算机技术,又可以指实现该技术的硬件模块(对于通用计算机PC而言,DMA控制逻辑由CPU和DMA控制接口逻辑芯片共同组成,嵌入式系统的DMA控制器内建在处理器芯片内部,一般称为 DMA控制器,DMAC)。
🤔为啥用到DMA?
在无须CPU干预的情况下,提供外设与存储器之间或者存储器与存储器之间的高速数据传输. 既节省了CPU的资源,又提高数据传输的快速性,因为不需要通过代码实施数据传输过程。👍
如何作用
只要CPU将DMA初始化后,内存和外设的数据传输只需要进过DMA就可以很方便进行(绕开CPU)
STM32 & DMA
例如需要传送100个8位的数据到外设,如果用CPU来做一般是:
for(i=0;i<100;i++) { 数据转移 }
这样CPU要履行100次for循环,如果用DMA方式只要把数据的个数和数据的起始地址给DMA,接着CPU可以执行其他操作了。🤘
STM32单片机可有两个DMA控制器,共12个通道,其中DMA1有7个通道,DMA2有5个通道。 每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。DMA控制器中还有一个仲裁器,专门协调各个DMA请求的优先权。
STM32 (F1) DMA特性🐾
DMA2仅存在于大容量产品和互联型产品
- 每个通道都支持软件触发,可通过软件配置
- 在同一个DMA模块上,多个请求的优先权可以通过软件编程设置
- 共有四级:很高、高、中等和低
- 优先权设置相等时由硬件决定(较低编号的通道比较高编号的通道有较高的优先权,比如通道2优先于通道4)
在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2控制器的优先级
-
独立数据源(取数据的地方)和目标数据区(放数据的地方)的传输宽度有字节(8位)、半字(16位)、全字(32位,字,不是字节)三种可选
- 源和目标地址必须按数据传输宽度对齐
- 支持循环的缓冲器管理—传输完数据又从数据头传输,可反复进行(
参考手册10.3.3
)
-
每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错)
-
这3个事件标志逻辑相“或”成为一个单独的中断请求,即任何一个事件均可触发中断
事件标志位是只读的,使能控制位是可读可写的(所以就是中断之后,只有使能了才能触发中断(?))
-
-
DMA传输的数据量是可编程的,最小为1,最大达到65535。包含要传输的数据项数量的寄存器,在每次传输后递减。
DMA_CCRx
STM32的DMA原理及其配置
STM32的DMA原理
- 在发生一个事件后,外设发送一个请求信号到DMA控制器
- DMA控制器根据通道的优先权处理请求
- 当DMA控制器开始访问外设的时候,DMA 控制器立即发送给外设一个应答信号
- 当外设释放了这个请求,DMA控制器同时撤销应答信号
可以在DMA传输过半、传输完成和传输错误时产生中断,每个DMA传送由3个操作组成:
- 从外设数据寄存器或者从DMA_CMARx寄存器指定地址的存储器单元执行加载操作
- 存数据到外设数据寄存器或者存数据到DMA_CMARx寄存器指定地址的存储器单元
- 执行一次DMA_CNDTRx寄存器的递减操作.该寄存器包含未完成的操作数目
STM32之DMA的配置步骤
进行DMA配置前,在RCC设置中使能DMA时钟
STM32的DMA控制器挂在AHB总线上
配置DMA通道x的过程(x代表通道号)主要包括6个方面:
🤔注意:
DMA与外设建立连接
要使DMA与外设建立有效连接,这不是DMA自身的事情,是各个外设的事情,每个外设都有一个xxx_DMACmd(XXXx,Enable )函数,如果使 DMA与ADC建立有效联系,就使用以下函数:
ADC_DMACmd(ADC1,Enable)
DMA三种工作模式的选用
DMA有三种工作模式:循环模式、非循环模式、存储器到存储器模式
- 非循环模式—DMA_Mode_Normal
- 即正常模式,当一次DMA数据传输完后,停止DMA传送。需要重组设置传送数量和启动后,才能进行下一次DMA数据传输。
- 循环模式—DMA_Mode_Circular
- 用于处理循环缓冲区和连续的数据传输(如ADC的扫描模式) 在DMA_CCRx寄存器中的“CIRC”位可开启这一功能。当启动了循环模式, 数据传输的数目变为0时,将会自动地被恢复成配置通道时设置的初值,DMA 操作将会继续进行.
- 存储器到存储器模式—DMA_M2M_Enable
- 存储器数据以DMA方式复制到另一地址存储
串口通信 | DMA实例
程序源码>>标准例程-HAL库函数版本>>实验17 DMA实验>>HARDWARE>>dma.c
void MYDMA_Config(DMA_Channel_TypeDef *chx) { __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_LINKDMA(&UART1_Handler,hdmatx,UART1TxDMA_Handler); UART1TxDMA_Handler.Instance=chx; UART1TxDMA_Handler.Init.Direction=DMA_MEMORY_TO_PERIPH; UART1TxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE; UART1TxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE; UART1TxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE; UART1TxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE; UART1TxDMA_Handler.Init.Mode=DMA_NORMAL; UART1TxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM; HAL_DMA_DeInit(&UART1TxDMA_Handler); HAL_DMA_Init(&UART1TxDMA_Handler); }
阅读并修改以上代码配置,实现SPI1 DMA接收: 1. chx的值应该为什么?请直接在代码上修改; 2. 修改代码,实现DMA传输为循环模式、优先级为高。
-
chx的值需要设为用于SPI1接收的正确DMA通道。通常在STM32中,SPI1使用的DMA通道为DMA1_Channel2或DMA1_Channel3,具体取决于您的STM32变体和DMA通道映射。本例中我们假设使用的是DMA1_Channel2,请根据您的硬件调整。
-
修改DMA配置为循环模式,并将优先级设置为高。
以下是修改后的代码:
void MYDMA_Config(DMA_Channel_TypeDef *chx)
{
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_LINKDMA(&UART1_Handler, hdmatx, UART1TxDMA_Handler);
// 将chx设置为SPI1接收对应的DMA通道
UART1TxDMA_Handler.Instance = DMA1_Channel2; // 根据具体的硬件调整DMA通道
UART1TxDMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY; // 改为从外设到内存,接收数据
UART1TxDMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;
UART1TxDMA_Handler.Init.MemInc = DMA_MINC_ENABLE;
UART1TxDMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
UART1TxDMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
UART1TxDMA_Handler.Init.Mode = DMA_CIRCULAR; // 将模式设置为循环模式
UART1TxDMA_Handler.Init.Priority = DMA_PRIORITY_HIGH; // 设置优先级为高
HAL_DMA_DeInit(&UART1TxDMA_Handler);
HAL_DMA_Init(&UART1TxDMA_Handler);
}
修改说明:
- DMA通道:将
UART1TxDMA_Handler.Instance
设置为DMA1_Channel2
。 - 方向:将方向从
DMA_MEMORY_TO_PERIPH
改为DMA_PERIPH_TO_MEMORY
,以处理接收数据。 - 模式:将
UART1TxDMA_Handler.Init.Mode
设置为DMA_CIRCULAR
,以启用循环模式。 - 优先级:将
UART1TxDMA_Handler.Init.Priority
改为DMA_PRIORITY_HIGH
。
思考
DMA的作用是什么?为什么STM32中要加入DMA功能?
在配置STM32的DMA时,主要有哪几个步骤?
作者:ZHEN_021