查看: 1130|回复: 0

[分享] LPC5516_SDK例程ADC_2Msps高速采集

[复制链接]
  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3298

    主题

    6545

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32018
    最后登录
    2024-4-9
    发表于 2023-1-17 09:40:29 | 显示全部楼层 |阅读模式
    LPC5516_SDK例程ADC_2Msps高速采集


    最近支持一个客户,需要在LPC5516下实现ADC 2Msps高速采集,根据数据手册描述:
    11.png
    ADC在12-bit模式下最高可以达到2.3Msps
    ADC在16-bit模式下最高可以达到2.0Msps.
    那么实际情况是否真如数据手册所述,能达到如此高的转换速率呢?小编这次就编写了测试代码进行了实测,结果为:
    12-bit模式下ADC最快可达2.326Msps,  16-bit模式下2.083Msps, 结果还是和数据手册很吻合的。

    代码设计
    代码基于SDK的例程:
    \SDK_2_12_0_LPCXpresso55S16\boards\lpcxpresso55s16\driver_examples\lpadc\dma
    修改:
    1. 为了实现最快速度ADC采集,我们需要将ADC配置为:
    ADC输入时钟: ADCCLK = 48MHz
    无硬件平均: HWAVG=1
    ADC采样时长设置为最短3xCLK:  STS=0
    ADC功率最大: PWRSEL=3


    除此之外,还需要将ADC设置为连续转换模式:即将g_LpadcCommandConfigStruct.chainedNextCommandNumber指向自己,即完成当前转换后,自动开始下次转换。


    以上所有配置对应SDK代码如下:
    1. /* Configure ADC. */
    2.     LPADC_GetDefaultConfig(&lpadcConfigStruct);
    3.     lpadcConfigStruct.enableAnalogPreliminary = true;
    4.     lpadcConfigStruct.conversionAverageMode = kLPADC_ConversionAverage1;
    5.     lpadcConfigStruct.powerLevelMode=kLPADC_PowerLevelAlt4;
    6.     lpadcConfigStruct.referenceVoltageSource = DEMO_LPADC_VREF_SOURCE;
    7.     lpadcConfigStruct.FIFO0Watermark = 2;
    复制代码
    1.    LPADC_GetDefaultConvCommandConfig(&g_LpadcCommandConfigStruct);
    2.     g_LpadcCommandConfigStruct.channelNumber = DEMO_LPADC_USER_CHANNEL;
    3.     g_LpadcCommandConfigStruct.sampleTimeMode = kLPADC_SampleTimeADCK3;
    4.     g_LpadcCommandConfigStruct.loopCount = 1;
    5.     g_LpadcCommandConfigStruct.conversionResolutionMode = kLPADC_ConversionResolutionHigh;
    6.   // g_LpadcCommandConfigStruct.conversionResolutionMode =kLPADC_ConversionResolutionStandard;
    7.     g_LpadcCommandConfigStruct.chainedNextCommandNumber = DEMO_LPADC_USER_CMDID;
    复制代码
    2. 配置DMA,使用DMA  Ping-Pang buffer接收ADC数据,即定义两个DMA描述符,A和B:A传输完成后自动触发B,B传输完成后自动触发A。对应SDK代码为:
    1.   SDK_ALIGN(uint32_t s_dma_table[DMA_DESCRIPTOR_NUM * sizeof(dma_descriptor_t)], FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE);
    2. 2.
    3. 3.   const uint32_t g_XferConfig =
    4. 4.      DMA_CHANNEL_XFER(true,                         /* Reload linkdescriptor after current exhaust, */
    5. 5.                      true,                         /* Clear trigger status.*/
    6. 6.                      true,                         /* Enable interruptA. */
    7. 7.                      false,                        /* Not enable interruptB. */
    8. 8.                      sizeof(uint32_t),           /* Dma transfer width. */
    9. 9.                      kDMA_AddressInterleave0xWidth, /* Dma source address no interleave */
    10. 10.                      kDMA_AddressInterleave1xWidth, /* Dma destination address nointerleave  */
    11. 11.                      sizeof(uint32_t)*ADC_DMA_SIZE              /* Dma transfer byte. */
    复制代码
    1. static void DMA_Configuration(void)
    2. {
    3.     dma_channel_config_t dmaChannelConfigStruct;
    4. #if defined (DEMO_DMA_HARDWARE_TRIGGER) && DEMO_DMA_HARDWARE_TRIGGER
    5.     /* Configure INPUTMUX. */
    6.     INPUTMUX_Init(DEMO_INPUTMUX_BASE);
    7.     INPUTMUX_AttachSignal(DEMO_INPUTMUX_BASE, DEMO_DMA_ADC_CHANNEL, DEMO_DMA_ADC_CONNECTION);
    8. #endif /* DEMO_DMA_HARDWARE_TRIGGER */

    9.     /* Configure DMA. */
    10.     DMA_Init(DEMO_DMA_BASE);
    11.     DMA_EnableChannel(DEMO_DMA_BASE, DEMO_DMA_ADC_CHANNEL);
    12.     DMA_CreateHandle(&g_DmaHandleStruct,  DEMO_DMA_BASE,  DEMO_DMA_ADC_CHANNEL);
    13.     DMA_SetCallback(&g_DmaHandleStruct, DEMO_DMA_Callback, NULL);


    14.     /* Prepare and submitthe transfer. */
    15.     DMA_PrepareChannelTransfer(&dmaChannelConfigStruct,             /* DMA channel transfer configuration structure. */
    16.                               (void *)DEMO_LPADC_RESFIFO_REG_ADDR,  /* DMA transfer source address.*/
    17.                               (void *)adc_result,             /* DMA transfer destination address. */
    18.                               g_XferConfig,                        /* Xfer configuration */
    19.                              kDMA_PeripheralToMemory,               /* DMAtransfer type. */
    20.                               NULL,                                /*DMA channel trigger configurations. */
    21.                               (dma_descriptor_t *)&(s_dma_table[0]) /* Address of next descriptor. */

    22.     );
    23.     DMA_SubmitChannelTransfer(&g_DmaHandleStruct, &dmaChannelConfigStruct);

    24.     /* Set two DMAdescripters to use ping-pong mode.  */
    25.     DMA_SetupDescriptor((dma_descriptor_t *)&(s_dma_table[0]), g_XferConfig, (void *)DEMO_LPADC_RESFIFO_REG_ADDR, (void *)adc_result, (dma_descriptor_t *)&(s_dma_table[4]));
    26.     DMA_SetupDescriptor((dma_descriptor_t *)&(s_dma_table[4]), g_XferConfig, (void *)DEMO_LPADC_RESFIFO_REG_ADDR, (void *)adc_result, (dma_descriptor_t *)&(s_dma_table[0]));

    27. }
    复制代码
    3. 最后小编还使能了SysTick定时器用于记录转换时间,程序开始运行后,ADC会启动连续转换,DMA设置为传输100次ADC转换结果后触发DMA完成中断,  DMA中断触发后(传输完成),程序会统计ADC转换时间,计算ADC转换结果的平均值和标准差,以及打印转换结果。

    代码清单


    最后为大家呈上完整代码清单(可以直接复制到lpadc_dma.c里运行):
    1. /*
    2. * Copyright 2018-2021 NXP
    3. * All rights reserved.
    4. *
    5. *
    6. * SPDX-License-Identifier: BSD-3-Clause
    7. */

    8. #include "pin_mux.h"
    9. #include "clock_config.h"
    10. #include "board.h"
    11. #include "fsl_debug_console.h"
    12. #include "fsl_dma.h"
    13. #include "fsl_inputmux.h"
    14. #include "fsl_lpadc.h"
    15. #include "stdio.h"
    16. #include "math.h"
    17. #include "fsl_power.h"
    18. #include "fsl_anactrl.h"
    19. /*******************************************************************************
    20. * Definitions

    21. ******************************************************************************/
    22. #define PF(a)   ((a) * (a))
    23. #define DEMO_LPADC_BASE                  ADC0
    24. #define DEMO_LPADC_USER_CHANNEL          0U
    25. #define DEMO_LPADC_USER_CMDID            1U /* CMD1 */
    26. #define DEMO_LPADC_VREF_SOURCE           kLPADC_ReferenceVoltageAlt2
    27. #define DEMO_LPADC_DO_OFFSET_CALIBRATION true
    28. #define DEMO_LPADC_RESFIFO_REG_ADDR      (uint32_t)(&(ADC0->RESFIFO[0]))
    29. #define DEMO_RESULT_FIFO_READY_FLAG      kLPADC_ResultFIFO0ReadyFlag

    30. #define DEMO_DMA_BASE          DMA0
    31. #define DEMO_DMA_ADC_CHANNEL   21U
    32. #define DMA_DESCRIPTOR_NUM 2U
    33. #define ADC_DMA_SIZE        (100)

    34. static void ADC_Configuration(void);
    35. static void DMA_Configuration(void);

    36. lpadc_conv_command_config_t g_LpadcCommandConfigStruct; /*
    37. Structure to configure conversion command. */

    38. dma_handle_t g_DmaHandleStruct;              /* Handler structure for using DMA. */
    39. uint32_t adc_result[ADC_DMA_SIZE];                 /* Keep the ADC conversion resulut moved from ADC data register by DMA. */
    40. static double adc_sum;
    41. static double adc_mean, adc_std;
    42. static double adc_sum_sqrt;

    43. volatile bool g_DmaTransferDoneFlag = false; /* Flag of DMA transfer done trigger by ADC conversion. */
    44. /* DMA descripter table used for ping-pong mode. */
    45. SDK_ALIGN(uint32_t s_dma_table[DMA_DESCRIPTOR_NUM * sizeof(dma_descriptor_t)], FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE);
    46.           const uint32_t g_XferConfig =    DMA_CHANNEL_XFER(true,                          /* Reload link descriptor after current exhaust, */
    47.                     true,                          /* Clear trigger status. */
    48.                     true,                          /* Enable interruptA. */
    49.                     false,                         /* Not enable interruptB. */
    50.                     sizeof(uint32_t),            /* Dma transfer width. */
    51.                     kDMA_AddressInterleave0xWidth, /* Dma source address no interleave  */
    52.                     kDMA_AddressInterleave1xWidth, /* Dma destination address no interleave  */
    53.                     sizeof(uint32_t)*ADC_DMA_SIZE               /* Dma transfer byte. */
    54.    );

    55. const uint32_t g_LpadcFullRange   = 65536U;
    56. const uint32_t g_LpadcResultShift = 0U;

    57.                     void DEMO_DMA_Callback(dma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
    58. {
    59.    //printf("DEMO_DMA_Callback\r\n");
    60.    if (true == transferDone)
    61.    {
    62.        g_DmaTransferDoneFlag = true;
    63.    }
    64. }

    65. int main(void)
    66. {
    67.    /* Initialize board hardware. */
    68.    /* set BOD VBAT level to 1.65V */
    69.    POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false);
    70.    /* attach main clock divide to FLEXCOMM0 (debug console) */    CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);    BOARD_InitBootPins();    BOARD_InitBootClocks();    BOARD_InitDebugConsole();    /* Set clock source for ADC0 */    CLOCK_SetClkDiv(kCLOCK_DivAdcAsyncClk, 2U, true);    CLOCK_AttachClk(kFRO_HF_to_ADC_CLK);    /* Disable LDOGPADC power down */    POWER_DisablePD(kPDRUNCFG_PD_LDOGPADC);    ANACTRL_Init(ANACTRL);    ANACTRL_EnableVref1V(ANACTRL, true);    PRINTF("LPADC DMA Example\r\n");    PRINTF("ADC CLK:%d\r\n", CLOCK_GetAdcClkFreq());    PRINTF("CORE CLK:%d\r\n", CLOCK_GetCoreSysClkFreq());        /* Configure peripherals. */    DMA_Configuration();    ADC_Configuration();    PRINTF("ADC Full Range: %d\r\n", g_LpadcFullRange);    PRINTF("ADCResolution: %dbit\r\n", (g_LpadcCommandConfigStruct.conversionResolutionMode == kLPADC_ConversionResolutionStandard)?(12):(16));            SysTick_Config(0xFFFFFF);    int tick;    PRINTF("Please press any key to trigger the conversion.\r\n");    while (1)    {        /* Get the input from terminal and trigger the converter by software. */        GETCHAR();        g_DmaTransferDoneFlag = false;                LPADC_DoSoftwareTrigger(DEMO_LPADC_BASE, 1UL); /* Trigger the ADC and start the conversion. */        DMA_StartTransfer(&g_DmaHandleStruct); /* Enable the DMA every time for each transfer. */                tick = SysTick->VAL;        /* Wait for the converter & transfer to be done. */        while (false == g_DmaTransferDoneFlag) {};        tick = tick - SysTick->VAL;        tick = tick / (CLOCK_GetCoreSysClkFreq() / (1000*1000));        printf("%-16s%dus(%.3fMS/s)\r\n",     "TIME:",      tick, (1 / (float)tick)*ADC_DMA_SIZE);                int i;        adc_sum = 0;        adc_sum_sqrt = 0;        for(i=0; i<ADC_DMA_SIZE; i++)        {            adc_result[i] = ((uint16_t)(adc_result[i] & ADC_RESFIFO_D_MASK) >> g_LpadcResultShift);            adc_sum += (float)adc_result[i];            adc_sum_sqrt += (adc_result[i]*adc_result[i]);                       // PRINTF("ADC[%d]:%d\r\n", i, adc_result[i]);        }               // printf("SUM:%.2f\r\n", adc_sum);      //  printf("SSUM:%.2f\r\n", adc_sum_sqrt);        adc_mean = adc_sum / ADC_DMA_SIZE;        adc_std  = (adc_sum_sqrt -  PF(adc_sum)/ADC_DMA_SIZE) / (ADC_DMA_SIZE-1);        adc_std  = sqrt(adc_std);                printf("%-16s%f\r\n",     "AVG :",      adc_mean);        printf("%-16s%f\r\n",     "STD :",      adc_std);    } } static void ADC_Configuration(void) {    lpadc_config_t lpadcConfigStruct;    lpadc_conv_trigger_config_t lpadcTriggerConfigStruct;    /* Configure ADC. */    LPADC_GetDefaultConfig(&lpadcConfigStruct);    lpadcConfigStruct.enableAnalogPreliminary = true;    lpadcConfigStruct.conversionAverageMode = kLPADC_ConversionAverage1;    lpadcConfigStruct.powerLevelMode=kLPADC_PowerLevelAlt4;    lpadcConfigStruct.referenceVoltageSource = DEMO_LPADC_VREF_SOURCE;    lpadcConfigStruct.FIFO0Watermark = 2;    LPADC_Init(DEMO_LPADC_BASE, &lpadcConfigStruct);    LPADC_DoOffsetCalibration(DEMO_LPADC_BASE);    LPADC_DoAutoCalibration(DEMO_LPADC_BASE);    /* Set conversion CMD configuration. */    LPADC_GetDefaultConvCommandConfig(&g_LpadcCommandConfigStruct);    g_LpadcCommandConfigStruct.channelNumber = DEMO_LPADC_USER_CHANNEL;    g_LpadcCommandConfigStruct.sampleTimeMode = kLPADC_SampleTimeADCK3;    g_LpadcCommandConfigStruct.loopCount = 1;    g_LpadcCommandConfigStruct.conversionResolutionMode = kLPADC_ConversionResolutionHigh;  //  g_LpadcCommandConfigStruct.conversionResolutionMode = kLPADC_ConversionResolutionStandard;        g_LpadcCommandConfigStruct.chainedNextCommandNumber = DEMO_LPADC_USER_CMDID;    LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, DEMO_LPADC_USER_CMDID, &g_LpadcCommandConfigStruct);    /* Set trigger configuration. */    LPADC_GetDefaultConvTriggerConfig(&lpadcTriggerConfigStruct);    lpadcTriggerConfigStruct.targetCommandId       = DEMO_LPADC_USER_CMDID;    lpadcTriggerConfigStruct.enableHardwareTrigger = true;    LPADC_SetConvTriggerConfig(DEMO_LPADC_BASE, 0U, &lpadcTriggerConfigStruct); /* Configurate the trigger0. */    /* DMA request enabled. */    LPADC_EnableFIFO0WatermarkDMA(DEMO_LPADC_BASE, true); } static void DMA_Configuration(void) {    dma_channel_config_t dmaChannelConfigStruct; #if defined(DEMO_DMA_HARDWARE_TRIGGER) && DEMO_DMA_HARDWARE_TRIGGER    /* Configure INPUTMUX. */    INPUTMUX_Init(DEMO_INPUTMUX_BASE);    INPUTMUX_AttachSignal(DEMO_INPUTMUX_BASE, DEMO_DMA_ADC_CHANNEL, DEMO_DMA_ADC_CONNECTION); #endif /* DEMO_DMA_HARDWARE_TRIGGER */    /* Configure DMA. */    DMA_Init(DEMO_DMA_BASE);    DMA_EnableChannel(DEMO_DMA_BASE, DEMO_DMA_ADC_CHANNEL);    DMA_CreateHandle(&g_DmaHandleStruct, DEMO_DMA_BASE, DEMO_DMA_ADC_CHANNEL);    DMA_SetCallback(&g_DmaHandleStruct, DEMO_DMA_Callback, NULL);    /* Prepare and submit the transfer. */    DMA_PrepareChannelTransfer(&dmaChannelConfigStruct,              /* DMA channel transfer configuration structure. */                               (void *)DEMO_LPADC_RESFIFO_REG_ADDR,  /* DMA transfer source address. */                               (void *)adc_result,              /* DMA transfer destination address. */                               g_XferConfig,                         /* Xfer configuration */                               kDMA_PeripheralToMemory,               /* DMA transfer type. */                               NULL,                                 /* DMA channel trigger configurations. */                               (dma_descriptor_t *)&(s_dma_table[0]) /* Address of next descriptor. */    );    DMA_SubmitChannelTransfer(&g_DmaHandleStruct, &dmaChannelConfigStruct);    /* Set two DMA descripters to use ping-pong mode.  */    DMA_SetupDescriptor((dma_descriptor_t *)&(s_dma_table[0]), g_XferConfig, (void *)DEMO_LPADC_RESFIFO_REG_ADDR, (void *)adc_result, (dma_descriptor_t *)&(s_dma_table[4]));    DMA_SetupDescriptor((dma_descriptor_t *)&(s_dma_table[4]), g_XferConfig, (void *)DEMO_LPADC_RESFIFO_REG_ADDR, (void *)adc_result, (dma_descriptor_t *)&(s_dma_table[0])); } void SysTick_Handler(void) { }
    复制代码






    签到签到
    回复

    使用道具 举报

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

    本版积分规则

    关闭

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

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

    GMT+8, 2024-4-25 05:34 , Processed in 0.113060 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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