LPC5516_SDK例程ADC_2Msps高速采集

最近支持一个客户,需要在lpc5516下实现adc 2msps高速采集,根据数据手册描述:
adc在12-bit模式下最高可以达到2.3msps
adc在16-bit模式下最高可以达到2.0msps.
那么实际情况是否真如数据手册所述,能达到如此高的转换速率呢?小编这次就编写了测试代码进行了实测,结果为:
12-bit模式下adc最快可达2.326msps,  16-bit模式下2.083msps, 结果还是和数据手册很吻合的。
代码设计
代码基于sdk的例程: 
sdk_2_12_0_lpcxpresso55s16oardslpcxpresso55s16driver_exampleslpadcdma
修改:
1. 为了实现最快速度adc采集,我们需要将adc配置为:
adc输入时钟: adcclk = 48mhz
无硬件平均: hwavg=1
adc采样时长设置为最短3xclk:  sts=0
adc功率最大: pwrsel=3
除此之外,还需要将adc设置为连续转换模式:即将g_lpadccommandconfigstruct.chainednextcommandnumber指向自己,即完成当前转换后,自动开始下次转换。
以上所有配置对应sdk代码如下:
    /* 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_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;
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.
3.   const uint32_t g_xferconfig =
4.      dma_channel_xfer(true,                         /* reload linkdescriptor after current exhaust, */
5.                      true,                         /* clear trigger status.*/
6.                      true,                         /* enable interrupta. */
7.                      false,                        /* not enable interruptb. */
8.                      sizeof(uint32_t),           /* dma transfer width. */
9.                      kdma_addressinterleave0xwidth, /* dma source address no interleave */
10.                      kdma_addressinterleave1xwidth, /* dma destination address nointerleave  */
11.                      sizeof(uint32_t)*adc_dma_size              /* dma transfer byte. */
12.      );
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 submitthe 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,               /* dmatransfer type. */
                              null,                                /*dma channel trigger configurations. */
                              (dma_descriptor_t *)&(s_dma_table[0]) /* address of next descriptor. */
    );
    dma_submitchanneltransfer(&g_dmahandlestruct, &dmachannelconfigstruct);
/* set two dmadescripters 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]));
}
3. 最后小编还使能了systick定时器用于记录转换时间,程序开始运行后,adc会启动连续转换,dma设置为传输100次adc转换结果后触发dma完成中断,  dma中断触发后(传输完成),程序会统计adc转换时间,计算adc转换结果的平均值和标准差,以及打印转换结果。
代码清单
最后为大家呈上完整代码清单(可以直接复制到lpadc_dma.c里运行):
/* * copyright 2018-2021 nxp * all rights reserved. * * * spdx-license-identifier: bsd-3-clause */ #include pin_mux.h #include clock_config.h #include board.h #include fsl_debug_console.h #include fsl_dma.h #include fsl_inputmux.h #include fsl_lpadc.h #include stdio.h #include math.h #include fsl_power.h #include fsl_anactrl.h /******************************************************************************* * definitions ******************************************************************************/ #define pf(a)   ((a) * (a)) #define demo_lpadc_base                  adc0 #define demo_lpadc_user_channel          0u #define demo_lpadc_user_cmdid            1u /* cmd1 */ #define demo_lpadc_vref_source           klpadc_referencevoltagealt2 #define demo_lpadc_do_offset_calibration true #define demo_lpadc_resfifo_reg_addr      (uint32_t)(&(adc0->resfifo[0])) #define demo_result_fifo_ready_flag      klpadc_resultfifo0readyflag #define demo_dma_base          dma0 #define demo_dma_adc_channel   21u #define dma_descriptor_num 2u #define adc_dma_size        (100) static void adc_configuration(void); static void dma_configuration(void); lpadc_conv_command_config_t g_lpadccommandconfigstruct; /* structure to configure conversion command. */ dma_handle_t g_dmahandlestruct;              /* handler structure for using dma. */ uint32_t adc_result[adc_dma_size];                 /* keep the adc conversion resulut moved from adc data register by dma. */ static double adc_sum; static double adc_mean, adc_std; static double adc_sum_sqrt; volatile bool g_dmatransferdoneflag = false; /* flag of dma transfer done trigger by adc conversion. */ /* dma descripter table used for ping-pong mode. */ sdk_align(uint32_t s_dma_table[dma_descriptor_num * sizeof(dma_descriptor_t)], fsl_feature_dma_link_descriptor_align_size);          const uint32_t g_xferconfig =    dma_channel_xfer(true,                          /* reload link descriptor after current exhaust, */                     true,                          /* clear trigger status. */                     true,                          /* enable interrupta. */                     false,                         /* not enable interruptb. */                     sizeof(uint32_t),            /* dma transfer width. */                     kdma_addressinterleave0xwidth, /* dma source address no interleave  */                     kdma_addressinterleave1xwidth, /* dma destination address no interleave  */                     sizeof(uint32_t)*adc_dma_size               /* dma transfer byte. */    ); const uint32_t g_lpadcfullrange   = 65536u; const uint32_t g_lpadcresultshift = 0u;                     void demo_dma_callback(dma_handle_t *handle, void *param, bool transferdone, uint32_t tcds) {    //printf(demo_dma_callback );    if (true == transferdone)    {        g_dmatransferdoneflag = true;    } } int main(void) {    /* initialize board hardware. */    /* set bod vbat level to 1.65v */    power_setbodvbatlevel(kpower_bodvbatlevel1650mv, kpower_bodhystlevel50mv, false);    /* 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 );    printf(adc clk:%d , clock_getadcclkfreq());    printf(core clk:%d , clock_getcoresysclkfreq());        /* configure peripherals. */    dma_configuration();    adc_configuration();    printf(adc full range: %d , g_lpadcfullrange);    printf(adcresolution: %dbit , (g_lpadccommandconfigstruct.conversionresolutionmode == klpadc_conversionresolutionstandard)?(12):(16));            systick_config(0xffffff);    int tick;    printf(please press any key to trigger the conversion. );    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) ,     time:,      tick, (1 / (float)tick)*adc_dma_size);                int i;        adc_sum = 0;        adc_sum_sqrt = 0;        for(i=0; i> g_lpadcresultshift);            adc_sum += (float)adc_result[i];            adc_sum_sqrt += (adc_result[i]*adc_result[i]);                       // printf(adc[%d]:%d , i, adc_result[i]);        }               // printf(sum:%.2f , adc_sum);      //  printf(ssum:%.2f , 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 ,     avg :,      adc_mean);        printf(%-16s%f ,     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){}
下期,将重点聊聊影响adc转换误差的各种因素。


关于存算融合的新型数据基础设施技术
精神航空公司承诺将订购100架空客A320neo系列飞机
苹果开启新一轮主板“革命” PCB厂商的未来在哪里?
大众汽车自建人工智能实验室
Google推出了超级强大的在线编辑器Colaboratory
LPC5516_SDK例程ADC_2Msps高速采集
继电器并联二极管的作用和电路图分析
苹果发布新专利,又一次刷新Apple Watch的操作体验
豪威科技发布了旗下一款型号为OV48C的4800万像素CMOS
led显示屏的优缺点_LED显示屏的主要功能
日本制造超越美国成功的秘诀是什么
江苏拓斯达(吴中)项目正式开工开业
昂科ic烧录器更新支持烧录BYD比亚迪半导体的8位微控制器BF7615CM32
音乐时钟DIY图解
从零开始到年赚190亿,这家半导体公司只用了5年
什么是主板ASUS插槽/AGP插槽
杜邦宣布将投资逾8000万美元在江苏省张家港市兴建全新制造基地
把握工业计算芯机遇 | 芯海科技受邀参加“2022中国工业计算机大会”
Versal GTY仿真:初始化,复位和速率变更
光电储能系统如何帮助电动车实现快充