Generating Sine, Triangular, and Sawtooth Waveforms using STM32F4 DAC

STM32F4 Waveform Generation using DAC

The STM32F4 microcontroller series is popular in embedded systems applications due to its powerful features. One of its key peripherals is the Digital-to-Analog Converter (DAC), which enables the generation of analog waveforms. In this article, I will show you how to generate sine, triangular, and sawtooth waveforms using the STM32F4 DAC and MATLAB.

The STM32F4 DAC provides one or more channels that can be used to convert digital values into analog voltages of 12-bit resolution. With proper configuration, the DAC can generate precise and smooth analog waveforms.

Setting up the DAC

Enabling the DAC of the STM32F4 is easy by using STM32CubeMX.

  1. Select STM32F407VET6 as the microcontroller
  2. On Pinout & Configuration, select Analog > DAC then check the OUT1 Configuration checkbox.
  3. In the Parameter Settings box, set the ff:
    1. Output Buffer: Enable
    2. Trigger: Timer 2 Trigger Out event
    3. Wave generation mode: Triangle wave generation
    4. Maximum Triangle Amplitude: 15
  4. In Pinout View, click the PA4 pin and select DAC_OUT1

 

5. We also add two inputs for adjusting the frequency speed. These pins are mapped to the on-board buttons on the STM32F407 development board.

5. We also need to use the DMA controller to transfer the waveform data from memory to the DAC register for continuous output.

6. Finally, we setup the TIMER2 timer as this acts as trigger for our waveform generation.

After this, name your project and then click the "Generate Code" button on the top right. Now let's do some coding!

Generating Waveforms with MATLAB

MATLAB is a powerful tool for numerical computation and signal processing. We can leverage MATLAB's capabilities to generate waveform data and then transfer it to the STM32F4 microcontroller for DAC output. Here's a step-by-step guide:

Step 1: Generate Waveform Data in MATLAB:

In MATLAB, use built-in functions or mathematical equations to generate the waveform data for the desired waveform types (sine, triangular, or sawtooth). For instance, you can use the sin(T), sawtooth(T), or sawtooth(T, 0.5) functions to create the respective waveforms. Specify the desired duration, sample points, and DAC resolution for the waveforms.

Here's the MATLAB script for generating a sine wave:

clear; clc; % Clear The Previous Points
Ns = 128; % Set The Number of Sample Points 
RES = 12; % Set The DAC Resolution 
OFFSET = 0; % Set An Offset Value For The DAC Output 
%------------[ Calculate The Sample Points ]------------- 

T = 0:((2*pi/(Ns-1))):(2*pi); 
Y = sin(T);
Y = Y + 1;
Y = Y*((2^RES-1)-2*OFFSET)/(2+OFFSET);
Y = round(Y);
plot(T, Y);
grid
%--------------[ Print The Sample Points ]---------------

fprintf('%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \n', Y);

 

For the other waveforms, we only need to change the function. For Sawtooth:

clear; clc; % Clear The Previous Points
Ns = 128; % Set The Number of Sample Points
RES = 12; % Set The DAC Resolution
OFFSET = 0; % Set An Offset Value For The DAC Output
%------------[ Calculate The Sample Points ]-------------

T = 0:((2*pi/(Ns-1))):(2*pi);
Y = sawtooth(T);
Y = Y + 1; 
Y = Y*((2^RES-1)-2*OFFSET)/(2+OFFSET);
Y = round(Y); 
plot(T, Y);
grid
%--------------[ Print The Sample Points ]---------------

fprintf('%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \n', Y);

 

For Triangular:

clear; clc; % Clear The Previous Points
Ns = 128; % Set The Number of Sample Points
RES = 12; % Set The DAC Resolution
OFFSET = 0; % Set An Offset Value For The DAC Output
%------------[ Calculate The Sample Points ]-------------

T = 0:((2*pi/(Ns-1))):(2*pi);
Y = sawtooth(T);
Y = Y + 1; 
Y = Y*((2^RES-1)-2*OFFSET)/(2+OFFSET);
Y = round(Y); 
plot(T, Y);
grid
%--------------[ Print The Sample Points ]---------------

fprintf('%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \n', Y);

 

Step 2: Export Waveform Data from MATLAB

The MATLAB scripts above will generate the data needed to create a lookup table for the STM32 code.

For Sine:

2048, 2149, 2250, 2350, 2450, 2549, 2646, 2742, 2837, 2929, 3020, 3108, 3193, 3275, 3355, 
3431, 3504, 3574, 3639, 3701, 3759, 3812, 3861, 3906, 3946, 3982, 4013, 4039, 4060, 4076, 
4087, 4094, 4095, 4091, 4082, 4069, 4050, 4026, 3998, 3965, 3927, 3884, 3837, 3786, 3730, 
3671, 3607, 3539, 3468, 3394, 3316, 3235, 3151, 3064, 2975, 2883, 2790, 2695, 2598, 2500, 
2400, 2300, 2199, 2098, 1997, 1896, 1795, 1695, 1595, 1497, 1400, 1305, 1212, 1120, 1031, 
944, 860, 779, 701, 627, 556, 488, 424, 365, 309, 258, 211, 168, 130, 97, 
69, 45, 26, 13, 4, 0, 1, 8, 19, 35, 56, 82, 113, 149, 189, 
234, 283, 336, 394, 456, 521, 591, 664, 740, 820, 902, 987, 1075, 1166, 1258, 
1353, 1449, 1546, 1645, 1745, 1845, 1946, 2047

For Sawtooth:

0, 32, 64, 97, 129, 161, 193, 226, 258, 290, 322, 355, 387, 419, 451, 
484, 516, 548, 580, 613, 645, 677, 709, 742, 774, 806, 838, 871, 903, 935, 
967, 1000, 1032, 1064, 1096, 1129, 1161, 1193, 1225, 1258, 1290, 1322, 1354, 1386, 1419, 
1451, 1483, 1515, 1548, 1580, 1612, 1644, 1677, 1709, 1741, 1773, 1806, 1838, 1870, 1902, 
1935, 1967, 1999, 2031, 2064, 2096, 2128, 2160, 2193, 2225, 2257, 2289, 2322, 2354, 2386, 
2418, 2451, 2483, 2515, 2547, 2580, 2612, 2644, 2676, 2709, 2741, 2773, 2805, 2837, 2870, 
2902, 2934, 2966, 2999, 3031, 3063, 3095, 3128, 3160, 3192, 3224, 3257, 3289, 3321, 3353, 
3386, 3418, 3450, 3482, 3515, 3547, 3579, 3611, 3644, 3676, 3708, 3740, 3773, 3805, 3837, 
3869, 3902, 3934, 3966, 3998, 4031, 4063, 0

For Triangular:

0, 64, 129, 193, 258, 322, 387, 451, 516, 580, 645, 709, 774, 838, 903, 
967, 1032, 1096, 1161, 1225, 1290, 1354, 1419, 1483, 1548, 1612, 1677, 1741, 1806, 1870, 
1935, 1999, 2064, 2128, 2193, 2257, 2322, 2386, 2451, 2515, 2580, 2644, 2709, 2773, 2837, 
2902, 2966, 3031, 3095, 3160, 3224, 3289, 3353, 3418, 3482, 3547, 3611, 3676, 3740, 3805, 
3869, 3934, 3998, 4063, 4063, 3998, 3934, 3869, 3805, 3740, 3676, 3611, 3547, 3482, 3418, 
3353, 3289, 3224, 3160, 3095, 3031, 2966, 2902, 2837, 2773, 2709, 2644, 2580, 2515, 2451, 
2386, 2322, 2257, 2193, 2128, 2064, 1999, 1935, 1870, 1806, 1741, 1677, 1612, 1548, 1483, 
1419, 1354, 1290, 1225, 1161, 1096, 1032, 967, 903, 838, 774, 709, 645, 580, 516, 
451, 387, 322, 258, 193, 129, 64, 0

This will be the DAC levels, generated in between TIMER2 intervals, which will result in the specific waveform. The above data can be easily converted to an array in C like this:

#define NS 128

uint32_t Sine_Wave_LUT[NS] = {
2048, 2149, 2250, 2350, 2450, 2549, 2646, 2742, 2837, 2929, 3020, 3108, 3193, 3275, 3355,
3431, 3504, 3574, 3639, 3701, 3759, 3812, 3861, 3906, 3946, 3982, 4013, 4039, 4060, 4076,
4087, 4094, 4095, 4091, 4082, 4069, 4050, 4026, 3998, 3965, 3927, 3884, 3837, 3786, 3730,
3671, 3607, 3539, 3468, 3394, 3316, 3235, 3151, 3064, 2975, 2883, 2790, 2695, 2598, 2500,
2400, 2300, 2199, 2098, 1997, 1896, 1795, 1695, 1595, 1497, 1400, 1305, 1212, 1120, 1031,
944, 860, 779, 701, 627, 556, 488, 424, 365, 309, 258, 211, 168, 130, 97,
69, 45, 26, 13, 4, 0, 1, 8, 19, 35, 56, 82, 113, 149, 189,
234, 283, 336, 394, 456, 521, 591, 664, 740, 820, 902, 987, 1075, 1166, 1258,
1353, 1449, 1546, 1645, 1745, 1845, 1946, 2047
};

uint32_t Saw_Wave_LUT[NS] = {
0, 32, 64, 97, 129, 161, 193, 226, 258, 290, 322, 355, 387, 419, 451,
484, 516, 548, 580, 613, 645, 677, 709, 742, 774, 806, 838, 871, 903, 935,
967, 1000, 1032, 1064, 1096, 1129, 1161, 1193, 1225, 1258, 1290, 1322, 1354, 1386, 1419,
1451, 1483, 1515, 1548, 1580, 1612, 1644, 1677, 1709, 1741, 1773, 1806, 1838, 1870, 1902,
1935, 1967, 1999, 2031, 2064, 2096, 2128, 2160, 2193, 2225, 2257, 2289, 2322, 2354, 2386,
2418, 2451, 2483, 2515, 2547, 2580, 2612, 2644, 2676, 2709, 2741, 2773, 2805, 2837, 2870,
2902, 2934, 2966, 2999, 3031, 3063, 3095, 3128, 3160, 3192, 3224, 3257, 3289, 3321, 3353,
3386, 3418, 3450, 3482, 3515, 3547, 3579, 3611, 3644, 3676, 3708, 3740, 3773, 3805, 3837,
3869, 3902, 3934, 3966, 3998, 4031, 4063, 0
};

uint32_t Tri_Wave_LUT[NS] = {
0, 64, 129, 193, 258, 322, 387, 451, 516, 580, 645, 709, 774, 838, 903,
967, 1032, 1096, 1161, 1225, 1290, 1354, 1419, 1483, 1548, 1612, 1677, 1741, 1806, 1870,
1935, 1999, 2064, 2128, 2193, 2257, 2322, 2386, 2451, 2515, 2580, 2644, 2709, 2773, 2837,
2902, 2966, 3031, 3095, 3160, 3224, 3289, 3353, 3418, 3482, 3547, 3611, 3676, 3740, 3805,
3869, 3934, 3998, 4063, 4063, 3998, 3934, 3869, 3805, 3740, 3676, 3611, 3547, 3482, 3418,
3353, 3289, 3224, 3160, 3095, 3031, 2966, 2902, 2837, 2773, 2709, 2644, 2580, 2515, 2451,
2386, 2322, 2257, 2193, 2128, 2064, 1999, 1935, 1870, 1806, 1741, 1677, 1612, 1548, 1483,
1419, 1354, 1290, 1225, 1161, 1096, 1032, 967, 903, 838, 774, 709, 645, 580, 516,
451, 387, 322, 258, 193, 129, 64, 0
};

The full code can be seen in my repo: https://github.com/kurimawxx00/STM32F4WaveFormGen/

Step 4: Run the Application

Finally, upload and run the firmware on the STM32F407 development board. The microcontroller will receive the waveform data from MATLAB, configure the DAC and DMA, and generate the desired waveform on the DAC output pin. Press the K0 button the decrease or the K1 button to increase the frequency of the waveform. Press both K0 and K1 buttons to change waveforms.

Conclusion

By leveraging the STM32F4 DAC and MATLAB's powerful signal processing capabilities, we can generate precise and smooth waveforms like sine, triangular, and sawtooth waveforms in embedded applications. The combination of MATLAB's waveform generation capabilities and the STM32F4 DAC's accurate voltage output allows for versatile waveform generation in various applications such as audio synthesis, waveform analysis, and testing. Experiment with different waveform parameters and explore additional features of the STM32F4 DAC and MATLAB to further enhance waveform generation capabilities in your projects. Happy waveform generation!