Skip to main content
Robmar
Senior II
December 3, 2022
Question

ADC sample rate impossible to set precisely (calculations added)

  • December 3, 2022
  • 43 replies
  • 5028 views

I realise that with ADC timer triggered DMA of 32 samples, you can set the timer precisely, but not the ADC​ per sample clock, so the samples get bunched up or stretched in the frame. The number of clocks per sample is limited, adjusting the APB2 clock hardly helps. A bit more flexibility on sample clocks would be really useful, I guess there is no easy solution?

Objective: capture ADC samples spread evenly at 96 KS/s on STM32F407VG with 8MHz xtal

Reference: STM32F406VG datasheet.

Overview:-

To capture samples from two independent ADCs at 96 KS/s, Timer3 is set to generate

an event every 1/3 mS, i.e. 333.3r uS

ABP1 Clk 84 MHz drives Timer3 from a 42MHz clk via a fixed x2 multiplier.

ADC-DMA is triggered and set to take 32 samples:

APB2 (PCLK2 + prescaler /4,/6,/8) clk drives ADCs at 84 MHz: Period 11.904 nS

Okay, so 3,000 triggers of 32 samples pers second.

1. 3K triggers the ADC-DMA every 333.3r uS

2. 32 samples every 333.3r uS gives 10.416r uS per ADC sample.

3. a1) ADC clk at 84 MHz has a clk period of 11.904761 nS or 0.011904761 uS,

  b1) Prescaler of 8 reduces this to 10.5 MHZ, and a clk period of 0.095238088 uS

  c1) Prescaler 6 clk reduces to 14 MHz and a clk of 0.07142857 uS. 

  d1) Prescaler 4 clk reduces to 21 MHz and a clk of 0.04761904 uS. 

  e1) Prescaler 2 (MX deselected not peritted) clk ... 42MHz ...

  

  b1-R) P8: We need 10.416 uS worth of clocks per sample, giving 109.375008312501 clks at 10.5 MHz

  c1-R) P6: -""-, giving 145.82400291648 clks at 14 MHz

  d1-R) P4: -""-, giving 218.736034997776 clks at 21 MHz

  e1-R) P2: -""-, giving 437.472 clks at 42 MHz (MX deselected)

Each samples takes 15 clks + (3, 15, 28, 56, 84, 112, 144, 480 sample time clks selectable)

Best match: Prescaler 8, our 96KHz sampling rate requires 109.375 clks per 32 sample trigger, subtracting the ADC sample time of 15 for 16-bit conversion = 94.375 clks, nearest selection is Sample time of 84 + 15 = 99, an increase in sample rate by 10.375 clks per sample.

This increase in the sample rate will require a significant non-standard change to my DSP code. A single transfer per trigger would solve this if there was a way that the ADC-DMA could increment the memory address, but so far I can't see that is supported.

This topic has been closed for replies.

43 replies

S.Ma
Principal
December 3, 2022

ADCs spec varies a lot between familiies.

On L4, I configure ADC normal channel with dma cycling them, and a timer pwm output pin feeding it wity external monitorable wire. The pwm edge triggers one channel conversion (not a sequence), and its period is longer to let the adc finish converting each channel. That works.

Robmar
RobmarAuthor
Senior II
December 3, 2022

Yes but unfortunately I must transfer 32 samples at least by DMA as its running at 192ks/s, else the cpu can't cope.

waclawek.jan
Super User
December 3, 2022

Which STM32?

What are you trying to achieve?

> I must transfer 32 samples at least by DMA as its running at 192ks/s,

How is this in conflict with what . said above, i.e. trigger individual conversions not sequences? Read the ADC chapter in RM to understand the capabilities of ADC in given STM32 family.

JW

Robmar
RobmarAuthor
Senior II
December 3, 2022

Hi, it's an 32f407vg 8mhz xtal, on a Discovery board.

I have an spi lcd connected on spi2 at max clk, and am using adc1 on in2 and adc on in14 to sample at 96 and 192 (user selectable) ks/s synchronised on both channels by tim3, reading 32 samples per trigger (0.33r mS triggers for 96ks), but the 32 samples must be spaced evenly across the 333uS period.

I can get dma samples spread over around 300 or ​360uS per trigger using available samples clock settings, like 144 with prescaler, but not closer. Not sure there is a solution without slowing the main clock.

Robmar
RobmarAuthor
Senior II
December 3, 2022

The samples have to be processed in DSP code leaving insufficient time for the CPU to process them individually at the same time, hence DMA use. I don't think there is an automated ​way to have repeat DMAs of single samples sent to an incremented memory address between each ADC -DMA run.

gbm
Super User
December 3, 2022

And why don't you convert just one sample per hardware trigger? The F4 DMA may be programmed to transfer, say 64 samples to a circular buffer and to issue an interrupt after 32th and 64th sample, so that you could process half of the buffer on each DMA interrupt.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
Robmar
RobmarAuthor
Senior II
December 3, 2022

Hi, (just posted my math in the main questions) thanks for your comment. Its because the 32/64/128 samples must be ​taken evenly spaced every 333.333 uS and the per sample time is limited to 12 clocks + 28/56/84/128/144/408 clocks plus prescaler, none of which comes to 333uS/32. So once the ADC-DMA is triggered by the timer, 32 samples must be taken, one each 333.333 / 32 uS, ie samples every 10.42uS. I'm trying to get my thick head around the clock options to achieve this

waclawek.jan
Super User
December 3, 2022

> just posted my math in the main question

Please don't modify older posts, including the original one (except for basic typos etc.), it makes it hard for us to follow as we then need to re-read the whole thread. Just post any new information as we go along.

> So once the ADC-DMA is triggered by the timer, 32 samples must be taken

No.

DMA is not triggered by the timer, but by ADC's end-of-conversion signal.

You trigger only the ADC. And if you set it to single conversion, it converts once per trigger, so simply set the timer to generate triggers at 96kHz pace. Just make sure that sampling+conversion is set so that the single conversion is finished within 1/96kHz.

After timer triggers single conversion in ADC, ADC waits the sampling time, then converts, then sets the conversion complete flag which triggers DMA to pick the result and move it to RAM. ADC is then idle until the next trigger from timer.

And as gbm said above, if you want to process N samples at once, make the DMA circular with NDTR=2xN, then you'll be interrupted by the half-complete and the transfer-complete interrupts at each N samples.

And hopefully you don't use Cube/CubeMX.

JW

Robmar
RobmarAuthor
Senior II
December 3, 2022

Its working circular DMA​ mode, but the ADC couldn't be set to complete 32 samples in exactly 333.3r uS due to sample clock options.

​So the ADC-DMA in DMA continuous requests mode can be set to do one transfer per timer trigger and increment the target address for the next ADC completion + trigger?

I'd thought that the DMA continuous requests ​mode incremented memory only during each run.

So how do I set it up, EOC at end of single, HAL_HDC_Start_DMA with length of 1 just once called at start for both ADCs, then HAL_Tim_Start to get both ADCs starting synchronised?

How does the MCU know to increment the address each trigger, and when to reset, like every 32 runs?​

Piranha
Principal III
December 3, 2022

The DMA doesn't care whether the ADC converts sequences or single conversions. It just transfers the data, when the data is ready, and increments addresses as configured. All of it is explained in the reference manual in the TIM, ADC, DMA chapters respectively.

AScha.3
Super User
December 3, 2022
  • sorry, but what should be the real target of this ? 96k makes me think on hi-end audio , 96/24 recording.

if this is it about, first take a matching clock. i took AS318 low jitter osc. 49.152MHz as master clock;

( on H743 cpu ) , THEN you can talk about speed and precision and so on.

not when beginning with useless clock.

If you feel a post has answered your question, please click on " Best Answer ".
Robmar
RobmarAuthor
Senior II
December 3, 2022

The clock is stable enough, and the 32F407VG already over £20 compared to the Arduino 328P which works perfectly well with dual ADC sampling in the very same application. I already have the code working perfectly but not at the exact target sample rate.

The aim is to sample efficiency with minimal CPU loading.​

gbm
Super User
December 3, 2022

You seem to ignore what I and Jan wrote. The ADC sampling time setting is (almost) irrelevant to your problem. Just set the timer to the required sampling frequency, line 96 or 192 kHz, which will trigger the SINGLE ADC conversion with the required frequency. Please re-read my and Jan's post. And yes, it's much easier to do this without HAL, at register level.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
Robmar
RobmarAuthor
Senior II
December 3, 2022

Please re-read my comments I think I wasn't clear

So, one memory incremented automatic transfer per trigger, how exactly?

Call hal_adc_start_dma() with size=1, but how does it know the target buffer size to increment the address each dma transfer?

Call the function with size 32 and it will just transfer 32 samples each trigger!

The "number of conversions" entry in MX relates to polling ADC inputs, it's not a special trigger-by-trigger dma to incremented memory mode.

Think about it, there is not an indicated way to do this in any document.​

 I would like to be wrong about this so please say where this mode is exactly activated because for the life of me I can't see its in the datasheet, STM's app notes, or YouTube videos

Piranha
Principal III
December 3, 2022

> Unless you are able to explain exactly where one selects this "single sample transfer with DMA to incremented memory" mode, what you´re saying has very little value.

That is the only mode the DMA does, because there is no "transfer multiple non-existing samples" mode - you made that up in your fantasies!

Until you read the reference manual... "what you´re saying has very little value". Open it and read the section "13.8.1 Using the DMA":

When the DMA mode is enabled (DMA bit set to 1 in the ADC_CR2 register), after each conversion of a regular channel, a DMA request is generated.

Robmar
RobmarAuthor
Senior II
December 3, 2022

So what?! I need it to increment the memory address ​each trigger, and reset the address after n samples.

Tell me where it says that's possible on single sample triggered ADC-DMA ​transfers?

Think about it​

Piranha
Principal III
December 3, 2022

> So what?!

About what? The quote literally tells when exactly the DMA request is generated! The DMA services the request and sits idle until the next one, not reads the same register multiple times with a maximum rate for no purpose. Incrementing (or not) memory address and setting a buffer length are DMA features and does not depend on ADC in any way.

> Think about it​

Think about reading the reference manual and all the posts in this topic! There is no special note in documentation like: "The only way, the DMA works, is actually possible."

Why don't you just try it? Set the timer triggering ADC with a 96 kHz rate and set the DMA to circular mode with 2*32 transfers. That's it!

Robmar
RobmarAuthor
Senior II
December 4, 2022

And the EOC per conversion, not end of conversions? Then it'll just have time to do one sample until the next trigger....mmm I hope, will test that out, fingers crossed​