cancel
Showing results for 
Search instead for 
Did you mean: 

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.3MHz

HTess.1
Associate III

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);
}

15 REPLIES 15

Try with DC first.

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

JW

HTess.1
Associate III

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

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

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
Associate III

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

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
Associate III

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

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 III

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.