cancel
Showing results for 
Search instead for 
Did you mean: 

How to generate a sine wave using PWM and RC filter with the STM32 Part1

B.Montanari
ST Employee

How to generate a sine wave using PWM and RC filter with the STM32?

  1. Introduction:

Generating a sine wave signal using an integrated DAC port in the board and DMA commands could be considered a simple task. However, what can be done to generate a sine wave signal if the board does not have an embedded DAC port?
The main objective on this article is to demonstrate how to generate a fully controllable sine wave signal using the Timer in PWM mode with a small Low-Pass Filter (LPF) circuit. As a fully controllable sine wave signal, the demo code will allow the user the possibility to choose the desirable frequency and amplitude via UART. This example has been tested with NUCLEO-G070RB board and can be easily tailored to any other supported device and development board.
 

2. Pre-requisite:
To develop this article’s proposal implementation, the following materials are needed:
 - Hardware:
  • Micro USB Cable: to power and program the board
  • NUCLEO-G070RB
 
432.jpg
  • Small prototype board for the filter – this article used these values for 80Hz
    • LPF:Resistor (20KΩ)
    • Capacitor (0.1µF)
  • Scope (optional)
 - Software:
  • STM32CubeIDE version 1.10.0 or later
  • TeraTerm or similar
3. Theory:
The PWM signal along with the LPF is a simple and effective method for digital-to-analog converter implementation. While the PWM will have a fixed frequency it is duty cycle will vary, maintaining a proportional relation with the output signal. It means that if the duty cycle is 0% the output signal will be 0V, and if the duty cycle is 100% the output signal will be the STM32’s voltage, which will be 3.3V for the NUCLEO-G070RB.
To implement the negative quadrants of the sine wave, keeping in mind that the duty cycle cannot generate a negative value, the demo implementation will have the 50% duty cycle acting as the midline of the sine wave, which allows the maximum amplitude range when it comes to peak-to-peak control for the sine wave output.
          The sine generation will rely on a pre-calculated table used as a vector instead of a sine math function generator in the code, which will optimize the code performance. This simple table can be re-created and modified with any other desirable settings and size, but for this application the table was divided in 360 positions, one for each degree. There will be a sine function per degree multiplied by the PWM counter value divided by 2, plus the offset. To keep the relation between the duty cycle and the negative values of the sine wave, the offset will be 50 and the PWM counter will be 100 just to favor the proposed logic and percentage direct analogy.
These values will be constantly updated in the timer’s PWM register, which means that the duty cycle will change to the values that are on the table and this will result in the desired sine wave, after passing through the LPF. Finally, the user will choose both the frequency and amplitude of the final output signal, via UART.
4. Development:
First, we need to create a new project in STM32CubeIDE interface for the STM32G070 board. After creating a new project, go to the Board Selector page and write “NUCLEO-G070RB” in the Commercial Part Number, click on the corresponding board and click on Next.
434.png
 437.png
After that, name the new project created and click on the Finish button. Right after, click on Yes to the pop up about initializing all peripherals.
440.png443.pngThe first step is to re-configure the clock that will be used for the TIMER3. Go to the Clock Configuration tab and ensure the HCLK (MHz) has a 16 value.
446.png
Now, is time to configure the pins. In the Pinout & Configuration tab, click on the pin PC7 and select TIM3_CH2. After that, go to Timers and select TIM3, put “Internal Clock” in the Clock Source and “PWM Generation CH2” in the Channel2, all contained in the TIM3 Mode and Configuration tab. In the Configuration tab, configure the Counter Settings and the PWM Generation Channel 2 as the picture below.
448.png
Click on the NVIC Settings and check the box that shows TIM3 global interrupt.
455.png
 And that is it for the TIMER3. This timer will be the main timer, which will generate the PWM signal that will be used to create the sine wave further on. The values on the Prescaler and on the Counter Period gives a 10kHz timer base frequency and the Pulse value on the PWM Generation Channel 2 is related to the duty cycle, which will be half of the Counter Period.
Now, it is time to configure the Auxiliary Timer (TIMER6), used to create the desired frequency by the user input, so it will be a flexible and dynamic configurable timer – it will specify the increment tick to construct the sine wave from the table positions. First, click on the Activate box in the Mode tab. This is the simple formula used to calculate the correct Counter Period got any given frequency received over UART:
457.png
Where:
460.png

The 360 used is the number of steps taken until the sine wave is completed. Therefore, since the TIM6 Counter frequency is 1MHz and the desirable sine wave frequency is initially 60Hz, that gives a 46 Counter Period initial value.
462.pngAlso check the box to activate the TIM6 global interrupt on the NVIC Settings.
464.pngNow, it is necessary to configure the UART. In the Connectivity, select USART2 and set the Word Length to 8 bits, the Parity to None and the Stop Bits to 1.
467.pngAfter that, check the box in the NVIC Settings to allow the global interrupt.
468.png
Finally, the only thing that remains is the configuration of the User Button (the blue one), connected to the PC13 pin. Click on the pin PC13 and select GPIO_EXTI13 and go to the System Core, select GPIO and click on the PC13, make sure to use the mode as Falling Edge trigger detection, no pull-up and no pull-down and label it as you wish. The pin will be used to switch the parameter to configure from “frequency” to “amplitude”.
469.pngAfter that, check the box in the NVIC Settings to global interrupt.
470.pngAll set! Generate the code for the configurations made to take effect, going to Project -> Generate Code.
In
part2 we'll cover the code implementation and a few scope images showing the expected output
See you soon!

  
Version history
Last update:
‎2022-08-30 09:19 AM
Updated by: