5.4 DMA 使用说明
本章说明 N32G033 标准外设库中 DMA 驱动的文件组成、12 个公开函数,以及 FLASH_RAM 1 个示例。DMA 的请求映射、传输方向与存储器到存储器模式请配合用户手册的“DMA”章节阅读,芯片已知问题以勘误手册为准。
5.4.1 相关文件
| 相对路径 | 作用 |
|---|---|
firmware/n32g033_std_periph_driver/inc/n32g033_dma.h |
定义 DMA_InitType 结构体与传输方向、地址增量、数据位宽、优先级、请求映射等宏,并按一段连续声明 12 个公开函数 |
firmware/n32g033_std_periph_driver/src/n32g033_dma.c |
实现上述 12 个函数:通道复位与初始化、使能与传输计数、中断与标志处理、请求重映射 |
projects/n32g033_EVAL/examples/DMA/ |
DMA 示例根目录,含 FLASH_RAM 1 个示例 |
projects/n32g033_EVAL/examples/DMA/FLASH_RAM/ |
该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt |
projects/n32g033_EVAL/bsp/ |
示例共用的板级支持文件:log.h 提供串口日志接口 |
5.4.2 API 参考
以下 12 个公开函数按 n32g033_dma.h 的声明顺序分为 1 组;每个条目给出功能摘要与 n32g033_dma.c 中该函数正上方的注释原文。
复位、初始化与传输控制
DMA_DeInit、DMA_Init、DMA_StructInit、DMA_EnableChannel、DMA_ConfigInt、DMA_SetCurrDataCounter、DMA_GetCurrDataCounter、DMA_GetFlagStatus、DMA_ClearFlag、DMA_GetIntStatus、DMA_ClrIntPendingBit、DMA_RequestRemap
void DMA_DeInit(DMA_ChannelType* DMAChx)将 DMA 通道 x 的 CHCFG、TXNUM、PADDR、MADDR、INTCLR 寄存器复位为默认值。
name DMA_DeInit.
fun Reset CHCFG, TXNUM, PADDR, MADDR, INTCLR registers of DMA Channel x
to their default reset values.
param DMAChx (The input parameters must be the following values):
- DMA_CH1
- DMA_CH2
- DMA_CH3
return none
void DMA_Init(DMA_ChannelType* DMAChx, DMA_InitType* DMA_InitParam)按 DMA_InitParam 初始化 DMA 通道 x,包括外设/存储器地址、传输方向、地址增量、数据位宽、优先级等。
name DMA_Init.
fun Initializes the DMA Channel x by the structure parameter
DMA_InitParam of type DMA_InitType. Includes configuration
peripheral/memory address, transmission direction, address
increment mode, data bit width, priority, etc.
param DMAChx (The input parameters must be the following values):
- DMA_CH1
- DMA_CH2
- DMA_CH3
param DMA_InitParam (The input parameters must be the following values):
- PeriphAddr
-0x00000000~0xFFFFFFFF
- MemAddr
-0x00000000~0xFFFFFFFF
- Direction
- DMA_DIR_PERIPH_DST
- DMA_DIR_PERIPH_SRC
- BufSize
-0x0000~0xFFFF
- PeriphInc
- DMA_PERIPH_INC_ENABLE
- DMA_PERIPH_INC_DISABLE
- DMA_MemoryInc
- DMA_MEM_INC_ENABLE
- DMA_MEM_INC_DISABLE
- PeriphDataSize
- DMA_PERIPH_DATA_SIZE_BYTE
- DMA_PERIPH_DATA_SIZE_HALFWORD
- DMA_PERIPH_DATA_SIZE_WORD
- MemDataSize
- DMA_MemoryDataSize_Byte
- DMA_MemoryDataSize_HalfWord
- DMA_MemoryDataSize_Word
- CircularMode
- DMA_MODE_CIRCULAR
- DMA_MODE_NORMAL
- Priority
- DMA_PRIORITY_VERY_HIGH
- DMA_PRIORITY_HIGH
- DMA_PRIORITY_MEDIUM
- DMA_PRIORITY_LOW
- Mem2Mem
- DMA_M2M_ENABLE
- DMA_M2M_DISABLE
return none
void DMA_StructInit(DMA_InitType* DMA_InitParam)用默认值填充用于初始化 DMA 的 DMA_InitType 结构体,通常在初始化该结构体之前调用。
name DMA_StructInit.
fun Initializes the structure parameter of type DMA_InitType used to
initialize DMA. This function is usually called before initializing
a parameter of type DMA_InitType.
param DMA_InitParam :
- Pointer to the DMA_InitType structure which will be initialized.
return none
void DMA_EnableChannel(DMA_ChannelType* DMAChx, FunctionalState Cmd)使能 DMA 通道 x;DMA 初始化成功后调用该函数开始搬运数据。
name DMA_EnableChannel.
fun DMA Channel x Channel enable. This function is called after DMA
initialization is successful to start moving data.
param DMAChx (The input parameters must be the following values):
- DMA_CH1
- DMA_CH2
- DMA_CH3
param Cmd:(The input parameters must be the following values)
- ENABLE
- DISABLE
return none
void DMA_ConfigInt(DMA_ChannelType* DMAChx, uint32_t DMAInt, FunctionalState Cmd)使能 DMA 通道 x 的中断,包括传输完成、半传输与传输错误中断。
name DMA_ConfigInt.
fun DMA Channel x interrupts enable. Before enabling a DMA channel,
enabling transfer completion interrupt, half-transfer interrupt
or transfer error interrupt will cause an interrupt when the
corresponding event occurs.
param DMAChx (The input parameters must be the following values):
- DMA_CH1
- DMA_CH2
- DMA_CH3
param DMAInt (The input parameters must be the following values):
- DMA_INT_TXC
- DMA_INT_HTX
- DMA_INT_ERR
param Cmd:(The input parameters must be the following values)
- ENABLE
- DISABLE
return none
void DMA_SetCurrDataCounter(DMA_ChannelType* DMAChx, uint16_t DataNumber)设置 DMA 通道 x 本次要传输的数据个数。
name DMA_SetCurrDataCounter.
fun Set the current number of data transfers for DMA Channel x.
param DMAChx (The input parameters must be the following values):
- DMA_CH1
- DMA_CH2
- DMA_CH3
param DataNumber(The input parameters must be the following values) :
- 0~0xFFFF
return none
note This function can only be used when the DMAChx is disabled.
uint16_t DMA_GetCurrDataCounter(const DMA_ChannelType* DMAChx)获取 DMA 通道 x 当前剩余待传输的数据个数。
name DMA_GetCurrDataCounter.
fun Get the current number of remaining data for DMA Channel x.
param DMAChx (The input parameters must be the following values):
- DMA_CH1
- DMA_CH2
- DMA_CH3
return Returns the number of bytes remaining to be transferred.
FlagStatus DMA_GetFlagStatus(uint32_t DMAFlag, const DMA_Module* DMAy)获取 DMA 通道 x 的标志状态,包括全局标志、传输完成、半传输与传输错误标志。
name DMA_GetFlagStatus.
fun Get DMA Channel x flag status. Contains the global flag, transfer
completion flag, half-transfer flag, and transfer error flag for
the corresponding channel.
param DMAFlag (The input parameters must be the following values):
- DMA_FLAG_GL1
- DMA_FLAG_TC1
- DMA_FLAG_HT1
- DMA_FLAG_TE1
- DMA_FLAG_GL2
- DMA_FLAG_TC2
- DMA_FLAG_HT2
- DMA_FLAG_TE2
- DMA_FLAG_GL3
- DMA_FLAG_TC3
- DMA_FLAG_HT3
- DMA_FLAG_TE3
param DMAy (The input parameters must be the following values):
- DMA
return SET or RESET.
void DMA_ClearFlag(uint32_t DMAFlag, DMA_Module* DMAy)清除 DMA 通道 x 的标志状态,包括全局标志、传输完成、半传输与传输错误标志。
name DMA_ClearFlag.
fun Clear DMA Channel x flag status. Contains the global flag, transfer
completion flag, half-transfer flag, and transfer error flag for the
corresponding channel.
param DMAFlag (The input parameters must be the following values):
- DMA_FLAG_GL1
- DMA_FLAG_TC1
- DMA_FLAG_HT1
- DMA_FLAG_TE1
- DMA_FLAG_GL2
- DMA_FLAG_TC2
- DMA_FLAG_HT2
- DMA_FLAG_TE2
- DMA_FLAG_GL3
- DMA_FLAG_TC3
- DMA_FLAG_HT3
- DMA_FLAG_TE3
param DMAy (The input parameters must be the following values):
- DMA
return none.
INTStatus DMA_GetIntStatus(uint32_t DMA_IT, const DMA_Module* DMAy)获取 DMA 通道 x 的中断状态,包括全局中断、传输完成、半传输与传输错误中断。
name DMA_GetIntStatus.
fun Get DMA Channel x interrupt status. Contains the global interrupt,
transfer completion interrupt, half-transfer interrupt, and transfer
error interrupt for the corresponding channel.
param DMA_IT (The input parameters must be the following values):
- DMA_INT_GLB1
- DMA_INT_TXC1
- DMA_INT_HTX1
- DMA_INT_ERR1
- DMA_INT_GLB2
- DMA_INT_TXC2
- DMA_INT_HTX2
- DMA_INT_ERR2
- DMA_INT_GLB3
- DMA_INT_TXC3
- DMA_INT_HTX3
- DMA_INT_ERR3
param DMAy (The input parameters must be the following values):
- DMA
return SET or RESET.
note Global interrupt status is the logic or generation of transfer completion
interrupt, half-transfer interrupt, transfer error interrupt.
void DMA_ClrIntPendingBit(uint32_t DMA_IT, DMA_Module* DMAy)清除 DMA 通道 x 的中断状态位,包括全局中断、传输完成、半传输与传输错误中断。
name DMA_ClrIntPendingBit.
fun Clear DMA Channel x interrupt status bits. Contains the global interrupt,
transfer completion interrupt, half-transfer interrupt, and transfer
error interrupt for the corresponding channel.
param DMA_IT (The input parameters must be the following values):
- DMA_INT_GLB1
- DMA_INT_TXC1
- DMA_INT_HTX1
- DMA_INT_ERR1
- DMA_INT_GLB2
- DMA_INT_TXC2
- DMA_INT_HTX2
- DMA_INT_ERR2
- DMA_INT_GLB3
- DMA_INT_TXC3
- DMA_INT_HTX3
- DMA_INT_ERR3
param DMAy (The input parameters must be the following values):
- DMA
return none.
note Global interrupt state is the logic or generation of transfer completion
interrupt, half-transfer interrupt, transfer error interrupt. In fact,
after clearing the three interrupt states, the global interrupt state
will also be cleared.
void DMA_RequestRemap(uint32_t DMA_REMAP, const DMA_Module* DMAy, DMA_ChannelType* DMAChx, FunctionalState Cmd)设置 DMA 通道 x 的请求重映射,可把任意 DMA 请求映射到任意通道;同一时刻每个通道只能有一个 DMA 请求。
name DMA_RequestRemap.
fun Set DMA Channel x's remap request. Channel request mapping is flexible,
allowing users to map any DMA request to any DMA channel as needed. It
is important to note that there can be only one DMA request per DMA
channel at a time.
param DMA_REMAP (The input parameters must be the following values):
- DMA_REMAP_UART1_TX
- DMA_REMAP_UART1_RX
- DMA_REMAP_UART2_TX
- DMA_REMAP_UART2_RX
- DMA_REMAP_UART3_TX
- DMA_REMAP_UART3_RX
- DMA_REMAP_SPI1_TX
- DMA_REMAP_SPI1_RX
- DMA_REMAP_SPI2_TX
- DMA_REMAP_SPI2_RX
- DMA_REMAP_I2C1_TX
- DMA_REMAP_I2C1_RX
- DMA_REMAP_I2C2_TX
- DMA_REMAP_I2C2_RX
- DMA_REMAP_TIM1_CH1
- DMA_REMAP_TIM1_CH2
- DMA_REMAP_TIM1_CH3
- DMA_REMAP_TIM1_CH4
- DMA_REMAP_TIM1_COM
- DMA_REMAP_TIM1_UP
- DMA_REMAP_TIM1_TRIG
- DMA_REMAP_TIM3_CH1
- DMA_REMAP_TIM3_CH2
- DMA_REMAP_TIM3_CH3
- DMA_REMAP_TIM3_CH4
- DMA_REMAP_TIM3_UP
- DMA_REMAP_TIM3_TRIG
- DMA_REMAP_TIM4_CH1
- DMA_REMAP_TIM4_CH2
- DMA_REMAP_TIM4_CH3
- DMA_REMAP_TIM4_UP
- DMA_REMAP_TIM4_TRIG
- DMA_REMAP_TIM6_UP
- DMA_REMAP_RESERVED
param DMAy (The input parameters must be the following values):
- DMA
param DMAChx (The input parameters must be the following values):
- DMA_CH1
- DMA_CH2
- DMA_CH3
param Cmd:(The input parameters must be the following values)
- ENABLE
- DISABLE
return none.
5.4.3 Demo 示例说明
本节说明 DMA 的 1 个示例:FLASH_RAM 用存储器到存储器模式把 FLASH 中的常量数组搬到 RAM 并做校验。
5.4.3.1 FLASH_RAM 存储器到存储器传输
工程目录: projects/n32g033_EVAL/examples/DMA/FLASH_RAM/
使能 DMA 时钟并打开通道中断→配置通道的源地址、目标地址与传输长度→启动存储器到存储器传输→传输完成中断读取剩余计数并清标志→串口打印校验结果
| 项目 | 源码解读 |
|---|---|
| 功能 | 用 DMA 的存储器到存储器模式把 FLASH 中的常量数组 SRC_Const_Buffer 搬到 RAM 数组 DST_Buffer,搬运完成后用 memcmp 比较并在串口打印结果。 |
| 源码组成 | src/main.c 含 main、RCC_Configuration 与 NVIC_Configuration;src/n32g033_it.c 中的 DMA_IRQ_HANDLER 读取剩余计数并清中断标志;inc/main.h、inc/n32g033_it.h 给出声明;readme.txt 给出测试步骤;工程文件在 MDK-ARM/ 与 EWARM/。 |
| 关键配置 | 通道:DMA_CH1;源为 FLASH 常量数组 SRC_Const_Buffer,目标为 RAM 数组 DST_Buffer;传输方向 DMA_DIR_PERIPH_SRC、存储器到存储器使能、字(Word)数据宽度;源与目标地址均递增、普通模式、高优先级; 传输完成中断使能,请求源重映射到保留项。 |
| 程序与数据路径 | main → RCC_Configuration 打开 AHB 上的 DMA 时钟 → NVIC_Configuration 使能 DMA 中断 → DMA_DeInit、DMA_StructInit、DMA_Init 配置通道 → DMA_RequestRemap 映射保留请求 → DMA_ConfigInt 使能传输完成中断 → DMA_EnableChannel 启动传输 → 等待剩余计数归零 → memcmp 校验后打印结果。 |
| 主要 API | DMA_DeInit、DMA_StructInit、DMA_Init、DMA_RequestRemap、DMA_ConfigInt、DMA_GetCurrDataCounter、DMA_EnableChannel、DMA_GetIntStatus、DMA_ClrIntPendingBit |
| 验证方法 | 硬件基于评估板 N32G033K8Q7-1_STB V1.0,串口 TX 为 PA9、RX 为 PA10,波特率 115200; 编译下载复位运行后,串口打印 DMA Flash to RAM passed 表示搬运与校验成功。 |
| 使用提示 | 系统时钟 64 MHz; 存储器到存储器模式不使用外设请求,示例把请求源重映射到保留项,否则请求会落到 UART1_TX 上。 |
核心代码解读与移植
示例用 DMA 的存储器到存储器模式在 FLASH 与 RAM 之间搬数,搬运结束后校验两侧内容是否一致。
数据路径: RCC_Configuration 打开 DMA 时钟 → NVIC_Configuration 使能 DMA 中断 → DMA_Init 配置源地址、目标地址与传输长度 → DMA_EnableChannel 启动传输 → 传输完成中断读取剩余计数并清标志 → memcmp 校验数据
1. 时钟与中断一起打开。 DMA 挂在 AHB 总线上,要先打开它的时钟,再把通道中断接入 NVIC,否则传输完成事件不会进入中断。
void RCC_Configuration(void)
{
/* Enable DMA clock */
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);
}
NVIC_InitType NVIC_InitStructure;
/* Enable DMA IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA_IRQN;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
换用其他 DMA 通道时同步修改中断号;DMA 的时钟位在 AHB 上而不是 APB,写错总线会让通道无法工作。
2. 地址与传输参数一次配好。 DMA_StructInit 给默认值后,用结构体指定源地址、目标地址、传输方向、数据宽度与存储器到存储器模式。
DMA_DeInit(DMA_CHANNEL_USED);
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.PeriphAddr = (uint32_t)SRC_Const_Buffer;
DMA_InitStructure.MemAddr = (uint32_t)DST_Buffer;
DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC;
DMA_InitStructure.BufSize = BUFFER_SIZE;
DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_ENABLE;
DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_WORD;
DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
DMA_InitStructure.Priority = DMA_PRIORITY_HIGH;
DMA_InitStructure.Mem2Mem = DMA_M2M_ENABLE;
DMA_Init(DMA_CHANNEL_USED, &DMA_InitStructure);
Direction 取 DMA_DIR_PERIPH_SRC 表示把 PeriphAddr 当作数据源;存储器到存储器模式下两个地址都可以递增。
3. 启动前先重映射并读取初值。 存储器到存储器模式建议把请求源重映射到保留项,随后使能传输完成中断与读取起始计数,再使能通道。
/* In memory-to-memory mode, it is recommended to set an reserved
peripheral request source in the system, otherwise the request
will be mapped to the UART1_TX. */
DMA_RequestRemap(DMA_REMAP_RESERVED, DMA, DMA_CHANNEL_USED, ENABLE);
/* Enable DMA Channel Transfer Complete interrupt */
DMA_ConfigInt(DMA_CHANNEL_USED, DMA_INT_TXC, ENABLE);
/* Get Current Data Counter value before transfer begins */
CurrDataCounterBegin = DMA_GetCurrDataCounter(DMA_CHANNEL_USED);
/* Enable DMA Channel transfer */
DMA_EnableChannel(DMA_CHANNEL_USED, ENABLE);
/* Wait the end of transmission */
while (CurrDataCounterEnd != 0)
{
}
等待剩余计数归零的 while 循环是示例的同步方式;实际工程里用中断或标志位判断传输结束更稳妥。
4. 中断读回剩余计数并清标志,主流程做校验。 DMA_IRQ_HANDLER 在传输完成时读取剩余数据个数并清全局中断标志,主流程再用 memcmp 比较源与目标数组。
void DMA_IRQ_HANDLER(void)
{
/* Test on DMA channel Transfer Complete interrupt */
if (DMA_GetIntStatus(DMA_IT_FLAG_TC, DMA))
{
/* Get Current Data Counter value after complete transfer */
CurrDataCounterEnd = DMA_GetCurrDataCounter(DMA_CHANNEL_USED);
/* Clear DMA channel Half Transfer, Transfer Complete and Global interrupt pending bits */
DMA_ClrIntPendingBit(DMA_IT_FLAG_GL, DMA);
}
}
if (memcmp(SRC_Const_Buffer, DST_Buffer, BUFFER_SIZE) == 0)
{
log_info("DMA Flash to RAM passed\n");
}
else
{
log_error("DMA Flash to RAM failed\n");
}
DMA_IRQ_HANDLER 上方的注释沿用了 SysTick_Handler 的名字,与实际函数名不一致,阅读时以函数定义为准。
对应源码: src/main.c、src/n32g033_it.c、firmware/n32g033_std_periph_driver/inc/n32g033_dma.h
5.4.4 注意与排障
| 场景 | 检查与建议 | 来源 |
|---|---|---|
| 存储器到存储器模式 | 用户手册 DMA 章写明该模式不使用外设请求,需要重映射请求源; 按手册把请求源映射到保留项,避免请求落到 UART1_TX。 |
用户手册 |
| 传输数据个数 | 用户手册 DMA 章写明传输个数须在通道使能前设置,DMA_SetCurrDataCounter 只能在通道关闭时调用;改传输长度前先关闭通道。 |
用户手册 |
| 中断与标志清除 | 用户手册 DMA 章写明全局中断状态是传输完成、半传输与传输错误三者的逻辑或; 清除三个中断状态后全局中断状态随之清除。 |
用户手册 |
| 外设时钟总线 | 用户手册 DMA 章写明 DMA 使用 AHB 时钟; 使能时钟时确认选择的是 AHB 外设位。 |
用户手册 |
勘误手册 V1.0.0(2025.9.25)针对 A 版芯片,未列出 DMA 相关条目。