当前位置: 首页 > news >正文

单片机STM32F103:DMA的原理以及应用

STM32F103系列微控制器(基于ARM Cortex-M3内核)集成了**DMA(Direct Memory Access,直接内存访问)**控制器,用于在存储器与外设、存储器与存储器之间高效传输数据,减少CPU的干预,从而提升系统性能。本文将详细介绍STM32F103的DMA原理、架构、功能特性及使用方法,结合实际代码示例说明如何在开发中应用DMA,特别以STM32CubeMX和HAL库为工具。


1. DMA原理

DMA是一种硬件机制,允许数据在存储器(Flash、SRAM)或外设(UART、SPI、ADC等)之间直接传输,而无需CPU逐字节处理。其核心思想是将数据搬运任务交给DMA控制器,CPU只需配置DMA通道并启动传输,传输完成后通过中断或查询方式获取结果。

1.1 工作原理
  • DMA控制器:STM32F103的DMA控制器管理多个通道,每个通道负责特定的数据传输任务。
  • 数据流
    • 存储器到存储器:如SRAM到SRAM。
    • 外设到存储器:如ADC数据到SRAM。
    • 存储器到外设:如SRAM数据到UART发送缓冲区。
  • 触发机制
    • DMA传输可由软件触发(手动启动)或硬件触发(外设请求,如UART发送完成)。
  • 中断支持
    • 传输完成(TC)、半传输(HT)或传输错误(TE)时可触发中断。
  • 优势
    • 降低CPU负载,适合高吞吐量任务(如ADC采样、音频流)。
    • 提高实时性,适合多任务系统。
1.2 STM32F103的DMA架构

STM32F103的DMA控制器分为DMA1DMA2(部分高密度型号支持DMA2),具体特性如下:

  • DMA1
    • 7个通道(Channel 1-7)。
    • 连接到APB1/APB2外设(如UART、SPI、ADC)及存储器。
  • DMA2(仅高密度型号,如STM32F103ZET6):
    • 5个通道(Channel 1-5)。
    • 通常用于高级外设或额外存储器访问。
  • 通道优先级
    • 每个通道可配置高、中、低优先级,解决多通道冲突。
  • 数据宽度
    • 支持8位、16位、32位数据传输。
  • 传输模式
    • 单次传输:传输固定长度数据后停止。
    • 循环模式:传输完成后自动重新开始,适合连续数据流。
    • 增量模式:支持源/目标地址自动递增或固定。
  • FIFO:STM32F103的DMA无独立FIFO,依赖外设缓冲区或直接传输。
1.3 DMA工作流程
  1. 配置DMA通道
    • 设置源地址、目标地址、数据长度。
    • 配置传输方向(存储器到外设、外设到存储器、存储器到存储器)。
    • 设置数据宽度、优先级、增量模式等。
  2. 启动传输
    • 软件触发(设置ENABLE位)或硬件触发(外设信号)。
  3. 数据传输
    • DMA控制器从源地址读取数据,写入目标地址。
  4. 完成处理
    • 传输完成后,触发中断或置位标志,通知CPU处理结果。

2. STM32F103 DMA功能特性

  • 通道数量
    • DMA1:7通道,支持ADC1/2、SPI1/2、UART1-3、I2C1/2、TIM1-4等。
    • DMA2(若有):5通道,支持高级外设或额外存储器。
  • 传输方向
    • 存储器到存储器(仅DMA1支持)。
    • 外设到存储器(如ADC采样到SRAM)。
    • 存储器到外设(如SRAM数据到UART)。
  • 中断支持
    • 传输完成中断(TCIF)。
    • 半传输中断(HTIF)。
    • 传输错误中断(TEIF)。
  • 数据对齐
    • 支持字节(8位)、半字(16位)、字(32位)传输。
    • 源和目标数据宽度可不同(如8位外设到16位SRAM)。
  • 循环模式
    • 启用后,传输完成后自动重新加载计数器,适合连续数据流。
  • 优先级管理
    • 软件配置通道优先级(Very High, High, Medium, Low)。
    • 硬件仲裁确保高优先级通道优先访问总线。

3. DMA使用方法

以下以STM32F103C8T6为例,结合STM32CubeMX和HAL库,介绍如何实现DMA传输,重点以ADC DMA(外设到存储器)和UART DMA(存储器到外设)为例。

3.1 开发环境准备
  • 硬件
    • STM32F103C8T6开发板(如“蓝板”)。
    • ST-Link V2调试器。
    • USB-TTL模块(如CH340)用于串口调试。
  • 软件
    • STM32CubeMX:配置外设和DMA。
    • STM32CubeIDE:编写和调试代码。
    • STM32CubeProgrammer:烧录程序。
    • 串口终端(如PuTTY):查看输出。
3.2 示例1:ADC DMA(外设到存储器)

目标:使用ADC1连续采样多个通道的数据,通过DMA传输到SRAM缓冲区。

3.2.1 STM32CubeMX配置
  1. 创建项目
    • 打开STM32CubeMX,选择STM32F103C8T6。
  2. 配置ADC
    • 在“Analog”中启用ADC1。
    • 配置通道(如IN0、IN1,连接到PA0、PA1)。
    • 设置为“Continuous Conversion Mode”(连续转换)。
    • 启用“DMA Continuous Requests”。
  3. 配置DMA
    • 在ADC1的“DMA Settings”中,添加DMA请求:
      • 选择DMA1 Channel 1(ADC1默认通道)。
      • 设置:
        • Mode:Circular(循环模式)。
        • Data Width:Half Word(16位,ADC为12位数据)。
        • Increment Address:Memory(目标地址递增)。
        • Priority:Medium。
  4. 配置时钟
    • 设置HSE(8MHz晶振),PLL倍频到72MHz,APB2为72MHz,ADC时钟分频到12MHz(最大14MHz)。
  5. 生成代码
    • 在“Project Manager”中设置项目名称、路径,选择“STM32CubeIDE”。
    • 生成代码。
3.2.2 代码实现

在STM32CubeIDE中,修改main.c实现ADC DMA采样:

#include "main.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "stdio.h"#define ADC_CHANNEL_COUNT 2
uint16_t adcData[ADC_CHANNEL_COUNT]; // 存储ADC采样数据void SystemClock_Config(void);int main(void) {HAL_Init();SystemClock_Config();MX_DMA_Init();MX_ADC1_Init();MX_USART1_UART_Init(); // 串口用于调试// 启动ADC DMAHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcData, ADC_CHANNEL_COUNT);while (1) {// 在循环模式下,DMA自动更新adcDatachar msg[50];sprintf(msg, "ADC1: %u, ADC2: %u\r\n", adcData[0], adcData[1]);HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 100);HAL_Delay(1000); // 每秒打印一次}
}// DMA传输完成回调(可选)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {// 可在此处理传输完成后的逻辑
}

说明

  • HAL_ADC_Start_DMA启动ADC和DMA,数据自动传输到adcData数组。
  • 循环模式下,DMA自动更新缓冲区,CPU无需干预。
  • 串口(UART1)打印ADC采样值,用于调试。
3.2.3 测试
  • 烧录程序到STM32F103。
  • 连接PA0/PA1到模拟信号(如电位器)。
  • 在串口终端(如PuTTY,115200波特率)查看ADC采样值。
3.3 示例2:UART DMA(存储器到外设)

目标:通过DMA将SRAM中的数据发送到UART1。

3.3.1 STM32CubeMX配置
  1. 配置UART
    • 启用USART1(PA9-TX,PA10-RX)。
    • 设置波特率(如115200),模式为异步。
    • 在“DMA Settings”中,添加DMA请求:
      • 选择DMA1 Channel 4(USART1_TX默认通道)。
      • 设置:
        • Mode:Normal(单次传输)。
        • Data Width:Byte(8位,UART数据)。
        • Increment Address:Memory。
        • Priority:Medium。
  2. 生成代码
    • 同ADC示例,生成STM32CubeIDE项目。
3.3.2 kazhuCode实现

修改main.c实现UART DMA发送:

#include "main.h"
#include "dma.h"
#include "usart.h"
#include "string.h"uint8_t txData[] = "Hello, STM32 DMA!\r\n";void SystemClock_Config(void);void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {// 传输完成回调HAL_UART_Transmit(&huart1, (uint8_t*)"TX Complete\r\n", 13, 100);
}int main(void) {HAL_Init();SystemClock_Config();MX_DMA_Init();MX_USART1_UART_Init();// 启动UART DMA发送HAL_UART_Transmit_DMA(&huart1, txData, strlen((char*)txData));while (1) {HAL_Delay(1000); // 每秒发送一次HAL_UART_Transmit_DMA(&huart1, txData, strlen((char*)txData));}
}

说明

  • HAL_UART_Transmit_DMA启动DMA传输,将txData发送到UART1。
  • 传输完成后,触发HAL_UART_TxCpltCallback中断。
  • 单次模式下,需手动重新启动传输。
3.3.3 测试
  • 烧录程序。
  • 连接USB-TTL模块(PA9->RX,PA10->TX)。
  • 在串口终端查看输出“Hello, STM32 DMA!”。

4. 关键配置注意事项

  • DMA初始化顺序
    • main.c中,MX_DMA_Init必须在其他外设初始化(如MX_ADC1_InitMX_USART1_Init)之前调用,确保DMA时钟启用。
  • 通道选择
    • 每个外设有固定DMA通道(如ADC1->DMA1 Channel 1,USART1_TX->DMA1 Channel 4)。参考STM32F103参考手册。
  • 数据对齐
    • 源和目标数据宽度需匹配(如ADC为16位,缓冲区应为uint16_t)。
  • 中断管理
    • 启用DMA中断(如HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn))。
    • 在中断回调中处理传输完成或错误。
  • 循环模式 vs 单次模式
    • 循环模式适合连续数据流(如ADC采样)。
    • 单次模式适合一次性传输(如UART发送固定字符串)。
  • 优先级冲突
    • 多通道同时传输时,设置高优先级给关键任务(如ADC优于UART)。

5. 常见问题及解决

  • DMA不工作
    • 检查DMA通道是否与外设匹配。
    • 确保MX_DMA_Init在其他外设初始化前调用。
    • 验证源/目标地址正确,数据长度非零。
  • 数据错误
    • 检查数据宽度(Byte/Half Word/Word)是否与外设匹配。
    • 确保目标缓冲区有足够空间。
  • 中断未触发
    • 确认中断使能(HAL_DMA_Start_IT或外设API)。
    • 检查NVIC配置(优先级、使能)。
  • 总线冲突
    • 避免多个DMA通道同时访问同一存储器区域。
    • 调整通道优先级或降低传输速率。

6. 扩展应用

  • 多通道ADC:使用DMA采集多个ADC通道数据,存储到数组,适合信号处理。
  • SPI DMA:实现高速SPI数据传输(如与LCD或Flash通信)。
  • FreeRTOS集成:结合DMA中断和信号量,优化实时任务调度。
  • 双缓冲技术:在循环模式下使用两个缓冲区交替存储数据,避免数据覆盖。

7. 学习资源

  • 官方文档
    • STM32F103参考手册(DMA章节)。
    • STM32CubeMX用户手册。
  • 教程
    • 正点原子/野火的STM32 DMA教程。
    • ST社区论坛的DMA应用笔记(如AN2548)。
  • 工具
    • STM32CubeMonitor:监控DMA传输数据。
    • 逻辑分析仪:调试外设信号。

8. 总结

STM32F103的DMA控制器通过高效的数据传输,显著降低CPU负载,适合高吞吐量场景。DMA1支持7通道,DMA2(部分型号)支持5通道,覆盖ADC、UART、SPI等外设。使用STM32CubeMX配置DMA参数,结合HAL库(如HAL_ADC_Start_DMAHAL_UART_Transmit_DMA)可快速实现传输。关键注意初始化顺序、通道选择和数据对齐,通过中断和循环模式优化性能。

http://www.dtcms.com/a/271610.html

相关文章:

  • 滚筒式茶叶杀青机设计【12张+总装图】+三维图+设计说明书+绛重
  • Hugging Face Agents Course unit1笔记
  • Pycharm 报错 Environment location directory is not empty 如何解决
  • Vue2开发:使用vuedraggable实现菜单栏拖拽
  • 什么是AI Agent同步调用工具和异步调用工具?
  • python实践思路(草拟计划+方法)
  • 力扣-240.搜索二维矩阵 II
  • 【C#】PanelControl与Panel
  • 【RidgeUI AI+系列】猜密码游戏
  • miniconda 初始化 base 环境
  • 洛谷 P2880 [USACO07JAN] Balanced Lineup G-普及/提高-
  • 图神经网络 gnn 应用到道路网络拓扑结构与交通碳排放相关性。,拓扑指标量化、时空关联模型及演化机制分析
  • NVIDIA显卡驱动安装失败的解决办法(例如7-zip data error或脚本错误)
  • 数据库技术体系及场景选型方案
  • Linux操作系统之进程间通信:管道概念
  • 双立柱式带锯床cad【1张总图】+设计说明书+绛重
  • 软件发布的完整流程梳理
  • RIP和静态路由结合实验:高可用及高可靠
  • Java -- 异常--以及处理
  • 图像自动化处理初探:从拖拽上传到参数设置
  • 智能Agent场景实战指南 Day 7:智能客服Agent设计与实现
  • 继承与多态:面向对象编程的两大支柱
  • 多线程(2)
  • 1、专栏介绍以及目录
  • Vue3常用指令
  • 可转债应该在什么价卖出?
  • 01-elasticsearch-搭个简单的window服务-ik分词器-简单使用
  • RAGFlow 与 QAnything 智能切片对比:深度解析与优劣考量
  • LeetCode热题100—— 152. 乘积最大子数组
  • ServBay Windows 1.2.0 更新!新增 PHP 设置与 Ollama 支持