Skip to main content
HTess.1
Associate III
August 19, 2022
Question

I have a huge accuracy loss (way above what is expected in the datasheet) on ADC reading when increasing the sampling rate. I get that the accuracy is supposed to decrease but I sample at only 200 kHz on the STM32H47AI which is supposed to go up to 3

  • August 19, 2022
  • 14 replies
  • 5819 views

Considering the fact that I can no longer make a difference between waveforms sent at 1kHz (sin and triangular) I am wondering about what I did code wrong in my ADC initialization to mess up my results that much. Below is a 1kHz sin I get for my 200 kHz sampling rate (code below). I use an external Vref MAX6225ACPA to stabilize my reference.

0693W00000QO6BvQAL.png

/******Summary**********/
/*
Use ADC1 channel 13 on PC3 triggered by timer 1 (PRESC 19 and ARR 47)
ADC->DR is read by the DMA in double buffer mode and circular
*/
 
void ADC_Init(void) {
 /*******************Clocks**************************/
 SET_BIT(RCC->AHB4ENR, RCC_AHB4ENR_GPIOCEN_Msk); //GPIOA clock
// /********************Port config************************/
 SET_BIT(GPIOC->MODER, GPIO_MODER_MODE3_0);
 SET_BIT(GPIOC->MODER, GPIO_MODER_MODE3_1);
 CLEAR_BIT(GPIOC->PUPDR, GPIO_PUPDR_PUPD3_0);
 CLEAR_BIT(GPIOC->PUPDR, GPIO_PUPDR_PUPD3_1);
 SET_BIT(SYSCFG->PMCR, SYSCFG_PMCR_PA0SO_Msk | SYSCFG_PMCR_PA1SO_Msk | SYSCFG_PMCR_PC2SO_Msk | SYSCFG_PMCR_PC3SO_Msk);
 SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_ADC12EN_Msk); //ADC12 clocks
 delay(1000);
 
 /********************ADC voltage regulator***************/
 CLEAR_BIT(ADC1->CR, ADC_CR_DEEPPWD_Msk); //END DEEPPWD
 SET_BIT(ADC1->CR, ADC_CR_ADVREGEN_Msk); //ENABLE ADC VOLTAGE REG
 delay(1000);//WAIT VOLTAGE REG
 /******************ADC clock*****************************/
 SET_BIT(ADC12_COMMON->CCR, ADC_CCR_CKMODE_0 | ADC_CCR_CKMODE_1);
 /*******************ADC Prescaler************************/
 SET_BIT(ADC12_COMMON->CCR, ADC_CCR_PRESC_0 | ADC_CCR_PRESC_1 | ADC_CCR_PRESC_3);
 /*******************Input Mode***************************/
 CLEAR_BIT(ADC1->DIFSEL, ADC_DIFSEL_DIFSEL_13); //Single Ended
 /********************INput Preselection******************/
 SET_BIT(ADC1->PCSEL, ADC_PCSEL_PCSEL_13);//Chan 13
 /********************ADC calibration*********************/
 CLEAR_BIT(ADC1->CR, ADC_CR_ADCALDIF_Msk);
 SET_BIT(ADC1->CR, ADC_CR_ADCAL_Msk);
 while (ADC_CR_ADCAL & ADC_CR_ADCAL_Msk != 0) {}
 delay(100);
 SET_BIT(ADC1->CR, ADC_CR_ADCALLIN_Msk);
 SET_BIT(ADC1->CR, ADC_CR_ADCAL_Msk);
 while (ADC_CR_ADCAL & ADC_CR_ADCAL_Msk != 0) {}
 delay(100);
 /**********************ADC BOOST*************************/
 SET_BIT(ADC1->CR, ADC_CR_BOOST_0 | ADC_CR_BOOST_1);
 /*******************ADC Enable***************************/
 SET_BIT(ADC1->ISR, ADC_ISR_ADRDY_Msk);
 SET_BIT(ADC1->CR, ADC_CR_ADEN_Msk);
 while (ADC_ISR_ADRDY & ADC_ISR_ADRDY_Msk != 1) {}
 SET_BIT(ADC1->ISR, ADC_ISR_ADRDY_Msk);
 /********************ADC RES*****************************/
 CLEAR_BIT(ADC1->CFGR, ADC_CFGR_RES_0 | ADC_CFGR_RES_1 | ADC_CFGR_RES_2);//16 bit res
 /********************ADC Data Management*****************/
 SET_BIT(ADC1->CFGR, ADC_CFGR_DMNGT_0 | ADC_CFGR_DMNGT_1);//DMA Circular mode
 /********************OVRMODE*****************************/
 SET_BIT(ADC1->CFGR, ADC_CFGR_OVRMOD_Msk); //Erase old data
 /********************CONT/Single/Discont*****************/
 CLEAR_BIT(ADC1->CFGR, ADC_CFGR_DISCEN_Msk); // discontinuous mode disabled
 CLEAR_BIT(ADC1->CFGR, ADC_CFGR_CONT_Msk); // cont disabled
 /***********************First chan to be converted**************/
 SET_BIT(ADC1->SQR1, ADC_SQR1_SQ1_3 | ADC_SQR1_SQ1_2 | ADC_SQR1_SQ1_0);
 /********************Trigger Detection*******************/
 SET_BIT(ADC1->CFGR, ADC_CFGR_EXTEN_0 | ADC_CFGR_EXTSEL_1 | ADC_CFGR_EXTSEL_3);//Trig rising edge Timer TRGO1
 CLEAR_BIT(ADC1->CFGR, ADC_CFGR_EXTEN_1 | ADC_CFGR_EXTSEL_0 | ADC_CFGR_EXTSEL_2 | ADC_CFGR_EXTSEL_4);
 /********************Sample Time reg*********************/
 SET_BIT(ADC1->SMPR2, ADC_SMPR2_SMP13_0 ); //2.5 CLCK Cycles| ADC_SMPR2_SMP13_1 | ADC_SMPR2_SMP13_2 
 /********************ADC IT******************************/
// SET_BIT(ADC1->IER, ADC_IER_EOCIE_Msk | ADC_IER_EOSMPIE_Msk | ADC_IER_OVRIE_Msk );//| ADC_IER_EOSIE_Msk | ADC_IER_OVRIE_Msk
// NVIC_EnableIRQ(ADC_IRQn);
// NVIC_SetVector(ADC_IRQn, (uint32_t)&ADC_IRQHandler);
}

This topic has been closed for replies.

14 replies

waclawek.jan
Super User
August 19, 2022

Try with DC first.

The signal source has to be low impedance, if you want to use short sampling times.

JW

HTess.1
HTess.1Author
Associate III
August 19, 2022

DC signals give me a sinus wave. I don't have anything to record a sample of the signals I get when inputting DC right now.

I will try using some capacitors when I get back.

raptorhal2
Lead
August 20, 2022

EDIT: Something is amiss here. The plot shows about 20 input cycles for 200 samples instead of 1 . Check your conversion frequency.

Cheers, Hal

raptorhal2
Lead
August 20, 2022

Is the following correct?

If SYSCLK is 480 MHz, Timer 1 is generating an ADC trigger at 240/(19*48) = 250KHz.

ADC prescalar is bit fields 1011 = divide by 256.

Sampling frequency is then 250KHz/256 = 0.976KHz.

Cheers, Hal

HTess.1
HTess.1Author
Associate III
August 20, 2022

True, I tried this configuration because I did not understand the LL_GetCommonClock() function return value which did go up when my clock speed was supposed to go down. But using the lowest prescalers values did not really get me satisfying results (still could not differentiate close waveforms like sin and triangular ones and my DC readings remained sin). Do you think there could be a link between my adc accuracy and the ADC clock not respecting a certain value(in the datasheet of the STM32h747 all the parameters of the ADC are described for certain frequencies) ? Should I setup a PLL as an asynchronous clock for ADC and aim for the exact value?

raptorhal2
Lead
August 20, 2022

The TIM1 trigger should work.

The example is not near any ADC limitations in the data sheet.

Is the signal source and 747 well grounded to each other?

Cheers, hal

HTess.1
HTess.1Author
Associate III
August 20, 2022

This is what my circuit looks like, I am using the STM32h747 within the Arduino Portenta (and the schematics are quite obscure to me https://content.arduino.cc/assets/Schematic%20PDF_SL-ABX00042.pdf?_gl=1*1lvkz5d*_ga*NzIxMjUwMTMuMTYzNzc3Mjc1OA..*_ga_NEXN8H46L5*MTY2MTAxMTI3Ny4yOS4xLjE2NjEwMTEyNzkuNTguMC4w page 2 )0693W00000QO8K1QAL.png

raptorhal2
Lead
August 20, 2022

The schematic shows PC3 connected to Arduino A3. Couldn't find any other connections.

Suggest eliminate one variable by using Portena built-in references.

Perhaps someone else can spot something.

Cheers, Hal

gregstm
Senior II
August 21, 2022

Just a thought. You could use the Micro's DAC to produce a triangle or sine wave and use that to test the DAC. That way you can disconnect the signal generator while you test your software - just in case there is some sort of weird noise/ground thing going on.

S.Ma
Principal
August 21, 2022

Measure the frequency and findout if a harmonic source is onboard.

Use internal pull up/down to test the signal. Change the sample and hold time. Typically use 1 Msps on the adc to get started. Check mcu errata sheet for any needed workaround. Probe with a scope at mcu pin during operating and around.