一.DMA_InitTypeDef 初始化结构体
typedef struct
{
uint32_t DMA_Channel; //通道选择
uint32_t DMA_PeripheralBaseAddr;//外设地址
uint32_t DMA_Memory0BaseAddr; //存储器 0 地址
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; //优先级
uint32_t DMA_FIFOMode; //FIFO 模式
uint32_t DMA_FIFOThreshold; //FIFO 阈值
uint32_t DMA_MemoryBurst; //存储器突发传输
uint32_t DMA_PeripheralBurst; //外设突发传输
}DMA_InitTypeDef;
1、DMA_Channel:
DMA 请求通道选择,可选通道 0 至通道 7,每个外设对应固定的通道,具体设置值需要查表 DMA1 各个通道的请求映像 和表 DMA2 各个通道的请求映像 ;它设定 DMA_SxCR寄存器的 CHSEL[2:0] 位的值。
外设通道选择要解决的主要问题是决定哪一个外设作为该数据流的源地址或者目标地址。
DMA 请求映射情况参考表 DMA1 各个通道的请求映像 和表 DMA2 各个通道的请求映像 。
例如,我们使用模拟数字转换器 ADC3 规则采集 4 个输入通道的电压数据,查表 DMA2 各个通道的请求映像 可知使用通道 2。
补充:DMA数据流
一个数据流会对应着8个通道选择,1个DAM拥有8 个 DMA 控制器数据流。每个外设请求都占用一个数据流通道,相同外设请求可以占用不同数据流通道。比如 SPI3_RX请求,即 SPI3 数据发送请求,占用 DMA1 的数据流 0 的通道 0,因此当我们使用该请求时,我们需要在把DMA_S0CR 寄存器的 CHSEL[2:0] 设置为“000”,此时相同数据流的其他通道不被选择,处于不可用状态,比如此时不能使用数据流 0 的通道 1 即 I2C1_RX 请求等等。
查阅表 DMA1 各个通道的请求映像 可以发现 SPI3_RX 请求不仅仅在数据流 0 的通道 0,同时数据流 2 的通道 0 也是 SPI3_RX 请求,实际上其他外设基本上都有两个对应数据流通道,这两个数据流通道都是可选的,这样设计是尽可能提供多个数据流同时使用情况选择。
配置DMA的数据流函数就是DMA的初始化函数:
//DMA1_Stream0:为DMA1的数据流0
DMA_Init(DMA1_Stream0, &DMA_InitStructure); //初始化DMA数据流
2、DMA_PeripheralBaseAddr:
外设地址。
例如: ADC3 转化的规则通道数据保存在数据寄存器ADC_DR中,其地址为 ((uint32_t)ADC3+0x4C)。ADC3是个宏定义,0x4C是寄存器的偏移量,可查阅数据手册。
注意:不同的传输模式对应的地址稍微有点变化,DMA_PeripheralBaseAddr:此变量配置的为DMA_SxPAR(x 为 0~7) 寄存器的值,根据模式的不同,可以作为源地址或者目标地址。
3、DMA_Memory0BaseAddr:
存储器地址。内容与上一个一样。
4、DMA_DIR:
数据传输方向,就是上面常说的外设到存储器,存储器到外设,存储器到存储器。
5、DMA_BufferSize:
设定待传输数据数目,根据自己的需求来设置,当传输完我们设定的数目值DMA才停止传输。例如:ADC要采集4个通道数据,所以待传输数目为4。
6、DMA_PeripheralInc:
外设地址自动递增
如果配置为 DMA_PeripheralInc_Enable,使能外设地址自动递增功能,它设定 DMA_SxCR 寄存器的 PINC 位的值;一般外设都是只有一个数据寄存器,所以一般不会使能该位。例如: ADC3 的数据寄存器地址是固定并且只有一个所以不使能外设地址递增。
7、DMA_MemoryInc:
存储器地址自动递增
如果配置为 DMA_MemoryInc_Enable,使能存储器地址自动递增功能,它设定 DMA_SxCR 寄存器的 MINC 位的值;我们自定义的存储区一般都是存放多个数据的,所以使能存储器地址自动递增功能。我们之前已经定义了一个包含 4 个元素的数字用来存放数据,使能存储区地址递增功能,自动把每个通道数据存放到对应数组元素内。
8、DMA_PeripheralDataSize:
外设数据宽度,可选字节 (8 位)、半字 (16 位) 和字 (32 位),它设定DMA_SxCR 寄存器的 PSIZE[1:0] 位的值。
例如:ADC 数据寄存器只有低 16 位数据有效,使用半字数据宽度
9、DMA_MemoryDataSize:
存储器数据宽度,可选字节 (8 位)、半字 (16 位) 和字 (32 位),它设定DMA_SxCR 寄存器的 MSIZE[1:0] 位的值。
例如:保存 ADC 转换数据也要使用半字数据宽度,这跟我们定义的数组是相对应的。
10、DMA_Mode:
DMA 传输模式选择,可选正常模式或者循环模式,它设定 DMA_SxCR 寄存器的 CIRC 位的值。
例如:ADC 采集可以是持续循环进行的,所以使用循环传输模式。
11、DMA_Priority:
软件设置数据流的优先级,有 4 个可选优先级分别为非常高、高、中和低,它设定 DMA_SxCR 寄存器的 PL[1:0] 位的值。
DMA 优先级只有在多个 DMA 数据流同时使用时才有意义,这里我们设置为非常高优先级就可以了。
拓展:
( 仲裁器管理数据流方法分为两个阶段。
第一阶段属于软件阶段
,我们在配置数据流时可以通过寄存器设定它的优先级别,具体配置 DMA_SxCR 寄存器 PL[1:0] 位,可以设置为非常高、高、中和低四个级别。
第二阶段属于硬件阶段
,如果两个或以上数据流软件设置优先级一样,则他们优先级取决于数据流编号,编号越低越具有优先权,比如数据流 2 优先级高于数据流 3。 )
12、DMA_FIFOMode:
FIFO 模式使能,如果设置为 DMA_FIFOMode_Enable
表示使能 FIFO 模式功能;它设定 DMA_SxFCR 寄存器的 DMDIS 位。FIFO 用于在源数据传输到目标地址之前临时存放这些数据。可以通过 DMA 数据流 xFIFO 控制寄存器 DMA_SxFCR 的 FTH[1:0] 位来控制 FIFO 的阈值,分别为 1/4、 1/2、 3/4 和满。如果数据存储量达到阈值级别时, FIFO 内容将传输到目标中。
如果设置为 DMA_FIFOMode_Disable
表示使能直接模式功能,在直接模式下,如果 DMA 配置为存储器到外设传输数据时, DMA 会将一个数据从存储器预加载到内部 FIFO,从而确保一旦外设触发 DMA 请求时则立即传输数据。为了避免 FIFO 饱和,建议使用高优先级配置相应的数据流。
(在存储器到存储器模式配置下不能使用直接模式。)
例如: ADC 采集传输使用直接传输模式即可,不需要使用 FIFO 模式。
13、DMA_FIFOThreshold:
FIFO 阈值选择,可选 4 种状态分别为 FIFO 容量的 1/4、 1/2、 3/4 和满;它设定 DMA_SxFCR 寄存器的 FTH[1:0] 位。
DMA_FIFOMode 设置为 DMA_FIFOMode_Disable,那 DMA_FIFOThreshold 值无效。ADC 采集传输不使用 FIFO 模式,设置该值无效。
(FIFO 对于要求源地址和目标地址数据宽度不同时非常有用,比如源数据是源源不断的字节数据,而目标地址要求输出字宽度的数据,即在实现数据传输时同时把原来 4 个 8 位字节的数据拼凑成一个 32 位字数据。此时使用 FIFO 功能先把数据缓存起来,分别根据需要输出数据。)
14、DMA_MemoryBurst:
存储器突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式,它设定 DMA_SxCR 寄存器的 MBURST[1:0] 位的值。
例如:ADC 采集传输是直接模式,要求使用单次模式。
拓展:
突发传输就是用非常短时间结合非常高数据信号率传输数据,相对正常传输速度,突发传输就是在传输阶段把速度瞬间提高,实现高速传输,在数据传输完成后恢复正常速度,有点类似达到数据块“秒传”效果。为达到这个效果突发传输过程要占用 AHB 总线,保证要求每个数据项在传输过程不被分割,这样一次性把数据全部传输完才释放 AHB 总线;而单次传输时必须通过 AHB 的总线仲裁多次控制才传输完成。
15、DMA_PeripheralBurst:
外设突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式,它设定 DMA_SxCR 寄存器的 PBURST[1:0] 位的值。
例如:ADC 采集传输是直接模式,要求使用单次模式。
## 15、DMA_PeripheralBurst:
二.DMA相关库函数
/* Optional Configuration functions ***************** 可选配功能**************************/
void DMA_PeriphIncOffsetSizeConfig(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t DMA_Pincos);
//配置外设增量偏移量
DMA_PINCOS_Psize :用于计算外设地址的偏移量与 PSIZE 相关,
DMA_PINCOS_WordAligned:用于计算外设地址的偏移量固定为 4( 32 位对齐)。
void DMA_FlowControllerConfig(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t DMA_FlowCtrl);
//配置外设流控制器
DMA_FlowCtrl_Memory:DMA 是流控制器
DMA_FlowCtrl_Peripheral:外设是流控制器
/* Data Counter functions ******************* 数据计数器功能**********************************/
void DMA_SetCurrDataCounter(DMA_Stream_TypeDef* DMAy_Streamx, uint16_t Counter);
//设置DMA 数据流 x 要传输的数据项数目
uint16_t DMA_GetCurrDataCounter(DMA_Stream_TypeDef* DMAy_Streamx);
//读取DMA 数据流 x 要传输的数据项数目
/* Double Buffer mode functions *** ******** 双缓冲模式函数 *********/
void DMA_DoubleBufferModeConfig(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t Memory1BaseAddr,
uint32_t DMA_CurrentMemory);
//在禁用DMAy Streamx时,配置双缓冲区模式和当前内存目标。
void DMA_DoubleBufferModeCmd(DMA_Stream_TypeDef* DMAy_Streamx, FunctionalState NewState);
//启用或禁用所选DMA流的双缓冲区模式
void DMA_MemoryTargetConfig(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t MemoryBaseAddr,
uint32_t DMA_MemoryTarget);
//在双缓冲区模式下(动态使用)为下一次缓冲区传输配置内存地址。当启用DMA流和传输正在进行时,可以调用此函数。
uint32_t DMA_GetCurrentMemoryTarget(DMA_Stream_TypeDef* DMAy_Streamx);
//返回双缓冲区传输所使用的当前内存目标。
/* Interrupts and flags management functions **********************************/
FunctionalState DMA_GetCmdStatus(DMA_Stream_TypeDef* DMAy_Streamx);
//读取DMAy_Streamx的使能状态。
uint32_t DMA_GetFIFOStatus(DMA_Stream_TypeDef* DMAy_Streamx);
//读取FIFO的存放状态
FlagStatus DMA_GetFlagStatus(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t DMA_FLAG);
//检查指定的DMAyStreamx标记是否设置。
void DMA_ClearFlag(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t DMA_FLAG);
清除DMAy Streamx的中断标志位。
void DMA_ITConfig(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t DMA_IT, FunctionalState NewState);
//启用或禁用指定的DMAyStreamx中断。
ITStatus DMA_GetITStatus(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t DMA_IT);
//检查是否发生了指定的DMAy Streamx中断
void DMA_ClearITPendingBit(DMA_Stream_TypeDef* DMAy_Streamx, uint32_t DMA_IT);
//清除DMAyStreamx的指定的中断等待位。