cancel
Showing results for 
Search instead for 
Did you mean: 

ADC sample rate impossible to set precisely (calculations added)

Robmar
Senior III

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.

43 REPLIES 43
S.Ma
Principal

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

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

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

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

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

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

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

(just posted my math in the main question)

> 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