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
S.Ma
Principal

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.

HTess.1
Associate III

I will test with DAC and Arduino's built-in definition.

About using pull-up/down to test the signal I might be misunderstanding but am I not supposed to setup my pin as analog? In the datasheet, it is written that pull-up and down are turned off when the pin is used this way.

0693W00000QO9DVQA1.png

S.Ma
Principal

What's the risk? Writing the post takes more time than just try in debug mode manually playing with pupd registers (at least for me)

BTW, The capture doesn't locate the resistors.

It s not about whether I am willing to take a risk or not, I just can not make tests until Monday. So if asking that question may evidence a misconception I have on Analog pins I will ask it. The reason I started this post is to find where I messed up and from my experience, it always comes from a lack of knowledge so please allow me to try and understand the debug method advised here.

As for where the resistors are located the typical schematics for a GPIO pin are below as well as the line I consider to be specifying that there is no access to pull-up and down resistor in analog mode:

0693W00000QO9VeQAL.png0693W00000QO9VZQA1.png

HTess.1
Associate III

So I had the time to test all the above.

1) For my signal shape it was due to the way I read it, the serial buffer was overwritting values due to the serial communication being too slow for my sampling rate. I only plot two values for 10 samples now.

2) Adding a capacitor made no difference for my readings however the capacitor values I could try where ten times bigger than the sample and hold capacitor. So I can not really conclude on that point. (Internal capacitor is 4 pF according to datasheet).

3) Changing PUPD register made no difference same for using Arduino built in definitions.

3) For the impedance issue I used an OPAMP, the TS922 and the result I got from my ADC gained in accuracy with the only issue being that the ADC ends up reading the values as negative ones despite the fact that there are only positive input (verified with an oscilloscope on the input pin). Could it be linked to the fact that the current is increased by the OPAMP circuit and no longer meets the ADC characteristics? The current values I measured where around the µA so considering every I/O pin sink around 20 mA (datasheet again) can it really be linked?

0693W00000QOJXzQAP.png

raptorhal2
Lead

the ADC ends up reading the values as negative ones

That is likely to be something in the calibration, offset or handling of the converted values, not an input problem.

Cheers, Hal