DMA(Direct Memory Access)是STM32微控制器中的一种重要外设,可以实现高效的数据传输,减轻CPU的负担。DMA的工作原理是通过独立的通道将数据从外设直接传输到内存,或者从内存传输到外设,而无需CPU的干预。本文将深入介绍STM32中DMA的工作原理和配置方法,并提供一个简单的示例代码来演示DMA的用法。
✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
点击领取更多详细资料
DMA的工作原理:
DMA控制器负责管理数据传输,包括源地址、目标地址和传输长度。当需要进行数据传输时,DMA将占用总线控制权,然后从源地址读取数据并将其传输到目标地址。在传输过程中,CPU可以执行其他任务,而无需等待数据传输完成。
关键术语:
- 源地址(Source Address):要传输数据的起始地址。
- 目标地址(Destination Address):数据传输的目标地址。
- 通道(Channel):DMA控制器中的通道用于连接外设和内存,进行数据传输。
- 传输长度(Transfer Length):数据传输的长度,通常是以字节单位进行传输。
- 循环模式(Circular Mode):当数据传输完成后,DMA可以自动重新开始传输,从而实现循环传输。
- 数据宽度(Data Width):DMA支持不同的数据宽度,如8位、16位或32位。
配置DMA的步骤:
步骤一:打开STM32CubeMX并创建新工程
首先打开STM32CubeMX软件,选择对应的STM32系列和型号。点击 "New Project" 按钮并创建一个新工程。接着选择目标微控制器系列和型号,并确定工程的存放位置。点击 "Start Project" 按钮创建新工程。
步骤二:配置外设和DMA
选择需要使用的外设,例如USART、SPI、I2C等,并为其分配一个DMA通道。在 "Pinout & Configuration" 选项卡中,选择外设对应的引脚,并为其分配DMA通道。
步骤三:配置DMA控制器
在 "Configuration" 选项卡中,选择 DMA 来配置 DMA 控制器的相关参数。这些参数包括传输方向、数据宽度、传输长度、循环模式等。
步骤四:生成代码并编写应用代码
在配置完成后,点击 "Project" 按钮,在配置相关选项后,点击 "Generate Code" 按钮生成初始化代码。然后导入生成的工程文件并编写应用代码。
示例代码:
以下是一个使用DMA从USART1接收数据并通过USART2发送数据的简单示例代码:
```c
#include "main.h"
#include "stm32f4xx_hal.h"UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart2_tx;void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();while (1){if (HAL_UART_Transmit_DMA(&huart2, (uint8_t *) "Hello DMA!\r\n", 12) != HAL_OK){Error_Handler();}HAL_Delay(1000);}
}void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct;RCC_ClkInitTypeDef RCC_ClkInitStruct;// 系统时钟配置代码// ...if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){Error_Handler();}
}void MX_GPIO_Init(void)
{// 配置GPIO引脚// ...
}void MX_DMA_Init(void)
{__HAL_RCC_DMA2_CLK_ENABLE(); // 使能DMA2时钟// 配置USART1的DMA接收hdma_usart1_rx.Instance = DMA2_Stream2;hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_usart1_rx.Init.Mode = DMA_NORMAL;hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK){Error_Handler();}__HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx);// 配置USART2的DMA发送hdma_usart2_tx.Instance = DMA1_Stream6;hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4;hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_usart2_tx.Init.Mode = DMA_NORMAL;hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK){Error_Handler();}__HAL_LINKDMA(&huart2, hdmatx, hdma_usart2_tx);
}void MX_USART1_UART_Init(void)
{huart1.Instance = USART1;huart1.Init.BaudRate = 115200;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}
}void MX_USART2_UART_Init(void)
{huart2.Instance = USART2;huart2.Init.BaudRate = 115200;huart2.Init.WordLength = UART_WORDLENGTH_8B;huart2.Init.StopBits = UART_STOPBITS_1;huart2.Init.Parity = UART_PARITY_NONE;huart2.Init.Mode = UART_MODE_TX;huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart2.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart2) != HAL_OK){Error_Handler();}
}void Error_Handler(void)
{while (1){}
}
```
在此示例代码中,我们配置了USART1和USART2进行UART通信,并使用DMA进行数据传输。在主函数中,通过HAL_UART_Transmit_DMA函数使用DMA从USART2发送数据到USART1。
总结:
DMA是STM32微控制器中的重要外设,通过直接内存访问实现高效的数据传输,减轻CPU的负担。通过使用STM32CubeMX工具,可以方便地配置DMA的工作参数,并生成相应的初始化代码。希望本教程对于深入理解STM32中DMA的工作原理和配置方法,并在实际开发中应用DMA功能的开发人员有所帮助。
✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
点击领取更多详细资料