文章目录
DMA简介
STM32最多有2个DMA控制器(DMA2仅存在大容量产品中)
DMA1有7个通道。DMA2有5个通道。
还有一个仲裁起来协调各个DMA请求的优先权。
原理图:
一、DMA配置过程
二、.DMA配置参数
1.DMA外设与通道对应图
每个通道都直接连接专用的硬件DMA请求,都支持软件触发。
参考寄存器手册
参考寄存器手册
2.优先级
仲裁器根据优先管理着通道的请求和启动外设/存储访问
优先级管理分两个方面:
-
软件:可通过DMA_CCRx寄存器配置每个通道的优先级,优先级分4个等级如下:
最高优先级 高优先级 中等优先级 低优先级
-
硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。举个例子,通道2优先于通道4
即:DMA 数据流请求之间的优先级可用软件编程(4 个级别:非常高、高、中、低),在软件优先级相同的情况下可以通过硬件决定优先级(例如,请求 0 的优先级高于请求 1)
3.DMA传输方向
(闪存)、(SRAM)、(外设的SRAM)、(APB1 APB2和AHB外设)均可作为访问的源和目标
DMA_CCRx寄存器:配置数据的传输方向
如果是存储器到存储器模式,需要配置DMA_CCRx的MEM2MEM位
DMA1传输模式:
● 外设到存储器的传输
● 存储器到外设的传输
DMA2传输模式:
● 外设到存储器的传输
● 存储器到外设的传输
● 存储器到存储器的传
4.外设、存储器数据宽度与对齐
DMA_CCRx寄存器中的PSIZE和MSIZE位:
设置源和目的的数据宽度,两边的位宽尽量保持一致。要不然就会出问题,
例如:ADC采用的12位,2个字节,因此此处数据设置应该也是2个字节
5.双方地址是否增量
DMA_CPARx寄存器:设置外设寄存器地址
DMA_CMARx寄存器:设置存储器地址
通过设置DMA_CCRx寄存器中的PINC和MINC标志位,外设和存储器的指针在每次传输后可以有选择的完成自动增量,当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值,增量值取决于所选的数据宽度1个数据宽度、2个数据宽度或4个数据宽度 (字节、半字、全字)。
例:ADC占12位,ADC->DR寄存器地址不变,所以存储器(存储数组)的增量应该设置为2。(32位的地址,需要16位来存储)
6.DMA工作模式
DMA-CCRx寄存器–CIRC位设置是否循环
-
正常缓存模式(DMA_Mode_Normal),在该模式下,每次使能仅进行一轮传输,一旦计数器的值减至0时,DMA传输会停止。想要再次传输,必须重新设置计数器CNDTR的数值;
-
循环工作模式(DMA_Mode_Circular),主要处理连续的数据传输,每进行一轮传输,计数器会被自动恢复为初始值,同时DMA传输进入下一轮,非常适合同ADC多通道(扫描)模式一起工作。
7.数据传输量
DMA_CNDTRx寄存器:写入需要传输的数据量,(0到65535)
例:.DMA_BufferSize=200;
8.结构体配置
typedef struct
{
uint32_t DMA_Channel; //DMA数据流对应的通道
uint32_t DMA_PeripheralBaseAddr;//外设基地址
uint32_t DMA_Memory0BaseAddr;//存储器基地址
uint32_t DMA_DIR;//传输方向,是存储器到外设还是存储器到存储器
uint32_t DMA_BufferSize;//一次传输的数据量大小
uint32_t DMA_PeripheralInc;//外设地址是否增量
uint32_t DMA_MemoryInc;//存储器地址是否增量
uint32_t DMA_PeripheralDataSize;//外设传输单位,字节还是字还是半字等等
uint32_t DMA_MemoryDataSize;//存储器传输单位,节拍定义
uint32_t DMA_Mode;//是否循环采集
uint32_t DMA_Priority;//DMA优先级别,是较高,高,中还是低
uint32_t DMA_FIFOMode;//FIFO模式是否开启
uint32_t DMA_FIFOThreshold; //FIFO模式阈值
uint32_t DMA_MemoryBurst;//用来配置存储器是几个单位数据的突发传输
uint32_t DMA_PeripheralBurst;//用来配置外设是几个单位数据的突发传输
}DMA_InitTypeDef;
实例:
void dma_init()
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
/*DMA配置*/
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;//串口数据寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendBuff; //内存地址(要传输的变量的指针)
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //方向(从内存到外设)
DMA_InitStructure.DMA_BufferSize = 500; //传输内容的大小
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_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止内存到内存的传输
DMA_Init(DMA1_Channel4, &DMA_InitStructure); //配置DMA1的4通道
DMA_Cmd(DMA1_Channel4,ENABLE);
DMA_SetCurrDataCounter(DMA_CH4,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);//配置DMA发送完成后产生中断
}
三、DMA中断
每个通道都有3个事件标志(DMA 半传输,DMA传输完成和DMA传输出错),
这3个事件标志逻辑或成为一个单独的中断请求。
在大容量产品中,DMA2通道4和通道5的中断被映射在一个中断向量上,
在互联网产品中,DMA2通道4和通道5的中断分别有独立的中断向量,
所有其他的DMA通道都有自己的中断向量。
中断服务函数:清除中断标志位
void DMA1_Channel4_IRQHandler(void)
{
if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==SET)
{
DMA_ClearFlag(DMA1_FLAG_TC4);
}
}
DMA配置流程
使能DMA时钟
RCC_AHBPeriphClockCmd();
初始化DMA通道
DMA_Init();
ADC模块使能DMA传输:
ADC_DMACmd();
使能DMA1通道,启动传输。
DMA_Cmd();