Implementing direct digital synthesis in STM32 microcontroller

I am working on a project that requires phase locking (digitally) of an output signal from a sensor to the reference signal which needs to be done on STM32 microcontroller. I am new to this area, and just read some basic theory behind phase locked loop and direct digital synthesizer, however, I am lost to even get started.

I want to break down my task into generating sinewaves for DDS and then design a PLL in the microcontroller.

To get started, I thought of generating a sine wave based on a Look up table, that i can either import generated from other program/ create a function to generate directly in the stm32cubeIDE. However, this doesn't work because we have a waveform of a fixed frequency. For a PLL, we should be able to change the output frequency and we could do it either changing size of lookup table, value of prescaler or ARR. But for a PLL, how do we do this without having to change the values manually?

If anyone has idea in this topic, could you please guide me to get started and provide me some more insights to this topic ?

• You create different frequencies from your single quadrant LUT by changing the rate at which you access the LUT. This usually has to be many times the frequency you're trying to synthesize, unless you have something like a DDS chip, For example (foregoing the math here), if you want to synthesize a sine wave, you may have to access the LUT 1,000 times to create one cycle of the sine wave. If that desired waveform is 100 KHz, that you have to access the LUT 1,000 faster than that, or 100 MHz. Commented Feb 23, 2023 at 16:29
• Do you need real sine waves, or would the much cheaper (in terms of instructions, data space and code space to generate) triangle wave be suitable? What is the range of frequencies you need? Commented Feb 23, 2023 at 20:13
• I need a real sine wave to control the mirror movement. My range is around 5-10 KHz.
– Rima
Commented Feb 24, 2023 at 7:13
• The general method is to have a sine lookup table (LUT) of, say, 256 entries for one cycle. Declare a 32bit unsigned int variable as your phase accumulator. To do DDS, add a value to the phase accumulator, use the top 8 bits of the phase accumulator as the index into your LUT which gives you your output value. Rinse and repeat at a regular rate. Change the value you add to alter the frequency and/or phase. No need to cater for overflow - C doesn’t care and in binary it all works as a fixed modulus. For an adder of 2^24, one cycle is 256 iterations. Commented Feb 24, 2023 at 13:53

Essentially you do have to generate a LUT for your fixed frequency. You only need to do this once, then use a phase-accumulator to generate any frequncy you require. You may need to adjust to obtain higher fidelity by using linear interpolation between the LUT values. There was a similar question here, that may be interesting for your application and may be suitable for your requirement. Good luck !

If you need to generate a sine wave with variable frequency, but fixed sample rate, then you could consider writing code in the MCU to act as a "resonator".
This code is essentially a digital filter, but with coefficients chosen such that its output does not decay or settle, but in fact sustains itself in much the same way that a phase-shift oscillator does in hardware.

I used this technique many years ago, and borrowed the idea from an old (perhaps even ancient by now) app-note from Microchip.
That app-note is focused towards generating DTMF dial-tones by creating the 2 sine-waves independently and then adding them together to create the final "dual-tone".

Doing it this way means that you don't need a Lookup-Table to store a sine wave at sufficient resolution, but instead means that your MCU needs to be fast enough to perform the necessary calculations for each time interval.
Considering that you're proposing to use an STM32, presumably running at 100MHz or so, I wouldn't expect this to be a problem.

In the code I wrote, I managed to have an 8-bit PIC running at 16MHz generate 2 sine waves in the 200-300Hz range, sampled at about 10kHz, with enough processing power to simultaneously perform UART comms at 115200 as well as some other processing duties.
In the initial version, the bulk of the code was written in C, but I had some hand-optimized assembler for the most critical bits.
In later iterations when I was able to use a faster MCU I ported all the code onto the new device and had it all written in C.