This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Tool/software:
Hello:
I verified the ADC acquisition time by timer, and the result was a little strange.
In one-shot mode, 8 channels are captured, the trigger FIFO threshold is set to 15 (8*2-1), and the time from adc startup to interrupt entry is about 9us.
However, similarly, with the acquisition of 1 channel, the trigger FIFO threshold is set to 1 (1*2-1), and the time from starting adc to entering the interrupt takes about 50us.
My question:
1. Why the collection channel is less, but the time is extended;
2. According to the data manual, the sampling frequency is 4MSPS, please help us to confirm whether the sampling time of 9us is reasonable;
3. Whether there are measures to speed up the sampling time.
My program is as follows,the timing starts and ends at hal_adc_trigger() and App_adcGetData():
uint16_t adc_original_buff[APP_ADC_NUM_CH]; int32_t adc_buff[APP_ADC_NUM_CH]; float curr_result[3]; static HwiP_Object gAdcHwiObject; HwiP_Params hwiPrms; volatile uint32_t adc_start_ns = 0; volatile uint32_t adc_interval_ns = 0; void App_adcGetData(void) { uint32_t voltageLvl; uint32_t id; uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR; uint32_t i = 0; uint32_t fifoData = 0; uint32_t fifoWordCnt; if(is_float_zero(gUserParams_float.adc_gain) == MT_TRUE) { gUserParams_float.adc_gain = 0.15f; } /* Get FIFO data */ fifoWordCnt = ADCGetFIFOWordCount(baseAddr, ADC_FIFO_NUM_0); for (i = 0U; i < fifoWordCnt; i++) { fifoData = ADCGetFIFOData(baseAddr, ADC_FIFO_NUM_0); id = ((fifoData & ADC_FIFODATA_ADCCHNLID_MASK) >> ADC_FIFODATA_ADCCHNLID_SHIFT); fifoData = ((fifoData & ADC_FIFODATA_ADCDATA_MASK) >> ADC_FIFODATA_ADCDATA_SHIFT); adc_original_buff[id] = (uint16_t)fifoData; if((id > 2) && (id < 6)) { voltageLvl = fifoData * (uint32_t) (V_ADC_REF * 1000); voltageLvl /= (uint32_t) ADC_GET_RANGE(CONFIG_ADC0_NUM_BITS); if(Old_m_state == MC_STATE_CALIBRATION) { //1650 = 3.3V * 1000 / 2 adc_buff[id] = voltageLvl - 1650; } else { adc_buff[id] = voltageLvl - 1650 - hal_hwParams_u32_t.PhaseCurrOffset[id - 3]; } curr_result[id - 3] = (adc_buff[id] * 1.0f / 1000.0f) / gUserParams_float.adc_gain; } else { adc_buff[id] = fifoData; } } adc_interval_ns = clock_cal_interval(adc_start_ns, clock_get_ns()); } void App_adcISR(void *handle) { uint32_t status; uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR; /* Get interrupt status and clear */ status = ADCGetIntrStatus(baseAddr); ADCClearIntrStatus(baseAddr, status); App_adcGetData(); /* Set EOI to generate next interrupt if any */ ADCWriteEOI(baseAddr); } void App_adcConfig(uint32_t baseAddr) { adcStepConfig_t adcConfig; uint32_t chCnt, adcStep; /* Enable interrupts */ ADCEnableIntr(baseAddr, ADC_INTR_SRC_FIFO0_THRESHOLD); /* * Configure all ADC Steps */ /* Initialize ADC configuration params */ adcConfig.mode = ADC_OPERATION_MODE_SINGLE_SHOT; adcConfig.openDelay = 0x0U; adcConfig.sampleDelay = 0U; adcConfig.rangeCheckEnable = 0U; adcConfig.averaging = ADC_AVERAGING_NONE; adcConfig.fifoNum = ADC_FIFO_NUM_0; /* Configure all required steps - Step 1 to N mapped to Channel 1 to N */ for(chCnt = 0U; chCnt < APP_ADC_NUM_CH; chCnt++) { adcConfig.channel = ADC_CHANNEL_1 + chCnt; adcStep = ADC_STEP_1 + chCnt; /* Step -> Channel one to one mapped */ ADCSetStepParams(baseAddr, adcStep, &adcConfig); } ADCStepIdTagEnable(baseAddr, TRUE); ADCSetCPUFIFOThresholdLevel(baseAddr, ADC_FIFO_NUM_0, APP_ADC_NUM_CH * 2); /* Step enable */ for(chCnt = 0U; chCnt < APP_ADC_NUM_CH; chCnt++) { adcStep = ADC_STEP_1 + chCnt; /* Step -> Channel one to one mapped */ ADCStepEnable(baseAddr, adcStep, TRUE); } } static void App_adcInit(uint32_t baseAddr) { /* Clear All interrupt status */ ADCClearIntrStatus(baseAddr, ADC_INTR_STATUS_ALL); /* Register & enable interrupt */ HwiP_Params_init(&hwiPrms); hwiPrms.intNum = CONFIG_ADC0_INTR; hwiPrms.callback = &App_adcISR; hwiPrms.priority = 1U; HwiP_construct(&gAdcHwiObject, &hwiPrms); /* Power up AFE */ ADCPowerUp(baseAddr, TRUE); /* Wait for 4us at least */ ClockP_usleep(5U); /* Do the internal calibration */ ADCInit(baseAddr, FALSE, 0U, 0U); } static void App_adcStart(uint32_t baseAddr) { adcSequencerStatus_t status; /* Check if FSM is idle */ ADCGetSequencerStatus(baseAddr, &status); while ((ADC_ADCSTAT_FSM_BUSY_IDLE != status.fsmBusy) && ADC_ADCSTAT_STEP_ID_IDLE != status.stepId) { ADCGetSequencerStatus(baseAddr, &status); } /* Start ADC conversion */ ADCStart(baseAddr, TRUE); } int32_t hal_adc_init(void) { uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR; App_adcInit(baseAddr); App_adcConfig(baseAddr); /* Set EOI to generate next interrupt if any */ ADCWriteEOI(baseAddr); App_adcStart(baseAddr); return MT_OK; } void hal_adc_trigger(void) { uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR; uint32_t chCnt, adcStep; /* Step enable */ for(chCnt = 0U; chCnt < APP_ADC_NUM_CH; chCnt++) { adcStep = ADC_STEP_1 + chCnt; /* Step -> Channel one to one mapped */ ADCStepEnable(baseAddr, adcStep, TRUE); } adc_start_ns = clock_get_ns(); App_adcStart(baseAddr); }
Hello Walker li,
I am looking at your queries and you may get reply in one or two days .
Regards, Anil.
Hello Walker li,
By default ADC is connecting to 25MHz clock only .
Can you please confirm what is the value of ADC clock selection Mux value in your setup ?
If you change the Mux selection value to 1 then ADC will run at 60MHz only to get the 4MSPS .
Try to change the Mux clock selection to 1 from 0 and check the Results .
Please look at the image below.
The Mux clock selection register is a CTRL MMR. So, there is a lock and unlock mechanism for this memory location.
Once CTRL_MMR is locked , user can't change the Mux selection.
So, we can go with lock mechanism to change the clock selection and you can try the code below.
Please go through chapter below for more details about lock protection .
/* set ADC clock source */ SOC_controlModuleUnlockMMR(SOC_DOMAIN_ID_MAIN, 2); *(volatile uint32_t*)AddrTranslateP_getLocalAddr(0x43008510U) = 0x01; SOC_controlModuleLockMMR(SOC_DOMAIN_ID_MAIN, 2);
Regards,
Anil.
I added the statement as suggested, but the test found that the adc did not run. Do you need to enable PLL clock before running? How can I enable PLL clock?
int32_t hal_adc_init(void) { uint32_t baseAddr = CONFIG_ADC0_BASE_ADDR; /* set ADC clock source */ SOC_controlModuleUnlockMMR(SOC_DOMAIN_ID_MAIN, 2); *(volatile uint32_t*)AddrTranslateP_getLocalAddr(0x43008510U) = 0x01; SOC_controlModuleLockMMR(SOC_DOMAIN_ID_MAIN, 2); App_adcInit(baseAddr); App_adcConfig(baseAddr); /* Set EOI to generate next interrupt if any */ ADCWriteEOI(baseAddr); App_adcStart(baseAddr); return MT_OK; }
Hello Walker li,
I am able to run the properly ADC example after the modyfing the Clock selection.
We don't need to configure the PLL settings we just need to update the ADC MUX selection.
Since, all PLL are configured by DMSC software.
Can you please confirm what the difference is between your code and an example code?
Regards,
Anil.
Dear Walker.
would you please check the response from Anil and provide the status on your side?
thanks a lot!
yong