简介
HC32F460用户手册中的简介如下
注意:
- 每一个DMA控制单元有4个通道
- 单个数据块最大1024个数据,每个数据的宽度可选8、16、32位。也就是说单个数据块的数据容量最大为4KB。
- 一次触发传输一个数据块,之后地址按照配置自增、重载、倒退或者跳转。
- 每一次传输都会使得计数值减1,当减到0的时候DMA失效,需要重新使能。
- 每一次触发传输一个数据块,引起一次块传输中断。计数值减为0的时候引起一次块传输中断和一次传输完成中断。
- 可以设置重复区域限制Repeat Size,当DMA自增访问到重复区域限制的时候自动重载目的地址。
DMA数据访问范围
所有外设和RAM均可达
示例,寄存器到数组
初步实现
内存中模拟一个寄存器和数组,将寄存器中的数据复制到数组中,每次DMA传输一个字节,一共传输4个字节
#define TEST_DMA_UNIT (M4_DMA1)
#define TEST_DMA_CLOCK_UNIT (PWC_FCG0_PERIPH_DMA1)
#define TEST_DMA_CHANNEL (DmaCh0)
#define TEST_DMA_TRIG_SOURCE (EVT_AOS_STRG)
uint8_t __attribute__((aligned(4))) SImulate_REG_SRC = 0xB0;
uint8_t __attribute__((aligned(4))) SImulate_DST_BUF[100] = {0};
static void BSP_DMA_Init(void)
{
stc_dma_config_t stcDmaCfg;
MEM_ZERO_STRUCT(stcDmaCfg);
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
PWC_Fcg0PeriphClockCmd(TEST_DMA_CLOCK_UNIT, Enable);
stcDmaCfg.u16BlockSize = 1u; //1个数据块里有1个数据
stcDmaCfg.u16TransferCnt = 4u; //最多传输4个数据块
stcDmaCfg.u32SrcAddr = (uint32_t)(&SImulate_REG_SRC); //源地址
stcDmaCfg.u32DesAddr = (uint32_t)(&SImulate_DST_BUF); //目的地址
stcDmaCfg.stcDmaChCfg.enSrcInc = AddressFix; //源地址不变
stcDmaCfg.stcDmaChCfg.enDesInc = AddressIncrease; //目的地址自增
stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma8Bit; //一个数据的宽度为8位
stcDmaCfg.stcDmaChCfg.enIntEn = Disable; //不使用中断
stcDmaCfg.stcDmaChCfg.enDesRptEn = Disable; //不使用重复区域限制
DMA_InitChannel(TEST_DMA_UNIT, TEST_DMA_CHANNEL, &stcDmaCfg);
DMA_SetTriggerSrc(TEST_DMA_UNIT, TEST_DMA_CHANNEL, TEST_DMA_TRIG_SOURCE); //设置触发源为AOS中的软件触发
DMA_Cmd(TEST_DMA_UNIT, Enable);
DMA_ChannelCmd(TEST_DMA_UNIT, TEST_DMA_CHANNEL, Enable);
}
void entry_task1(void *pvParameters)
{
while(1)
{
SImulate_REG_SRC++; //源数据变化一次
AOS_SW_Trigger(); //触发一次
vTaskDelay(500);
}
}
再上面的while1里打断点,手动控制逐次trigger,可以观察到现象如下
trigger -> {0xB1, 0x00, 0x00, 0x00, 0x00}
trigger -> {0xB1, 0xB2, 0x00, 0x00, 0x00}
trigger -> {0xB1, 0xB2, 0xB3, 0x00, 0x00}
trigger -> {0xB1, 0xB2, 0xB3, 0xB4, 0x00}
trigger -> {0xB1, 0xB2, 0xB3, 0xB4, 0x00} //计数清0,trigger不再生效
绑定中断
增加中断相关宏定义和回调函数如下
/* DMA block transfer complete interrupt */
#define DMA_BTC_INT_NUM (INT_DMA1_BTC0)
#define DMA_BTC_INT_IRQn (Int004_IRQn)
#define DMA_TC_INT_NUM (INT_DMA1_TC0)
#define DMA_TC_INT_IRQn (Int005_IRQn)
static void DmaBtcIrqCallback(void);
static void DmaTcIrqCallback(void);
static void DmaBtcIrqCallback(void)
{//块传输中断
DMA_ClearIrqFlag(TEST_DMA_UNIT, TEST_DMA_CHANNEL, BlkTrnCpltIrq);
}
static void DmaTcIrqCallback(void)
{//传输完成中断
DMA_ClearIrqFlag(TEST_DMA_UNIT, TEST_DMA_CHANNEL, TrnCpltIrq);
}
DMA初始化代码修改为使用中断
stcDmaCfg.stcDmaChCfg.enIntEn = Enable; //使用中断
DMA初始化末尾增加如下代码
stc_irq_regi_conf_t stcIrqRegiCfg;
/* Set DMA block transfer complete IRQ */
stcIrqRegiCfg.enIRQn = DMA_BTC_INT_IRQn; //块传输中断
stcIrqRegiCfg.pfnCallback = &DmaBtcIrqCallback;
stcIrqRegiCfg.enIntSrc = DMA_BTC_INT_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/* Set DMA transfer complete IRQ */
stcIrqRegiCfg.enIRQn = DMA_TC_INT_IRQn; //传输完成中断
stcIrqRegiCfg.pfnCallback = &DmaTcIrqCallback;
stcIrqRegiCfg.enIntSrc = DMA_TC_INT_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
再while(1)中打断点,再块传输中断和传输完成中断打断点,现象如下
trigger -> {0xB1, 0x00, 0x00, 0x00, 0x00} ,块传输中断BTC
trigger -> {0xB1, 0xB2, 0x00, 0x00, 0x00},块传输中断BTC
trigger -> {0xB1, 0xB2, 0xB3, 0x00, 0x00},块传输中断BTC
trigger -> {0xB1, 0xB2, 0xB3, 0xB4, 0x00},块传输中断BTC,传输完成中断TC
trigger -> {0xB1, 0xB2, 0xB3, 0xB4, 0x00} //计数清0,trigger不再生效