cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7B0 incorrect ADC sample rate

OGhis
Senior

Hey,

We using an STM32H7B0 100 pins MCU.
With this mcu we will sampling 1 16 bit ADC input at 1 MHz and we using a DMA in circular mode for 1000 samples

The ADC clock works at 48Mhz, the clock precaler for the ADC is divided by 32 and the sample time is 1.5 cycles.
So, 48Mhz / 32 / 1.5 / 1000 = 1Mhz, but we when seen that the sample rate is only at 75Khz.
The 75Khz was measured with a GPIO toggle output pin in the HAL_ADC_ConvCpltCallback() end of single convertion call back.

What we doing wrong? 

OGhis_2-1723818782378.png

 

 

OGhis_1-1723818766460.png

 



OGhis_0-1723818752330.png

 

 

9 REPLIES 9
AScha.3
Chief II

Hi, 

Your ADC clock is much too low, set divider to two.

The ADC needs some clocks to convert, 15 or so, plus sampling time ; and depending on source impedance you need longer sampling time, so set not the shortest possible, try 7.5 ; then you get about 1us sampling.

(48MHz /2 -> 24 / 20 clocks -> about 1 us ).

Just try - and read RM about the ADC.

If you feel a post has answered your question, please click "Accept as Solution".
OGhis
Senior

Hi,

Thanks for the information, but we must have a sample rate of exact 1 Mega samples.
How we can do this?

Just look at ds, how many clocks your ADC at the resolution you set needs, then add the sampling clocks to get total ADC conversion time. You cannot choose everything as you like, only certain steps are possible to set - obviously.

But you can choose the basic clock for ADC and the division of the clock, so by choosing a certain clock for the ADC and a sample time, you can adjust it.

Other way is, to make the conversion faster than needed, let's say 1.5...2 msps, then start the ADC by a timer at the desired frequency to get exactly the rate you want and adjust it just by the timer -> trigger the ADC at this rate.

That's the perfect way to get any sampling rate (as long, as the ADC is faster than the trigger you set, because it has to be ready for the next trigger in time.).

If you feel a post has answered your question, please click "Accept as Solution".
OGhis
Senior

Hi,
Thanks.

We try to let sample the ADC above the 1Mhz, but there is somethings wrong.

- The ADC clock is 48Mhz.
- The clock prescaler is: divided by 1
- The ADC has a resolution of 16 bits
- The Sample Time is 32.5 Cycles.

When we now caculate the sample time:

TCONV = Sampling time + 8.5 ADC clock cycles
TCONV = 32.5 + 8.5 = 41 cycles or 48 / 41 = 1.170 M samples.

OGhis_0-1723834866835.png

For the ADC conversion we us a DMA in circular mode with a buffer size of 1000 samples.
Than we us the HAL_ADC_ConvCpltCallback() function to indicate when the 1000 sample are taken.
In this interrupt we let toggle an output port.

The frequentie on the output pin should be:
Freq I/O pin = Sample freq ADC / 1000 / 2    (2 here means, factor 2 due togglling)
Freq I/O pin = 1.170 mega sample / 1000 / 2
Freq I/O pin = 585.3 Hz.

We measure 292.7Hz on the I/O pin.
This is a factor 2 slower than calculated.

Can you explain us why this is a factor 2 slower? (sample rate is 585Khz and not 1.17 Mhz)

 



Hmmm... look in RM, ADC block picture, some ADC have internal /2 division, so running on half clock rate. Maybe depends on version of chip, V or Y or so. Check this.

And just try with shorter sampling time, to get about 24 cycles, and see, what happens.

If you feel a post has answered your question, please click "Accept as Solution".

Hi,
When we reduce the sample time to 25 cycles we have the same issue. Sample rate is 2 times lower than the calculated sample rate.

So there is somthing internal that pre divide the ADC clock by 2.

==>  Maybe depends on version of chip, V or Y
Where i can find this information?

On our chip we have the follow marking:
STM32H7B0
VBT6
AA128   LM   1
TWN   AA   338
                  03


There should be a single letter, V or Y or Z...

Show a pic of the chip, maybe it's there.

But that's no problem, just to know the divider is there, then you can include it in the calculation for ADC clock.

And anyway, for getting a certain ADC rate, using a timer to trigger is the best way, to get it running at a certain frequency.

If you feel a post has answered your question, please click "Accept as Solution".
OGhis
Senior

Hi,
Thanks for the information
We cannot find the the single letter, V or Y or Z... on the chip.
But we found this in the datasheet. So the Clock of the ADC is always divided by 2.

OGhis_0-1723887308783.png

For the 1 M sample rate we using now a timer and this works fine.
Due the high sample rate we using also a DMA in normal mode.
The idea was using at first the 2D DMA, but i think the stm32H7 has not such DMA.
So then we would simulate such DMA.

Therefore we will using 2 DMA buffers with a length of 10K samples.
In the HAL_ADC_ConvCpltCallback() call back we restart the ADC in DMA mode but we swap every time from sample buffer. So is the other sample buffer free and can we logging to another location (in our case to an external QSPI RAM).
It's works but we seen that we missing 1 or 2 samples at the restart of ADC.

Here he code we using:

#define MODADCF_DMA_BUF_SIZE  (10000)
int16_t buffer0 [MODADCF_DMA_BUF_SIZE];
int16_t buffer1 [MODADCF_DMA_BUF_SIZE];

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
  volatile uint8 pos2D = 0;
  if (pos2D & 0x01) {
    BSPADC_StartScanMeasure_DMA(&hadc2,(uint32_t*)&buffer0, MODADCF_DMA_BUF_SIZE);
  } else {
    BSPADC_StartScanMeasure_DMA(&hadc2,(uint32_t*)&buffer1, MODADCF_DMA_BUF_SIZE);
  }
  pos2D ++;
}


Is there another methode to do this without missing samples?
or
Is there a faster way to change the DMA buffer address without restarting the ADC?








Sure, the trick is called: circular DMA mode.

That's continuous sampling to a buffer in 2 parts, you get half and full buffer callbacks, so DMA storing without missing sample and you only start it once, then it's running... and you just use the callback to transfer this half buffer to your... whatever you do with it. No need to stop it, If don't need the data, just do nothing on callback and let it run on and overwrite old data. 

You can enable callbacks in Cube, the tab with advanced... whatever (just look, it's long list on right side of screen).

If you feel a post has answered your question, please click "Accept as Solution".