This example demonstrates a method of generating more complicated analog signal using simple DAC. To be more precise, **sine wave** but the same method can be used to generate any type of wave.

In the previous example it was shown how to generate voltage level using PWM and low pass RC filter.

If you change voltage level you get not horizontal line but wave. The shape of the wave depends on the way you change voltage level.

To set output voltage from RC filter, RMS value of PWM must be changed what means output voltage is proportional to **OCRx**.

The wave on the above picture has only 32 levels to show the idea. To get nice smooth wave, we need to increase the number of levels for one sine period. In connection with RC filter this give us sine wave that looks like true analog not discrete wave.

In the example *timer0* is used in Fast PWM mode to achieve the maximum frequency of the sine wave.

# Wave table generation

For this example we use 256 samples. sin() function gives values from -1 to 1. PWM duty cycle is controller by OCR0 register, so we need values from 0 to 255.

Equation for the *n* sample is:

256 is the number of samples.

For practical implementation see `InitSinTable()`

function in the sample code.

# Filter

We use the same type of filter as in previous example but with different parameters.

In the previous example frequency of the wave was 0Hz, that is we assumed output is constant in time. For sine wave this is not true and new values of C and R must be used.

This article is not about low pass filters, so filter theory is limited to minimum. In other words, just use **R=10kΩ** and **C=0.1µF**.

The most important parameter of the filter is **cut-off** frequency. For RC low pass filter it is:

which gives us f_{cutoff}=159.2Hz. The filter passes frequency from 0 to 159Hz. Good filter should generate smooth waves in desired frequency of sine wave.

# Sine wave frequency

We use *timer0* in Fast PWM mode and prescaler 1 to generate PWM signal. For 8MHz clock:

Period is equal to 1/31250=0.000032s (32µs). As 256 samples is used to generate sine wave, period of the sine wave is 256×0.000032s=0.008192s. From that frequency is: 1/0.008192=122.07Hz.

In other words frequency of the resulting wave is always:

where *Samples* is the number of samples. Note, that this equation is true for any wave not only sine wave.

The same modified equation gives the answer what PWM frequency use to achieve specific analog wave frequency:

To change the frequency of the sine wave you can:

- Change PWM frequency (set prescaler or system clock or use different PWM mode with smooth frequency control)
- Change the number of samples

# Code snippets

OC0 pin as output.

DDRB |= _BV(PB3);

Configure Fast PWM mode of *timer0*

TCCR0 |= _BV(WGM01) | _BV(WGM00); //mode 1, Fast PWM TCCR0 |= _BV(COM01); //Clear OC0 on compare match, set OC0 at BOTTOM TCCR0 |= _BV(CS00); //prescaler divider 1

# Sample code

The example code (pwm_sinusoid.zip) generates sine wave on **OC0** pin. This signal is then filtered by low pass RC filter. To see the results an oscilloscope must be connected to the output of RC filter (see diagram at the beginning).

First *timer0* is initialized (Fast PWM Mode). Then Timer/Counter0 Overflow Interrupt is enabled. The interrupt routine changes PWM frequency every time *timer0* overflows. That automatically synchronize PWM frequency change and the end of PWM period. Fast PWM mode is not phase correct, so this simple solution prevents from changing PWM frequency in the middle of the period.

When macro `COMPUTE_SINE_WAVE`

is defined program compute sine table at startup. Playing a bit with `InitSinTable()`

function it is possible to generate any wave. By default program uses predefined sine table with 256 samples.

To increase or decrease the number of samples value of `WAVE_PROBES`

must be changed. In addition `COMPUTE_SINE_WAVE`

must be defined to force program to compute new samples.

## Oscilloscope snapshots

Sine wave - output from the RC filter. Grid: 1ms/0.5V.

Two signals: PWM (yellow) and sine wave (blue). PWM duty cycle grows from left to right. Grid: 50µs/0.5V.

# Additional links

- Filtering PWM Signals by Jim Wagner
- Using the AVR’s High-speed PWM by Atmel

Attachment | Size |
---|---|

pwm_sinusoid.zip | 3.92 KB |