Skip to main content
GGold.3
Associate
June 7, 2023
Question

I wonder if it is possible to use the DAC in STM32G4 to produce a 30kHz sinewave with 1Hz resolution.

  • June 7, 2023
  • 7 replies
  • 2788 views

The application is to fine tune acoustic resonantors. In other words we want to be able to tune DMA DAC output from 29.990 to 30.010 in 1 Hz steps. Ideally we also would like to tune the amplitude. There are some ideas with DAC reference prescalers and different LUTs. Any idea for a more elegant solution?

This topic has been closed for replies.

7 replies

waclawek.jan
Super User
June 7, 2023

DDS.

What is your expected sampling rate/reconstruction filter cutoff?

JW

GGold.3
GGold.3Author
Associate
June 7, 2023

At the moment we plan with 20 times oversampling, meaning about 600kHz, but this is potentially adjustable.

waclawek.jan
Super User
June 7, 2023

You can't achieve 1Hz step purely by integer division from cca 170MHz - the minimal step is around 5Hz. That's the case of "reference prescalers and LUTs". For cca 1Hz step you would need system clock of around 900MHz.

If properly written, you should be able to have around 1MHz sampling with software DDS (of course it's still timer/DMA based); question is, if spectral purity and amplitude stability are acceptable for your purpose - IMO the best way is to establish this experimentally. I've done 20Hz-20kHz test signal using DDS in 'F407 in the past, but I don't remember what analog qualities of the output signal have we achieved.

Other than DDS, a fractional-N PLL could perhaps be imagined, but that's nontrivial amount of external components and again, spectral purity is to be determined.

JW

TDK
June 7, 2023

Set up the DAC to trigger off of a timer via DMA, and also use DMA to reload the ARR value of that timer from a circular buffer of, say 100 points, on the update event. This gives you very fine control over output sine wave frequency.

Example:

Set up your DAC output buffer with 20 samples for a sine wave.

If your target sine wave frequency is 30 kHz, and your timer frequency is 50 MHz, you want 83.3333 ticks/sample, so set the ARR value buffer to be 83, 83, 84, 83, 83, 84, ...

With 100 samples in the ARR buffer, it would have 8333 ticks (67*83+33*84) total to output 5 full sine waves. So your exact output sine wave frequency would be 30001.2 Hz. If you remove a tick somewhere in the ARR buffer, it becomes 29997.6 Hz, so resolution of ~3.6 Hz. If you want a resolution of 1 Hz instead, increase the ARR buffer length to 500.

Edit: ARR values should be 1 less that what is written above, but that's in the details. Concept is there.

"If you feel a post has answered your question, please click ""Accept as Solution""."
GGold.3
GGold.3Author
Associate
June 7, 2023

Thanks for this idea. Might be worth to look into this especially since we aim to run a closed loop regulation the resonance peak to would just give as simple possibility for the PID controller to increase or decrease ARR counts...

TDK
June 7, 2023
One nice thing with this method is subtle adjustments can be made on the fly by modifying the ARR buffer without causing a discontinuity in the output.
"If you feel a post has answered your question, please click ""Accept as Solution""."
waclawek.jan
Super User
June 7, 2023

Hm, dithering in time domain. I wonder what the consequence for spectrum would be, as compared to the time-wise more regular DDS. Samples are also more "rough" amplitude-wise.

OTOH, much less computations, as you assume to calculate the ARR buffer only once.

JW

TDK
June 7, 2023
I think the error caused by the discrete DAC output will trump the error induced from the time slightly shifting. Depends on the application of course but a ~20ns shift is generally small when your signal of interest is 30kHz.
"If you feel a post has answered your question, please click ""Accept as Solution""."
waclawek.jan
Super User
June 7, 2023

> ~20ns shift is generally small

At 50MHz the individual sinewaves will differ by 15Hz, so in the spectrum you will basically have something like a merger of two peaks 15Hz apart, with mutual amplitude adjusted so that the "average center" will be at the frequency of interest. Of course this will be smeared into more-less one, but relatively wide peak.

> Depends on the application of course

+1

JW

AScha.3
Super User
June 7, 2023

well, question is: do you want/need full sinewave with many samples in constant pattern ?

then, as ...Jan and others explained, not possible.

if you can be ok with an little "noisy" pattern, then DDS is the solution.

because 32bit cpu here, lets take a 32bit dds -> and for good THD, 1024 elements 12 bit (data) value lookup table.

so we calculate a 32bit "phase-accu" , using top 10bits for the lookup table.

and we try calculation at 600kHz , = "sampling frequ." . (if we (cpu) can faster...good. we will see..)

the loop is simple:

// preset array with 1024 sinus values, one full 2pi wave
uint16_t sinval[1024];
 
uint32_t phase_sum, phase_speed;
phase_speed = 213909504; // for 29,882 KHz at 600k sampling
while(1 ...loop) // - or better : do in timer INT , called at 600kHz
{
 phase_sum += phase_speed; // sum just rolls over...for next sine wave :)
 DAC1->DHR12R1 = sinval[phase_sum>>22]; // DAC1->DHR12R1 = mod. -> dac write register
}
 

so resolution is about 0,00011 Hz . (average....and need low pass filter, maybe 40kHz , 12dB/Oct. )

"program" is just to show the way, not without possible error...

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