四、DMA配置一、开启时钟,设置触发源 华大半导体的HC32F4A0和国内惯用的STM32F4xx相比,其中一个显著的设计区别是HC32F4A0有一个AOS外设,用于硬件之间的联动。详见用户手册第11章及相关章节。
本例涉及到的ADC和DMA的联动功能也集成在该外设中。——而我们知道STM32和DMA联动的外设都设有专门的寄存器,ADC想要使用DMA就得配置ADC外设中与DMA联动的寄存器——由于使用了DMA和AOC两个外设,我们需要把它们的时钟都开启。然后开启“ADC传输完毕->DMA开始传输”联动。
/* * Definitions of DMA. * 'APP_DMA_BLOCK_SIZE': 1~1024, inclusive. 1~16 for ADC1 and ADC2; 1~20 for ADC3. * 'APP_DMA_TRANS_COUNT': 0~65535, inclusive. 0: always transmit. */ #define ADC_DMA_UNIT (M4_DMA2) #define ADC_DMA_CH (DMA_CH0) #define ADC_DMA_PERIP_CLK (PWC_FCG0_DMA2) #define ADC_DMA_BLOCK_SIZE (8U) #define ADC_DMA_TRANS_COUNT (1U) #define ADC_DMA_DATA_WIDTH (DMA_DATAWIDTH_16BIT) #define ADC_DMA_TRIG_SRC (EVT_ADC1_EOCA) #define ADC_DMA_SRC_ADDR (&M4_ADC1->DR0)
/******************************************************************************* * Local variable definitions ('static') ******************************************************************************/ static uint16_t m_au16AdcSaVal[ADC_DMA_BLOCK_SIZE];
/* Enable DMA peripheral clock and AOS function. */ PWC_Fcg0PeriphClockCmd((ADC_DMA_PERIP_CLK | PWC_FCG0_AOS), Enable); DMA_SetTriggerSrc(ADC_DMA_UNIT, ADC_DMA_CH, ADC_DMA_TRIG_SRC);
下面进行DMA初始化配置:
stc_dma_init_t stcDmaInit; (void)DMA_StructInit(&stcDmaInit); stcDmaInit.u32IntEn = DMA_INT_DISABLE; stcDmaInit.u32BlockSize = ADC_DMA_BLOCK_SIZE; stcDmaInit.u32TransCnt = ADC_DMA_TRANS_COUNT; stcDmaInit.u32DataWidth = ADC_DMA_DATA_WIDTH; stcDmaInit.u32DestAddr = (uint32_t)(&m_au16AdcSaVal[0U]); stcDmaInit.u32SrcAddr = (uint32_t)ADC_DMA_SRC_ADDR; stcDmaInit.u32SrcInc = DMA_SRC_ADDR_INC; stcDmaInit.u32DestInc = DMA_DEST_ADDR_INC; (void)DMA_Init(ADC_DMA_UNIT, ADC_DMA_CH, &stcDmaInit);
- 不开启DMA中断
- 数据块大小为8,表示8个通道即8个模拟量。
- 传输次数为1
- 每个数据位宽为16位
- 目标起始地址
- 源起始地址
- 目标地址自增
- 源目标地址自增
HC32F4A0每个通道都有对应的数据寄存器,且地址连续,而STM32每个ADC就只有一个数据寄存器。所以这里源地址和目标地址同步自增。
这样在前面第三节我们重映射通道的意义就体现了出来。前面映射到了CH0-7,这样数据寄存器的地址就是连续的,配置DMA就方便的多。
按理后面只要开启DMA通道和DMA使能,最后再ADC使能就可以工作了。
DMA_Cmd(ADC_DMA_UNIT, Enable); DMA_ChannelCmd(ADC_DMA_UNIT, ADC_DMA_CH, Enable);
ADC_Start(APP_ADC_UNIT);
DMA由ADC触发,ADC序列A转换完毕后,触发DMA传输,DMA传输一次后停止,等待下一次触发。但是在实际运行中,DMA传完一次后就不传了。
官方例程使用DMA时,在其初始化后还有以下一段代码
(void)DMA_RepeatStructInit(&stcDmaRptInit); stcDmaRptInit.u32SrcRptEn = DMA_SRC_RPT_ENABLE; stcDmaRptInit.u32SrcRptSize = ADC_DMA_BLOCK_SIZE; stcDmaRptInit.u32DestRptEn = DMA_DEST_RPT_ENABLE; stcDmaRptInit.u32DestRptSize = ADC_DMA_BLOCK_SIZE; (void)DMA_RepeatInit(ADC_DMA_UNIT, ADC_DMA_CH, &stcDmaRptInit);
并且
#define ADC_DMA_TRANS_COUNT (0U)
对比用户手册,发现该段代码主要操作了下列寄存器这些位:
且初始化时传输次数被设为0。
测试发现可以连续传输了。用户手册在DMA章节的功能描述和应用举例小节太春秋笔法。
|