cancel
Showing results for 
Search instead for 
Did you mean: 

ADC1 and 2 timing longer than data sheet values

Mr_M_from_G
Senior

Hello,

I try to setup ADC1 and ADC2, but I don't get the timing values given in reference manual and data sheet. I work with STM32H743 Nucleo

I have setup RCC to clk ADC with 36 MHz from PLL2P. I checked the frequency at master clock out 2 on PC9. To initialize ADC1 and 2 I use this code:

volatile uint32_t wait_cnt;
  // ADC init: for ADC1 and ADC2
  // reset ADC1 and ADC2:
  SetBitMask (RCC->AHB1RSTR, RCC_AHB1RSTR_ADC12RST);
  ClearBitMask (RCC->AHB1RSTR, RCC_AHB1RSTR_ADC12RST);
  // enable ADC clk
  SetBitMask (RCC->AHB1ENR, RCC_AHB1ENR_ADC12EN);
  __DSB ();  // needs to be here according to errata, to wait till periph clk is enabled
 
  ClearBitMask (ADC1->CR, ADC_CR_DEEPPWD);
  ClearBitMask (ADC2->CR, ADC_CR_DEEPPWD);
  SetBitMask (ADC1->CR, ADC_CR_ADVREGEN);
  SetBitMask (ADC2->CR, ADC_CR_ADVREGEN);
 
 
  SetPortBit (port_Testpins, pin_ADC_test);
  for (wait_cnt = 0; wait_cnt < 500; wait_cnt++)
  { // wait for ADC voltage regulator to stabilize, this loop is ca 12 µsec
    __NOP ();
    __NOP ();
  }
  ClearPortBit (port_Testpins, pin_ADC_test);
 
  SetBitMask (ADC1->CR, ADC_CR_BOOST);
  SetBitMask (ADC2->CR, ADC_CR_BOOST);
 
  SetBitMask (ADC1->CR, ADC_CR_ADCALDIF | ADC_CR_ADCALLIN);
  SetBitMask (ADC2->CR, ADC_CR_ADCALDIF | ADC_CR_ADCALLIN);
  SetBitMask (ADC1->CR, ADC_CR_ADCAL);
  SetBitMask (ADC2->CR, ADC_CR_ADCAL);
  SetPortBit (port_Testpins, pin_ADC_test);
  while (BitMaskIsNOTClear(ADC1->CR, ADC_CR_ADCAL) || BitMaskIsNOTClear(ADC2->CR, ADC_CR_ADCAL))
  { // wait for calibration to complete
  }
  ClearPortBit (port_Testpins, pin_ADC_test);
 
  SetBitMask (ADC1->ISR, ADC_ISR_ADRD); // to clear it
  SetBitMask (ADC2->ISR, ADC_ISR_ADRD); // to clear it
  SetBitMask (ADC1->CR, ADC_CR_ADEN);
  SetBitMask (ADC2->CR, ADC_CR_ADEN);
  SetPortBit (port_Testpins, pin_ADC_test);
  while (BitMaskIsClear(ADC1->ISR, ADC_ISR_ADRD) || BitMaskIsClear(ADC2->ISR, ADC_ISR_ADRD))
  { // wait for startup to complete
  }
  ClearPortBit (port_Testpins, pin_ADC_test);
  ADC1->SQR1 = (3 << ADC_SQR1_SQ1_Pos) + (1-1);
  ADC1->PCSEL = 1 << 3;
  ADC1->SMPR1 |= 2 << ADC_SMPR1_SMP3_Pos;  // 2 = 8,5 ADC clk cycles
  ADC1->ISR = ADC_ISR_EOS;
  SetBitMask (ADC1->CR, ADC_CR_ADSTART);
 
  SetPortBit (port_Testpins, pin_ADC_test);
  while (BitMaskIsClear(ADC1->ISR, ADC_ISR_EOS))
  { // wait for calibration to complete
  }
  ClearPortBit (port_Testpins, pin_ADC_test);

I have set 8.5 clk cycles sampling time + another 8.5 for conversion time, @36MHz I would expect a total conversion time of 472 nsec but I get 670 nsec.

Even more differing from datasheet is the time for calibration. Data sheet says it is 16384 cycles = 455µsec @36MHz but I measure 4.56 msec. Is there a digit missing in data sheet ?

Do I miss some setting in my code?

Any help is welcome

Thanks a lot.

Martin

1 ACCEPTED SOLUTION

Accepted Solutions
Amel NASRI
ST Employee

hi @Mr_M_from_G​ ,

Could you please provide more details on how you measured the conversion time?

Did you got any improvement when applying @S.Ma​ 's proposal?

Regarding the calibration value, you are almost right saying that there is a missing digit 🙂

In fact the correct value of this parameter is 165010 cycles instead of 16384 cycles. Datasheet will be updated accordingly.

-Amel

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

8 REPLIES 8
MNapi
Senior II

I cannot comment on this. But I setup ADC in Cube MX for STM32F446 and it was like the data sheet said 1.5 Msps for 12 bit resolution. I did measure the speeds with oscilloscope.

S.Ma
Principal

Try to run the code with interrupts disabled as they could slow down the process. Same for dma memory access if activated. Then compare. Is the vdda same as in the spec or different?

Amel NASRI
ST Employee

hi @Mr_M_from_G​ ,

Could you please provide more details on how you measured the conversion time?

Did you got any improvement when applying @S.Ma​ 's proposal?

Regarding the calibration value, you are almost right saying that there is a missing digit 🙂

In fact the correct value of this parameter is 165010 cycles instead of 16384 cycles. Datasheet will be updated accordingly.

-Amel

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

>Could you please provide more details on how you measured the conversion time?

>> SetPortBit (port_Testpins, pin_ADC_test);

>> ClearPortBit (port_Testpins, pin_ADC_test);

Sounds much like wiggling GPIO pin and observing by oscilloscope/LA...

JW

Mr_M_from_G
Senior

Hello all,

thanks for your messages.

Here are my answers:

This code is bound to be the initialization routine for ADC1+2. Therefore it is placed before enabling interrupts and DMA.

Sorry I frequently forget to add my macros, I am so used to them...

#define SetBitMask(Var,BitMask) (Var|=(BitMask))

#define SetPortBit(Port,BitNr) (Port->BSRRL=1U<<(BitNr))

#define ClearPortBit(Port,BitNr) (Port->BSRRH=1U<<(BitNr))

So I set and clear a GPIO pin around everything I want to measure. These are the time to wait for voltage regulator, calibration time, waiting for ADC ready, which seems to be one conversion and a conversion.

Meanwhile I did two more experiments:

When I add this line

  SetBitMask (ADC12_COMMON->CCR, ADC_CCR_PRESC_0);

after voltage regulator is up and before the BOOST lines I get a calibration time of 9.18 msec and a conversion time of 1.24 µsec.

Setting ADC_CCR_PRESC_1 results in 18.35 msec and 2.44 µsec resp.

And again without any ADC_CCR_PRESC bit set and changed after ADC is ready to this:

  ADC1->SQR1 = (3 << ADC_SQR1_SQ1_Pos) | (3 << ADC_SQR1_SQ2_Pos) | (3 << ADC_SQR1_SQ3_Pos) | (3 << ADC_SQR1_SQ4_Pos) | (4-1);
  ADC1->PCSEL = 1 << 3;
  ADC1->SMPR1 |= 2 << ADC_SMPR1_SMP3_Pos;  // 2 = 8,5 ADC clk cycles
  ADC1->ISR = ADC_ISR_EOS;
  SetBitMask (ADC1->CR, ADC_CR_ADSTART);
 
  SetPortBit (port_Testpins, pin_ADC_test);
  while (BitMaskIsClear(ADC1->ISR, ADC_ISR_EOS))
  { // wait for conversion sequence to complete
    ADC1->ISR = ADC_ISR_EOC;
  }
  ClearPortBit (port_Testpins, pin_ADC_test);

which is setting up a sequence of 4 conversions and permanently clearing bit EOC to start a new conversion as fast as possible (sequence seems not to be continued if EOC stays high, this is in contrast to section ADC overrun on page 941 in RM0433 Rev5 which I understand so that conversions always continue until sequence is through only the way of storing data depends on OVRMOD)

The sequence loop now measures 2.13 µsec which is 533 nsec per conversion. So conversion time is getting closer to the expected value.

I will set up a DMA to read out ADC_DR as fast as possible and come back with results.

Any comment on the ten times longer calibration time is welcome.

best regards

Martin

Mr_M_from_G
Senior

Hello again,

I setup a DMA to run a number of conversions and I can confirm the calculated 470 nsec per conversion. The difference seems to be caused by the loop and GPIO set and clear.

Still I have 4.5 msec calibration time 🙂

Martin

> Still I have 4.5 msec calibration time

Yes, but wasn't that explained by the second part of Amel's answer above?

> I can confirm the calculated 470 nsec per conversion. The difference seems to be caused by the loop and GPIO set and clear.

So if this is settled, can you please mark some of the posts as Best (maybe Amel's) so that the thread is tagged as solved?

Thanks,

JW

Hello Amel,

my apologies for coming up again with the longer calibration time, and thanks to Jan for pointing me to this. I didn't see the second part of your post because I didn't click "show more".

I mark your post as best and my question is completely solved now.

Thanks to all who contributed.

Martin