查看: 4307|回复: 0

[原创] 【经验分享】frdm-k64 adc多路采集四连之第三连--灵活多路采集

[复制链接]

该用户从未签到

715

主题

6374

帖子

0

超级版主

Rank: 8Rank: 8

积分
25234
最后登录
2025-8-20
发表于 2020-6-12 10:16:34 | 显示全部楼层 |阅读模式
                                                                                 灵活多通道dma扫描
使用lptmr触发adc采集,adc采集完成触发dma通道1开始传输到指定缓存,dma通道1传输完成触发链接,链接dma通道0,dma通道0将adc配置传给adc配置寄存器。这样可以灵活采集各种通道,并且对资源占用较小。只要设置好配置adc的数组,剩下的dma就会处理
原理过程如下
adc1.png
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通道1adc值传到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;
    }
}

实验结果
2.PNG
程序见附件
参考文章:Using DMA to Emulate ADC Flexible ScanMode with SDK 2.x



K64F_ADC_DMA_Demo.zip

388.34 KB, 下载次数: 40, 下载积分: 威望 1

回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|恩智浦技术社区

GMT+8, 2025-8-21 13:03 , Processed in 0.086910 second(s), 20 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表