DMA支持各种外设、闪存、SRAM作为数据源和数据目标,具体可查表。 同时仅一个有效。
STM32的DMA特性包括:
STM32F103ZET6 有两个 DMA 控制器,DMA1 和 DMA2。
外设(如TIMx、ADC、SPIx、I2Cx、USARTx)产生的DMA请求经逻辑或处理后输入DMA控制器,确保同时仅一个有效,通过仲裁器和DMA_CCRx的优先级配置裁决哪个先执行。
通道1的多个DMA1请求(如ADC1、TIM2_CH3、TIM4_CH1)通过逻辑或运算合并,确保同一时间仅一个请求能被响应,其他通道同理。
例如我们想使用 USART1,查表可知需用到DMA1的通道4和通道5。
由于DMA1有7个通道,每个通道有传输错误标志、半传输标志、传输完成标志、全局中断标志,因此DMA_ISR作为32位寄存器使用了4*7=28位。
半传输指数据已经传输缓冲区的一半。
全局中断指传输错误、半传输、传输完成任意一个满足都触发。
最常用的是传输完成标志。如果开启了这些中断,达到条件后就会跳到中断服务函数。
可通过查询中断状态寄存器DMA_ISR来获得当前DMA的状态。
DMA_ISR是只读寄存器,可以用来获得DMA的传输错误、半传输、传输完成、全局中断标志。要清除 DMA_ISR的标志位需要使用中断标志清除寄存器DMA_IFCR。
传输错误、半传输、传输完成、全局中断标志位,仍然是32位寄存器使用了4*7=28。
通道x配置寄存器DMA_CCRx用来配置
- 模式(存储器到存储器模式,寄存器到存储器模式)、
- 通道优先级(低、中、高、最高),
- 存储器数据宽度(8位、16位、32位、保留),
- 外设数据宽度(8位、16位、32位、保留),
- 存储器地址增量模式(0,1), 传输完成后地址自增,用于连续传输
- 外设地址增量模式(0,1),
- 循环模式(0,1),
- 数据传输方向(从外设读,从存储器读),
- 允许错误传输中断(0,1),
- 允许半传输中断(0,1),
- 允许传输完成中断(0,1),
- 通道开启(0,1)
通道x传输数据量寄存器DMA_CNDTRx,用来控制DMA通道x每次要传输的数据量,范围为0~65535,字节。该寄存器的值会随着传输的进行而减少,数据量寄存器的值为0表示传输完成。所以可通过传输量寄存器的值得知当前传输进度。Channel x Number of Data to Transfer Register
DMA Channel x Peripheral Address Register
1)使能DMA时钟:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
2)初始化DMA通道4参数:
创建并填充DMA_InitTypeDef结构体,
传输方向(如DMA_DIR_PeripheralDST)、
传输数据量、
数据宽度、
传输模式(如DMA_Mode_Normal)、
优先级、
是否存储器到存储器传输等。
调用
DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)
函数进行初始化。
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; // 外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)cmar; // 内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 内存到外设
DMA_InitStructure.DMA_BufferSize = 64; // 传输数据量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; // 中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 非内存到内存
DMA_Init(DMA1_Channel4, &DMA_InitStructure); // 初始化DMA1通道4
3)使能串口DMA发送
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // 使能USART1的DMA发送
4)启动DMA传输
DMA_Cmd(DMA1_Channel4, ENABLE); // 启动DMA1通道4
5)查询DMA传输状态
// 查询DMA1通道4是否传输完成
FlagStatus status = DMA_GetFlagStatus(DMA1_FLAG_TC4);
// 获取DMA1通道4剩余数据量
uint16_t remainingData = DMA_GetCurrDataCounter(DMA1_Channel4);
因篇幅问题不能全部显示,请点此查看更多更全内容