1,DMA原理图
2,功能描述
1 使能 DMA 控制器
使用 DMA 时需要先将功能时钟控制 0 寄存器 FCG0.DMAx 位写 0 允许 DMA 的时钟
供给,再将 DMA 使能寄存器 DMA_EN.EN 位写 1。 同时, DMA 需要外围电路来启动
传输,所以 FCG0.PTDIS 外设电路触发功能位也需写 0。
当不使用 DMA,或者芯片需要进入 STOP 模式时,请将 DMA_EN.EN 设定为 0,并写
FCG0 关闭 DMA 时钟。 EN 写 0 前请先确认寄存器 DMA_CHSTAT.DMAACT 为 0,确
保 DMA 已完成所有传输。
2 通道选择和通道优先级
每个 DMA 控制单元中包含 8 个通道, 每个通道可以独立配置传输功能。
8 个通道优先级顺序为:通道 0>通道 1>通道 2>...>通道 7。
当一个 DMA 单元有多个通道请求传输时将按照优先级顺序执行。 但已处于传输中的
通道不会被打断,高优先通道需等当前通道传输完成后才会启动。
3 启动 DMA
DMA 通 过 外 围 电 路 产 生 的 请 求 启 动 , 这 些 请 求 通 过 触 发 源 选 择 寄 存 器
DMA_TRGSELx(x=0~7)进行配置,可以配置通道 x 的启动请求源。当外围电路产生启
动请求或软件写寄存器产生启动请求时, 并且 DMA 传输使能有效 DMA_EN.EN=1,
传输通道处于许可状态 DMA_CHEN.CHEN[x]=1,则启动通道 x 传输。
使用前,需要先将功能时钟控制 0 寄存器(FCG0)的外设电路触发功能及 DMA 功能使
能位置为有效。
4 数据块
DMA 每 次 启 动 传 输 的 数 据 量 用 块 (block) 表 示 , 块 的 大 小 由 数 据 控 制 寄 存 器
DMA_DTCTLx.BLKSIZE 设定, 最大可以设置 1024 个数据。 每个的数据宽度由
DMA_CHCTLx.HIZE 决定。
5 传输地址控制
传输的源地址和目标地址可以由寄存器设定为固定、递增、递减、 重载或者不连续跳
转。
固定: 源地址、 目标地址将在传输过程中固定不变。
递增及递减: 源地址、 目标地址将在每传输完成 1 个数据后根据 HSIZE 的值向前或向
后跳转。例如当 HSIZE 为 8bit 时,地址将每次增加/减少 1, 为 16bit 时每次增加/减少
2, 为 32bit 时每次增加/减少 4。
重载: 传输指定数量的数据后, 源、 目标地址将重新返回至最初的地址设定值。 地址
重载前需要传输的数据量,即重复区域的大小由寄存器 DMA_RPT 设定。
不连续地址传输: 传输指定数量的数据后, 源、 目标地址将跳过指定偏移量。地址跳
转的偏移量,以及跳转前需要传输的数据量,即不连续 区域的大小,由寄存器
DMA_SNSEQCTL/DMA_DNSEQCTL 设定。 当地址重载与不连续跳转的条件同时满足
时,执行地址重载。
6 传输次数
DMA 传输的总数据块的个数由数据控制寄存器 DMA_DTCTLx 的 CNT 位设定。传输
次数最多可设置 65535 次。 每传输一个数据块寄存器值减 1, 当寄存器值减为 0 时代
表本通道全部数据传输完成, 自动清除通道传输许可位 DMA_CHEN.CHEN[x],并产
生传输完成中断。 如果传输开始时 DMA_DTCTLx.CNT 被设为 0,表示无限次传输,
每次启动请求传输一个数据块, 但不清除通道传输许可位,也不会产生传输完成中断。
7 中断和事件信号输出
DMA 控制器可以产生以下 3 种中断:
数据块完成中断 DMA_BTCx: 完成一个数据块传输后产生。
传输完成中断 DMA_TCx: 完成寄存器 DMA_DTCTLx.CNT 设置的传输次数后产生。
传输错误中断 DMA_ERR: 当启动请求溢出(即通道的上一次请求还未响应时此通道
再次触发启动请求)时,或者, 传输过程中总线发生错误时产生此中断。其中,总线
错误时会同时终止传输并将该通道传输许可位 DMA_CHEN.CHEN[x]清零。
以上中断除了启动请求溢出错误外,其他中断都可以通过寄存器 DMA_CHCTLx.IE 设
置中断的有效或无效。 另外所有中断还配有独立的 MASK 寄存器,对中断进行屏蔽。
上述的 DMA_BTCx, DMA_TCx 中断同时也可以作为事件信号输出,可用作其它外围
电路的触发源,事件输出受 MASK 寄存器控制,但不受中断许可位 DMA_CHCTLx.IE
控制。 DMA_BTCx, DMA_TCx, DMA_ERR 事件发生会将对应的状态位寄存器置位,
不受 DMA_CHCTLx.IE、或 MASK 寄存器影响。
3,寄存器说明:
寄存器介绍
1) DMA_EN: DMA 使能寄存器,使能或关闭 DMA 模块。
2) DMA_CHEN:通道使能寄存器,使能或关闭 DMA 通道, bit0~3 分别对应一个通道。
3) DMA_INSTAT0~1:中断状态寄存器(传输请求溢出错误中断、传输错误中断、块传输完
成中断、传输完成中断)。
4) DMA_INTMASK0~1:中断屏蔽寄存器,配置各中断是否屏蔽。
5) DMA_INTCLR0~1:中断复位寄存器,清空中断状态标志位。
应用笔记 Page 5 of 13
6) DMA_RCFGCTL:通道重置寄存器,配置 DMA 重置后的相关参数,包括:剩余传输次数
计数方式、目标/源地址重置方式、通道选择、链式传输等。
7) DMA_CHSTAT: 通道状态观测寄存器。
8) DMA_TRGSEL0~3:触发源选择寄存器,配置各通道启动传输的触发源,配置前需打开
PWR_FCG0 寄存器的 AOS 位。
9) DMA_TRGSELRC:通道重置触发源选择寄存器,配置启动通道重置的触发源。
10) DMA_SAR0~3:源地址寄存器,配置传输源地址。
11) DMA_DAR0~3:目标地址寄存器,配置传输目标地址。
12) DMA_DTCTL0~3:数据控制寄存器,配置传输次数和数据块大小。
13) DMA_RPT0~3:重复区域大小寄存器,配置源地址和目标地址重复区域大小。
14) DMA_RPTBB0~3: 重复区域大小寄存器 B,配置源地址和目标地址重复区域大小。
15) DMA_SNSEQCTL0~3: 源设备不连续地址传输控制寄存器,配置源地址跳转的地址偏移和
源地址跳转的数据量
16) DMA_SNSEQCTLB0~3: 源设备不连续地址传输控制寄存器 B,配置源不连续区域地址间
距和源地址跳转的数据量
17) DMA_DNSEQCTL0~3: 目标设备不连续地址传输控制寄存器,配置目标地址跳转的地址偏
移量和数据量
18) DMA_DNSEQCTLB0~3: 目标设备不连续地址传输控制寄存器 B,配置目标不连续区域地
址间距和目标地址跳转数据量
19) DMA_LLP0~3: 链指针寄存器,配置链指针
20) DMA_CHxCTL(x=0~3):通道控制寄存器
21) DMA_MONSARx , DMA_MONDARx , DMA_MONDTCTLx , DMA_MONRPTx ,
DMA_MONSNSEQCTLx, DMA_MONDNSEQCTLx:通道监视寄存器, DMA 每完成一
次传输请求后更新.
4,该传输可以配置源地址、目标地址在增加/减少至寄存器配置的重复区域大小时重新返回至
最初的地址设定值。重复区域的大小由寄存器 DMA_RPT 和 DMA_CHxCTL.HSIZE 的设定
值决定。
#include "hc32_ddl.h"
#define DDL_ON (1U)
#define DDL_OFF (0U)
#define DDL_ICG_ENABLE (DDL_ON)
#define DDL_UTILITY_ENABLE (DDL_ON)
#define DDL_PRINT_ENABLE (DDL_OFF)
#define DDL_ADC_ENABLE (DDL_OFF)
#define DDL_AES_ENABLE (DDL_OFF)
#define DDL_CAN_ENABLE (DDL_OFF)
#define DDL_CLK_ENABLE (DDL_ON)
#define DDL_CMP_ENABLE (DDL_OFF)
#define DDL_CRC_ENABLE (DDL_OFF)
#define DDL_CTC_ENABLE (DDL_OFF)
#define DDL_DAC_ENABLE (DDL_OFF)
#define DDL_DCU_ENABLE (DDL_OFF)
#define DDL_DMA_ENABLE (DDL_ON)
#define DDL_DMC_ENABLE (DDL_OFF)
#define DDL_DVP_ENABLE (DDL_OFF)
#define DDL_EFM_ENABLE (DDL_ON)
#define DDL_EMB_ENABLE (DDL_OFF)
#define DDL_ETH_ENABLE (DDL_OFF)
#define DDL_EVENT_PORT_ENABLE (DDL_OFF)
#define DDL_FCM_ENABLE (DDL_OFF)
#define DDL_FMAC_ENABLE (DDL_OFF)
#define DDL_GPIO_ENABLE (DDL_ON)
#define DDL_HASH_ENABLE (DDL_OFF)
#define DDL_HRPWM_ENABLE (DDL_OFF)
#define DDL_I2C_ENABLE (DDL_ON)
#define DDL_I2S_ENABLE (DDL_OFF)
#define DDL_INTERRUPTS_ENABLE (DDL_ON)
#define DDL_KEYSCAN_ENABLE (DDL_ON)
#define DDL_MAU_ENABLE (DDL_OFF)
#define DDL_MPU_ENABLE (DDL_OFF)
#define DDL_NFC_ENABLE (DDL_OFF)
#define DDL_OTS_ENABLE (DDL_OFF)
#define DDL_PWC_ENABLE (DDL_ON)
#define DDL_QSPI_ENABLE (DDL_OFF)
#define DDL_RMU_ENABLE (DDL_OFF)
#define DDL_RTC_ENABLE (DDL_OFF)
#define DDL_SDIOC_ENABLE (DDL_OFF)
#define DDL_SMC_ENABLE (DDL_OFF)
#define DDL_SPI_ENABLE (DDL_OFF)
#define DDL_SRAM_ENABLE (DDL_ON)
#define DDL_SWDT_ENABLE (DDL_OFF)
#define DDL_TMR0_ENABLE (DDL_OFF)
#define DDL_TMR2_ENABLE (DDL_OFF)
#define DDL_TMR4_ENABLE (DDL_OFF)
#define DDL_TMR6_ENABLE (DDL_OFF)
#define DDL_TMRA_ENABLE (DDL_OFF)
#define DDL_TRNG_ENABLE (DDL_OFF)
#define DDL_USART_ENABLE (DDL_OFF)
#define DDL_USBFS_ENABLE (DDL_OFF)
#define DDL_USBHS_ENABLE (DDL_OFF)
#define DDL_WDT_ENABLE (DDL_OFF)
#define BSP_ON (1U)
#define BSP_OFF (0U)
#define DMA_UNIT (M4_DMA2)
#define DMA_CH (DMA_CH4)
#define DMA_MX_CH (DMA_MX_CH0)
#define DMA_TC (4UL)
#define DMA_BC (5UL)
#define DMA_DW (DMA_DATAWIDTH_32BIT)
#define DMA_INT_SRC (INT_DMA2_TC4)
#define DMA_IRQn (Int000_IRQn)
static en_flag_status_t m_u8DmaTcEnd = Reset;
static const uint32_t u32SrcBuf[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
static uint32_t u32DestBuf[20] = {0};
static uint32_t u32ExpectDestBufData[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20};
static void Peripheral_WE(void)
{
GPIO_Unlock();
PWC_FCG0_Unlock();
PWC_Unlock(PWC_UNLOCK_CODE_0);
SRAM_WTCR_Unlock();
EFM_Unlock();
}
static void Peripheral_WP(void)
{
GPIO_Lock();
PWC_FCG0_Lock();
PWC_Lock(PWC_UNLOCK_CODE_0);
SRAM_WTCR_Lock();
EFM_Lock();
}
static void DmaInit(void)
{
stc_dma_init_t stcDmaInit;
DMA_SetTriggerSrc(DMA_UNIT, DMA_CH, EVT_AOS_STRG);
(void)DMA_StructInit(&stcDmaInit);
stcDmaInit.u32IntEn = DMA_INT_ENABLE;
stcDmaInit.u32BlockSize = DMA_BC;
stcDmaInit.u32TransCnt = DMA_TC;
stcDmaInit.u32DataWidth = DMA_DW;
stcDmaInit.u32DestAddr = (uint32_t)(&u32DestBuf[0]);
stcDmaInit.u32SrcAddr = (uint32_t)(&u32SrcBuf[0]);
stcDmaInit.u32SrcInc = DMA_SRC_ADDR_INC;
stcDmaInit.u32DestInc = DMA_DEST_ADDR_INC;
(void)DMA_Init(DMA_UNIT, DMA_CH, &stcDmaInit);
}
static void DMA2_CH4_TransEnd_IrqCallback(void)
{
m_u8DmaTcEnd = Set;
DMA_ClearTransIntStatus(DMA_UNIT, DMA_TC_INT_CH4);
}
static void DmaIntInit(void)
{
stc_irq_signin_config_t stcIrqSignConfig;
stcIrqSignConfig.enIntSrc = DMA_INT_SRC;
stcIrqSignConfig.enIRQn = DMA_IRQn;
stcIrqSignConfig.pfnCallback= &DMA2_CH4_TransEnd_IrqCallback;
(void)INTC_IrqSignIn(&stcIrqSignConfig);
DMA_ClearTransIntStatus(DMA_UNIT, DMA_TC_INT_CH4);
NVIC_ClearPendingIRQ(DMA_IRQn);
NVIC_SetPriority(DMA_IRQn,DDL_IRQ_PRIORITY_DEFAULT);
NVIC_EnableIRQ(DMA_IRQn);
}
int32_t main(void)
{
Peripheral_WE();
BSP_CLK_Init();
BSP_IO_Init();
BSP_LED_Init();
PWC_Fcg0PeriphClockCmd((PWC_FCG0_DMA2 | PWC_FCG0_AOS), Enable);
Peripheral_WP();
DmaInit();
DmaIntInit();
DMA_Cmd(DMA_UNIT, Enable);
DMA_ChannelCmd(DMA_UNIT, DMA_CH, Enable);
AOS_SW_Trigger();
while (Reset == m_u8DmaTcEnd)
{
AOS_SW_Trigger();
}
if (0 != memcmp(u32DestBuf, u32ExpectDestBufData, sizeof(u32DestBuf)))
{
BSP_LED_On(LED_RED);
}
else
{
BSP_LED_On(LED_BLUE);
}
for (;;)
{
;
}
}