STM32 DMA传输模式
介绍
DMA(Direct Memory Access,直接内存访问)是STM32微控制器中一种高效的数据传输机制。它允许外设与内存之间直接传输数据,而无需CPU的干预。这种机制可以显著提高系统的性能,尤其是在需要大量数据传输的场景中。
在STM32中,DMA传输模式有多种,每种模式适用于不同的应用场景。本文将详细介绍这些传输模式,并通过代码示例和实际案例帮助你更好地理解和应用它们。
DMA传输模式概述
STM32的DMA控制器支持以下几种传输模式:
- 正常模式(Normal Mode)
- 循环模式(Circular Mode)
- 内存到内存模式(Memory-to-Memory Mode)
- 外设到内存模式(Peripheral-to-Memory Mode)
- 内存到外设模式(Memory-to-Peripheral Mode)
1. 正常模式(Normal Mode)
在正常模式下,DMA传输会在一次传输完成后停止。这种模式适用于只需要传输一次数据的场景。
配置示例
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = 100;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
2. 循环模式(Circular Mode)
在循环模式下,DMA传输会在缓冲区末尾自动回到起始位置,继续传输。这种模式适用于需要连续传输数据的场景,如音频流处理。
配置示例
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = 100;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
3. 内存到内存模式(Memory-to-Memory Mode)
在内存到内存模式下,DMA可以直接在两个内存区域之间传输数据,而无需外设的参与。这种模式适用于需要快速复制大量数据的场景。
配置示例
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToMemory;
DMA_InitStruct.DMA_BufferSize = 100;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_M2M = DMA_M2M_Enable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
4. 外设到内存模式(Peripheral-to-Memory Mode)
在外设到内存模式下,DMA可以从外设(如ADC、UART等)读取数据并存储到内存中。这种模式适用于需要从外设读取大量数据的场景。
配置示例
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = 100;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
5. 内存到外设模式(Memory-to-Peripheral Mode)
在内存到外设模式下,DMA可以从内存中读取数据并发送到外设(如DAC、UART等)。这种模式适用于需要向外设发送大量数据的场景。
配置示例
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStruct.DMA_BufferSize = 100;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
实际案例
案例1:使用DMA进行ADC数据采集
假设我们需要从ADC采集100个样本,并将这些数据存储到内存中。我们可以使用外设到内存模式的DMA来实现这一功能。
uint16_t adc_buffer[100];
void ADC_DMA_Init(void) {
DMA_InitTypeDef DMA_InitStruct;
ADC_InitTypeDef ADC_InitStruct;
// 配置DMA
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = 100;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStruct);
// 配置ADC
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_ScanConvMode = ENABLE;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStruct);
// 启动DMA
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
}
案例2:使用DMA进行UART数据发送
假设我们需要通过UART发送100个字节的数据。我们可以使用内存到外设模式的DMA来实现这一功能。
uint8_t uart_buffer[100] = "Hello, World!";
void UART_DMA_Init(void) {
DMA_InitTypeDef DMA_InitStruct;
USART_InitTypeDef USART_InitStruct;
// 配置DMA
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStruct.DMA_BufferSize = 100;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStruct);
// 配置UART
USART_InitStruct.USART_BaudRate = 9600;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx;
USART_Init(USART1, &USART_InitStruct);
// 启动DMA
DMA_Cmd(DMA1_Channel4, ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
USART_Cmd(USART1, ENABLE);
}
总结
通过本文,我们详细介绍了STM32中的DMA传输模式,包括正常模式、循环模式、内存到内存模式、外设到内存模式和内存到外设模式。每种模式都有其特定的应用场景,理解这些模式的工作原理和配置方法对于优化STM32应用程序的性能至关重要。
附加资源与练习
- 练习1:尝试使用DMA将数据从一个内存区域复制到另一个内存区域,并验证数据的正确性。
- 练习2:使用DMA从ADC采集数据,并将数据通过UART发送出去。
- 资源:参考STM32官方文档,了解更多关于DMA的详细配置和使用方法。
在实际项目中,合理使用DMA可以显著提高系统的性能和响应速度。建议在需要大量数据传输的场景中优先考虑使用DMA。