stm32f10x_dma

STM32F10x DMA 外设标准库函数参考文档

数据类型定义

DMA_InitTypeDef - DMA初始化结构体

typedef struct
{
  uint32_t DMA_PeripheralBaseAddr;  /* 外设基地址 */
  uint32_t DMA_MemoryBaseAddr;      /* 存储器基地址 */
  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_M2M;                 /* 存储器到存储器模式 */
} DMA_InitTypeDef;

成员说明:

  • DMA_PeripheralBaseAddr:指定DMA通道的外设基地址
  • DMA_MemoryBaseAddr:指定DMA通道的存储器基地址
  • DMA_DIR:指定传输方向,可选值见 @ref DMA_data_transfer_direction
  • DMA_BufferSize:指定缓冲区大小,以数据单元为单位(1-65535)
  • DMA_PeripheralInc:外设地址是否递增,可选值见 @ref DMA_peripheral_incremented_mode
  • DMA_MemoryInc:存储器地址是否递增,可选值见 @ref DMA_memory_incremented_mode
  • DMA_PeripheralDataSize:外设数据宽度,可选值见 @ref DMA_peripheral_data_size
  • DMA_MemoryDataSize:存储器数据宽度,可选值见 @ref DMA_memory_data_size
  • DMA_Mode:传输模式,可选值见 @ref DMA_circular_normal_mode
  • DMA_Priority:通道优先级,可选值见 @ref DMA_priority_level
  • DMA_M2M:存储器到存储器传输使能,可选值见 @ref DMA_memory_to_memory

枚举类型定义

DMA传输方向

#define DMA_DIR_PeripheralDST    ((uint32_t)0x00000010)  /* 存储器到外设 */
#define DMA_DIR_PeripheralSRC    ((uint32_t)0x00000000)  /* 外设到存储器 */

说明:

  • DMA_DIR_PeripheralDST:数据从存储器传输到外设
  • DMA_DIR_PeripheralSRC:数据从外设传输到存储器

DMA外设地址递增模式

#define DMA_PeripheralInc_Enable     ((uint32_t)0x00000040)  /* 外设地址递增使能 */
#define DMA_PeripheralInc_Disable    ((uint32_t)0x00000000)  /* 外设地址递增禁用 */

DMA存储器地址递增模式

#define DMA_MemoryInc_Enable     ((uint32_t)0x00000080)  /* 存储器地址递增使能 */
#define DMA_MemoryInc_Disable    ((uint32_t)0x00000000)  /* 存储器地址递增禁用 */

DMA外设数据宽度

#define DMA_PeripheralDataSize_Byte      ((uint32_t)0x00000000)  /* 8位数据宽度 */
#define DMA_PeripheralDataSize_HalfWord  ((uint32_t)0x00000100)  /* 16位数据宽度 */
#define DMA_PeripheralDataSize_Word      ((uint32_t)0x00000200)  /* 32位数据宽度 */

DMA存储器数据宽度

#define DMA_MemoryDataSize_Byte      ((uint32_t)0x00000000)  /* 8位数据宽度 */
#define DMA_MemoryDataSize_HalfWord  ((uint32_t)0x00000400)  /* 16位数据宽度 */
#define DMA_MemoryDataSize_Word      ((uint32_t)0x00000800)  /* 32位数据宽度 */

DMA传输模式

#define DMA_Mode_Circular    ((uint32_t)0x00000020)  /* 循环传输模式 */
#define DMA_Mode_Normal      ((uint32_t)0x00000000)  /* 正常传输模式 */

说明:

  • DMA_Mode_Circular:循环传输模式,传输完成后自动重新开始
  • DMA_Mode_Normal:正常传输模式,传输完成后停止

DMA通道优先级

#define DMA_Priority_VeryHigh    ((uint32_t)0x00003000)  /* 非常高优先级 */
#define DMA_Priority_High        ((uint32_t)0x00002000)  /* 高优先级 */
#define DMA_Priority_Medium      ((uint32_t)0x00001000)  /* 中等优先级 */
#define DMA_Priority_Low         ((uint32_t)0x00000000)  /* 低优先级 */

DMA存储器到存储器模式

#define DMA_M2M_Enable     ((uint32_t)0x00004000)  /* 存储器到存储器模式使能 */
#define DMA_M2M_Disable    ((uint32_t)0x00000000)  /* 存储器到存储器模式禁用 */

DMA中断标志定义

基本中断类型

#define DMA_IT_TC    ((uint32_t)0x00000002)  /* 传输完成中断 */
#define DMA_IT_HT    ((uint32_t)0x00000004)  /* 半传输中断 */
#define DMA_IT_TE    ((uint32_t)0x00000008)  /* 传输错误中断 */

DMA1具体中断标志

#define DMA1_IT_GL1    ((uint32_t)0x00000001)  /* DMA1通道1全局中断 */
#define DMA1_IT_TC1    ((uint32_t)0x00000002)  /* DMA1通道1传输完成中断 */
#define DMA1_IT_HT1    ((uint32_t)0x00000004)  /* DMA1通道1半传输中断 */
#define DMA1_IT_TE1    ((uint32_t)0x00000008)  /* DMA1通道1传输错误中断 */
/* ... 其他通道中断标志 ... */

DMA2具体中断标志

#define DMA2_IT_GL1    ((uint32_t)0x10000001)  /* DMA2通道1全局中断 */
#define DMA2_IT_TC1    ((uint32_t)0x10000002)  /* DMA2通道1传输完成中断 */
#define DMA2_IT_HT1    ((uint32_t)0x10000004)  /* DMA2通道1半传输中断 */
#define DMA2_IT_TE1    ((uint32_t)0x10000008)  /* DMA2通道1传输错误中断 */
/* ... 其他通道中断标志 ... */

DMA状态标志定义

DMA1状态标志

#define DMA1_FLAG_GL1    ((uint32_t)0x00000001)  /* DMA1通道1全局标志 */
#define DMA1_FLAG_TC1    ((uint32_t)0x00000002)  /* DMA1通道1传输完成标志 */
#define DMA1_FLAG_HT1    ((uint32_t)0x00000004)  /* DMA1通道1半传输标志 */
#define DMA1_FLAG_TE1    ((uint32_t)0x00000008)  /* DMA1通道1传输错误标志 */
/* ... 其他通道状态标志 ... */

DMA2状态标志

#define DMA2_FLAG_GL1    ((uint32_t)0x10000001)  /* DMA2通道1全局标志 */
#define DMA2_FLAG_TC1    ((uint32_t)0x10000002)  /* DMA2通道1传输完成标志 */
#define DMA2_FLAG_HT1    ((uint32_t)0x10000004)  /* DMA2通道1半传输标志 */
#define DMA2_FLAG_TE1    ((uint32_t)0x10000008)  /* DMA2通道1传输错误标志 */
/* ... 其他通道状态标志 ... */

标准库函数详解

1. DMA_DeInit

/**
 * @brief  将 DMA 通道寄存器恢复为复位默认值,用于重新配置前清空旧传输状态
 * @param  DMAy_Channelx: 指定的DMA通道,可以是DMA1_Channel1到DMA1_Channel7或DMA2_Channel1到DMA2_Channel5
 * @retval
 * @example
 *     DMA_DeInit(DMA1_Channel1);  // 复位DMA1通道1
 */
void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);

功能说明:

  • 清除方向、地址、计数等全部通道配置
  • 切换传输源/目的或模式前先 DeInit
  • 传输异常后可重置通道再 Init

2. DMA_Init

/**
 * @brief  初始化 DMA 通道(源/目的地址、方向、宽度、模式等),建立外设与内存间的搬运路径
 * @param  DMAy_Channelx: 指定的DMA通道
 * @param  DMA_InitStruct: 指向DMA_InitTypeDef结构体的指针,包含配置信息
 * @retval
 * @example
 *     DMA_InitTypeDef DMA_InitStructure;
 *     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
 *     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer;
 *     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
 *     DMA_InitStructure.DMA_BufferSize = 100;
 *     DMA_Init(DMA1_Channel5, &DMA_InitStructure);
 */
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

功能说明:

  • 配置外设到内存、内存到外设或内存到内存
  • 设置数据宽度、地址是否递增、循环/普通模式
  • 需在 DMA_Cmd 前完成,并匹配外设 DMA 请求线

3. DMA_StructInit

/**
 * @brief  将 DMA_InitTypeDef 成员填为安全默认值,避免未赋值字段导致随机配置
 * @param  DMA_InitStruct: 指向DMA_InitTypeDef结构体的指针
 * @retval
 * @example
 *     DMA_InitTypeDef DMA_InitStructure;
 *     DMA_StructInit(&DMA_InitStructure);
 */
void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);

功能说明:

  • 提供合理的默认地址、宽度、优先级等
  • 先 StructInit 再按需修改各成员
  • 降低多字段 DMA 配置的遗漏风险

4. DMA_Cmd

/**
 * @brief  启动或停止 DMA 通道;ENABLE 后按配置自动搬运,DISABLE 后暂停
 * @param  DMAy_Channelx: 指定的DMA通道
 * @param  NewState: DMA通道的新状态,可以是ENABLE或DISABLE
 * @retval
 * @example
 *     DMA_Cmd(DMA1_Channel1, ENABLE);   // 启动DMA传输
 *     DMA_Cmd(DMA1_Channel1, DISABLE);  // 停止DMA传输
 */
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

功能说明:

  • Init 完成且外设 DMA 请求使能后 ENABLE 开始传输
  • DISABLE 可中止当前传输(剩余计数停止递减)
  • 修改 CNDTR 前须先 DISABLE 通道

5. DMA_ITConfig

/**
 * @brief  打开/关闭 DMA 中断(传输完成/半传输/错误),配合 NVIC 获知搬运进度
 * @param  DMAy_Channelx: 指定的DMA通道
 * @param  DMA_IT: 指定的DMA中断源,可以是DMA_IT_TC、DMA_IT_HT、DMA_IT_TE的组合
 * @param  NewState: 中断的新状态,可以是ENABLE或DISABLE
 * @retval
 * @example
 *     DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);  // 使能传输完成中断
 */
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);

功能说明:

  • TC:整缓冲传完,常用于通知应用处理数据
  • HT:半缓冲完成,适合双缓冲乒乓操作
  • TE:传输错误,需排查地址或总线问题

6. DMA_SetCurrDataCounter

/**
 * @brief  设置本次传输的数据单元个数,决定 DMA 搬多少数据后停止
 * @param  DMAy_Channelx: 指定的DMA通道
 * @param  DataNumber: 要传输的数据数量(1-65535)
 * @retval
 * @example
 *     DMA_SetCurrDataCounter(DMA1_Channel1, 1024);  // 设置传输1024个数据单元
 */
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); 

功能说明:

  • 仅在通道 DISABLE 时写入 CNDTR
  • 重复启动传输前需重新设置计数
  • 单元大小由 Init 中的 Memory/Periph DataSize 决定

7. DMA_GetCurrDataCounter

/**
 * @brief  读取通道剩余未传输的数据单元数,用于监控进度或判断完成
 * @param  DMAy_Channelx: 指定的DMA通道
 * @retval 剩余的数据传输数量
 * @example
 *     uint16_t remaining = DMA_GetCurrDataCounter(DMA1_Channel1);
 */
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

功能说明:

  • 传输进行中 CNDTR 递减,为 0 表示完成
  • 可计算已传输量 = 初始值 - 剩余值
  • 轮询等待完成时可替代中断

8. DMA_GetFlagStatus

/**
 * @brief  查询 DMA 标志位(TC/HT/TE),判断传输完成、半完成或错误
 * @param  DMAy_FLAG: 指定的DMA标志位
 * @retval FlagStatus: 标志位状态(SET或RESET)
 * @example
 *     if (DMA_GetFlagStatus(DMA1_FLAG_TC1) == SET) {
 *         // 传输完成处理
 *     }
 */
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);

功能说明:

  • 轮询模式下等待 TC 再处理缓冲
  • TE 置位表示传输错误
  • 标志与通道号对应(如 TC1 对应 Channel1)

9. DMA_ClearFlag

/**
 * @brief  清除 DMA 标志位,避免重复检测到同一完成/错误事件
 * @param  DMAy_FLAG: 指定要清除的DMA标志位
 * @retval
 * @example
 *     DMA_ClearFlag(DMA1_FLAG_TC1);  // 清除传输完成标志
 */
void DMA_ClearFlag(uint32_t DMAy_FLAG);

功能说明:

  • 轮询处理 TC/HT 后必须清除
  • 中断模式下也可配合使用
  • 未清除会导致误以为再次完成

10. DMA_GetITStatus

/**
 * @brief  在中断服务程序中判断具体 DMA 中断源是否挂起
 * @param  DMAy_IT: 指定的DMA中断标志
 * @retval ITStatus: 中断状态(SET或RESET)
 * @example
 *     if (DMA_GetITStatus(DMA1_IT_TC1) == SET) {
 *         // 处理传输完成中断
 *     }
 */
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);

功能说明:

  • 检查使能位与挂起位组合
  • ISR 中区分 TC/HT/TE 分支
  • 比 GetFlagStatus 更适合中断上下文

11. DMA_ClearITPendingBit

/**
 * @brief  清除 DMA 中断挂起位,ISR 处理完毕后必须调用以免重复进中断
 * @param  DMAy_IT: 指定要清除的DMA中断挂起位
 * @retval
 * @example
 *     DMA_ClearITPendingBit(DMA1_IT_TC1);  // 清除传输完成中断挂起位
 */
void DMA_ClearITPendingBit(uint32_t DMAy_IT);

功能说明:

  • 处理完 TC/HT/TE 中断后调用
  • 未清除会导致中断反复触发
  • 与 ClearFlag 配合确保状态干净

使用示例

USART接收DMA配置示例

#include "stm32f10x.h"

#define BUFFER_SIZE 100
uint8_t rx_buffer[BUFFER_SIZE];

void DMA_USART_RX_Config(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    
    // 使能DMA1时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    // 复位DMA通道
    DMA_DeInit(DMA1_Channel5);
    
    // 配置DMA初始化结构体
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rx_buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    
    // 初始化DMA通道
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);
    
    // 使能DMA传输完成中断
    DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
    
    // 启动DMA传输
    DMA_Cmd(DMA1_Channel5, ENABLE);
}

存储器到存储器传输示例

#define DATA_SIZE 1024
uint32_t src_buffer[DATA_SIZE];
uint32_t dst_buffer[DATA_SIZE];

void DMA_M2M_Transfer(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    
    // 使能DMA1时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    // 复位DMA通道
    DMA_DeInit(DMA1_Channel1);
    
    // 配置存储器到存储器传输
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)src_buffer;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)dst_buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = DATA_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
    
    // 初始化并启动DMA传输
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    DMA_Cmd(DMA1_Channel1, ENABLE);
    
    // 等待传输完成
    while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
    DMA_ClearFlag(DMA1_FLAG_TC1);
}

注意事项

  1. 通道选择:不同外设对应特定的DMA通道,需要查阅参考手册确认正确的通道映射

  2. 数据对齐:确保外设和存储器的数据宽度配置正确,避免数据对齐错误

  3. 缓冲区大小:DMA_BufferSize的有效范围是1-65535,超出范围会导致不可预期的行为

  4. 循环模式限制:存储器到存储器传输不能使用循环模式

  5. 中断处理:使用中断时,必须在中断服务程序中清除相应的中断标志位

  6. 优先级冲突:多个DMA通道同时工作时,硬件优先级为DMA1 > DMA2,通道号小的优先级高

  7. 地址递增:根据实际需求配置地址递增模式,FIFO类外设通常不递增地址

  8. 传输监控:可以通过DMA_GetCurrDataCounter()函数实时监控传输进度

总结

STM32F10x DMA外设提供了强大的数据传输功能,支持外设到存储器、存储器到外设以及存储器到存储器的传输。通过合理配置DMA参数,可以大大减轻CPU负担,提高系统整体性能。DMA的关键特性包括多种传输模式、可配置的优先级、灵活的数据宽度支持以及完善的中断机制,是高效数据传输的理想选择。