灵活多通道dma扫描
使用lptmr触发adc采集,adc采集完成触发dma通道1开始传输到指定缓存,dma通道1传输完成触发链接,链接dma通道0,dma通道0将adc配置传给adc配置寄存器。这样可以灵活采集各种通道,并且对资源占用较小。只要设置好配置adc的数组,剩下的dma就会处理 原理过程如下
adc配置
使能adc中断,配置adc通道 EnableIRQ(ADC0_IRQn); ADC16_GetDefaultConfig(&adc16ConfigStruct); ADC16_Init( ADC0, &adc16ConfigStruct); ADC16_DoAutoCalibration( ADC0 ); ADC16_EnableHardwareTrigger( ADC0, true); ADC16_EnableDMA( ADC0, true); adc16ChannelConfigStruct.channelNumber = g_ADC_mux[2]; adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = true; adc16ChannelConfigStruct.enableDifferentialConversion = false; ADC16_SetChannelConfig(ADC0, 0, &adc16ChannelConfigStruct);
Lptmr配置 lptmr_config_t lptmrConfig; LPTMR_GetDefaultConfig(&lptmrConfig); lptmrConfig.bypassPrescaler = false; lptmrConfig.prescalerClockSource = kLPTMR_PrescalerClock_1; /* Initialize the LPTMR */ LPTMR_Init(LPTMR0, &lptmrConfig); /* Set the LPTimer period */ LPTMR_SetTimerPeriod( LPTMR0,USEC_TO_COUNT(200000,CLOCK_GetFreq(kCLOCK_LpoClk))); SIM->SOPT7 |=0x8EU; //配置adc硬件触发源
Dma配置 edma_transfer_config_t transferConfig_ch0; edma_transfer_config_t transferConfig_ch1; edma_config_t userConfig; /* Configure DMAMUX */ DMAMUX_Init(DMAMUX0); DMAMUX_SetSource(DMAMUX0,DMAChannel_0, 60); /* Channel 0 Source 60: DMA always enabled */ DMAMUX_EnableChannel(DMAMUX0,DMAChannel_0); DMAMUX_SetSource(DMAMUX0,DMAChannel_1, 40); /* Channel 1 Source 40: ADC COCO trigger */ DMAMUX_EnableChannel(DMAMUX0,DMAChannel_1); EDMA_GetDefaultConfig(&userConfig); userConfig.enableHaltOnError = false; EDMA_Init(DMA0, &userConfig); EDMA_CreateHandle(&g_EDMA_Handle_1,DMA0, DMAChannel_1); EDMA_SetCallback(&g_EDMA_Handle_1,EDMA_Callback_1, NULL); //设置dma通道1的adc值传到g_ADC0_resultBuffer EDMA_PrepareTransfer(&transferConfig_ch1, /* Prepare TCD for CH1 */ (uint32_t*) (ADC0->R), /* Source Address (ADC0_RA) */ sizeof(uint16_t), /* Source width (2 bytes) */ g_ADC0_resultBuffer, /*Destination Address (Internal buffer)*/ sizeof(g_ADC0_resultBuffer[0]), /* Destination width (2 bytes) */ sizeof(uint16_t), /* Bytes to transfer each minorloop (2 bytes) */ B_SIZE * 2, /* Total of bytes to transfer(12*2 bytes) */ kEDMA_PeripheralToMemory); /* From ADC to Memory */ /* Push TCD for CH1 into hardware TCD Register */ EDMA_SubmitTransfer(&g_EDMA_Handle_1,&transferConfig_ch1); //将dma通道1链接到通道0 EDMA_SetChannelLink(DMA0, DMAChannel_1, kEDMA_MinorLink, DMAChannel_0); EDMA_SetChannelLink(DMA0, DMAChannel_1, kEDMA_MajorLink,DMAChannel_0); EDMA_CreateHandle(&g_EDMA_Handle_0,DMA0, DMAChannel_0); EDMA_SetCallback(&g_EDMA_Handle_0,EDMA_Callback_0, NULL); //设置dma通道0,将adc的配置传给寄存器adc_sc1 EDMA_PrepareTransfer(&transferConfig_ch0, /* Prepare TCD for CH0 */ &g_ADC_mux[0], /*Source Address (ADC channels array) */ sizeof(g_ADC_mux[0]), /* Source width (1 bytes) */ (uint32_t*)(ADC0->SC1),/* Destination Address (ADC_SC1A_ADCH)*/ sizeof(uint8_t), /* Destination width (1 bytes) */ sizeof(uint8_t), /* Bytes to transfer each minorloop (1 bytes) */ CHANNELS, /* Total of bytes to transfer (3*1bytes) */ kEDMA_MemoryToPeripheral);/* From ADC channels array to ADCH register */ /* Push TCD for CH0 into hardware TCD Register */ EDMA_SubmitTransfer(&g_EDMA_Handle_0,&transferConfig_ch0);
//传输完后修正,通道0倒退3,通道1倒退24 DMA0->TCD[0].SLAST = -1 * CHANNELS; DMA0->TCD[1].DLAST_SGA = -2 * B_SIZE;
中断函数,以及edma的回调函数,这个程序执行一遍就结束了,如果想一直执行下去,将EDMA_Callback_1里的EDMA_StartTransfer(&g_EDMA_Handle_1);注释去掉,就可以一直运行 void ADC0_IRQHandler(void) { g_Adc16ConversionDoneFlag = true; } void EDMA_Callback_0(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds) { if (transferDone) { g_Transfer_Done_ch0 = true; } } void EDMA_Callback_1(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds) { if (transferDone) { // EDMA_StartTransfer(&g_EDMA_Handle_1); g_Transfer_Done_ch1 = true; } }
实验结果 程序见附件 参考文章:Using DMA to Emulate ADC Flexible ScanMode with SDK 2.x
|