STM32数据搬运工-DMA
STM32-DMA工作原理
DMA的概念:
DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。
STM32F4-DMA功能框图分析
1.外设通道;2.数据流仲裁;3.数据FIFO;4.存储器端口;5.外设端口。
1-DMA外设通道:
STM32F4xx 系列资源丰富,具有两个 DMA 控制器,同时外设繁多,为实现正常传输,DMA需要通道选择控制。每个 DMA控制器具有 8个数据流,每个数据流对应 8个外设请求。外设通道选择要解决的主要问题是决定哪一个外设作为该数据流的源地址或者目标地址。
(注: DMA控制器会通过 DMA数据流 x 配置寄存器 DMA_SxCR的CHSEL[2:0]位选择对应的通道作为该数据流的目标外设。)
2-数据流仲裁
一个 DMA控制器对应 8个数据流,数据流包含要传输数据的源地址、目标地址、数据长度等等信息。如果我们需要同时使用同一个 DMA 控制器(DMA1 或 DMA2)多个外设请求时,那必然需要同时使用多个数据流,那究竟哪一个数据流具有优先传输的权利呢?这就需要仲裁器来管理判断了。
数据流传输优先级配置:
1.配置 DMA_SxCR寄存器 PL[1:0]位,可以设置为非常高、高、中和低四个级别;
2.如果两个或以上数据流软件设置优先级一样,则他们优先级取决于数据流编号,编号越低越具有优先权。
3-数据FIFO
每个数据流都有一个独立的 4 字 FIFO(先进先出存储器缓冲区)。 DMA传输具有 FIFO模式和直接模式。
直接模式: 每个 DMA 请求会立即启动对存储器的传输。当在直接模式(禁止 FIFO)下将 DMA请求配置为以存储器到外设模式传输数据时,DMA 仅会将一个数据从存储器预加载到内部 FIFO,从而确保一旦外设触发 DMA 请求时则立即传输数据。
FIFO模式: 可通过控制寄存器 DMA_SxFCR 的 FTH[1:0]位来设置FIFO 阈值级别为 FIFO 大小的 1/4、1/2 或 3/4。如果数据存储量达到阈值级别时,FIFO 内容将传输到目标中。
5-存储器端口和外设端口
DMA 控制器提供两个 AHB 主端口:AHB 存储器端口 (用于连接存储器)和 AHB 外设端口(用于连接外设)。
但是,要执行存储器到存储器的传输,AHB 外设端口 必须也能访问存储器。
所以 DMA1 不能实现存储器到存储器传输。
STM32F4-DMA传输
DMA传输模式
DMA1 只有外设到存储器和存储器到外设两种模式,DMA2 除前面两种外还支持存储器到存储器的传输模式。模式选择可以通过 DMA_SxCR 寄存器的 DIR[1:0]位控制。
DMA传输的源、目的、长度
DMA_SxPAR寄存器:设置外设寄存器地址
DMA_SxM0AR寄存器:设置存储器地址
DMA_SxCR 寄存器 :DIR[1:0]位配置数据的传输方向
DMA_CNDTRx 寄存器:写入需要传输的数据量, (0 到 65535)
DMA_SxCR 寄存器中的 PSIZE 和 MSIZE 位:设置源和目的的数据宽度,两边的位宽尽量保持一致。
DMA增量设置
根据设置 DMA_SxCR 寄存器中 PINC 和 MINC 位的状态,外设和存储器指针在每次传输后可以自动向后递增或保持常量。
当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值,增量值取决与所选的数据宽度为 1 、 2 或 4 。
DMA循环模式
循环模式用于处理循环缓冲区和连续的数据传输 ( 如 ADC 的扫描模式 ) 。可以使用 DMA_SxCR寄存器中的 CIRC 位使能此特性。
当启动了循环模式,一组的数据传输完成时,计数寄存器将会自动地被恢复成配置该通道时设置的初值, DMA 操作将会继续进行。
DMA单次传输和突发传输
DMA传输类型有单次(Single)传输和突发(Burst)传输。DMA 控制器可以产生单次传输或 4 个、8 个和 16 个节拍的增量突发传输。
突发大小通过软件针对两个 AHB 端口独立配置,配置时使用 DMA_SxCR 寄存器中的MBURST[1:0] 和 PBURST[1:0] 位。
为确保数据一致性,形成突发的每一组传输都不可分割:在突发传输序列期间,AHB 传输会锁定,并且 AHB 总线矩阵的仲裁器不解除对 DMA 主总线的授权。
STM32F4-DMA中断
对于每个 DMA 数据流,可在发生以下事件时产生中断:
● 达到半传输
● 传输完成
● 传输错误
● FIFO 错误(上溢、下溢或 FIFO 级别错误)
● 直接模式错误
(注:这些标志位都在中断状态寄存器DMA_xISR中设置)
ADC_DMA多路采集实例
CubeMX参数配置
首先要配置ADC,参考另一篇笔记:STM32学习笔记—ADC原理与实验,使用ADC1的两个通道采集电位器的电压和STM32芯片内部温度,具体这里不再重复介绍ADC相关参数设置。
配置好ADC后,DMA设置如上图所示:
**首先: **add—>DMARequest(DAM请求)选择ADC1,Stresm(数据流)参考芯片手册可知ADC1可选DMA2的数据流0和4,Direction(方向):外设(ADC)到内存;Priority(优先级):这里选择低优先级即可。
Mode: 可选正常和循环模式,这里选择正常模式;
IncrementAddress: 这里模式将内存设置为增量模式;
Use Fifo: 不使用;
Data Width: 数据位宽默认值Half Word(16位)。
此外,还需要打开中断,DMA以中断方式传输数据,中断是默认打开的,这里只将优先级改低了一些,避免与系统中断冲突。
实验相关程序设计
先定义一个全局数组用来接收ADC采集的数据
uint16_t adc_value[2];
之后主函数中在while循环里反复延时1秒调用HAL_ADC_Start_DMA函数(因为ADC没有设置连续转换),uint32_t *pData:用于接收采集ADC数据的数组;uint32_t Length:数据量(这里采集两个ADC数据所以是2)
while (1)
{
//HAL_ADC_Start_DMA(ADC_HandleTypeDef *hadc, uint32_t *pData, uint32_t Length)
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_value, 2);
HAL_Delay(1000);
}
在中断函数中通过串口打印数据
extern uint16_t adc_value[2];
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
if(hadc->Instance == ADC1)
{
printf("adc_value[0] = %d, adc_value[1] = %d\n", adc_value[0], adc_value[1]);
}
}
标签:DMA,存储器,传输,ADC,数据流,原理,搬运工,外设
From: https://blog.csdn.net/weixin_51824176/article/details/145038382