最近支持一個(gè)客戶,需要在LPC5516下實(shí)現(xiàn)ADC 2Msps高速采集,根據(jù)數(shù)據(jù)手冊描述:
-
ADC在12-bit模式下最高可以達(dá)到2.3Msps
-
ADC在16-bit模式下最高可以達(dá)到2.0Msps.
那么實(shí)際情況是否真如數(shù)據(jù)手冊所述,能達(dá)到如此高的轉(zhuǎn)換速率呢?小編這次就編寫了測試代碼進(jìn)行了實(shí)測,結(jié)果為:
12-bit模式下ADC最快可達(dá)2.326Msps, 16-bit模式下2.083Msps, 結(jié)果還是和數(shù)據(jù)手冊很吻合的。
代碼設(shè)計(jì)
代碼基于SDK的例程:
SDK_2_12_0_LPCXpresso55S16oardslpcxpresso55s16driver_exampleslpadcdma
修改:
1. 為了實(shí)現(xiàn)最快速度ADC采集,我們需要將ADC配置為:
除此之外,還需要將ADC設(shè)置為連續(xù)轉(zhuǎn)換模式:即將g_LpadcCommandConfigStruct.chainedNextCommandNumber指向自己,即完成當(dāng)前轉(zhuǎn)換后,自動(dòng)開始下次轉(zhuǎn)換。
以上所有配置對應(yīng)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數(shù)據(jù),即定義兩個(gè)DMA描述符,A和B:A傳輸完成后自動(dòng)觸發(fā)B,B傳輸完成后自動(dòng)觸發(fā)A。對應(yīng)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定時(shí)器用于記錄轉(zhuǎn)換時(shí)間,程序開始運(yùn)行后,ADC會(huì)啟動(dòng)連續(xù)轉(zhuǎn)換,DMA設(shè)置為傳輸100次ADC轉(zhuǎn)換結(jié)果后觸發(fā)DMA完成中斷, DMA中斷觸發(fā)后(傳輸完成),程序會(huì)統(tǒng)計(jì)ADC轉(zhuǎn)換時(shí)間,計(jì)算ADC轉(zhuǎn)換結(jié)果的平均值和標(biāo)準(zhǔn)差,以及打印轉(zhuǎn)換結(jié)果。
代碼清單
最后為大家呈上完整代碼清單(可以直接復(fù)制到lpadc_dma.c里運(yùn)行):
/* * 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
下期,將重點(diǎn)聊聊影響ADC轉(zhuǎn)換誤差的各種因素。
審核編輯:湯梓紅
-
adc
+關(guān)注
關(guān)注
98文章
6391瀏覽量
543766 -
SDK
+關(guān)注
關(guān)注
3文章
1020瀏覽量
45694 -
高速采集
+關(guān)注
關(guān)注
0文章
5瀏覽量
6139
原文標(biāo)題:LPC5516_SDK例程ADC_2Msps高速采集
文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論