In this tutorial, we explain how to use a PWM output to make a DAC (Digital to Analog Converter). Can be useful if the processor you're using does not have a DAC.

More about PWM

We have explained in the tutorial about PWM that if the PWM period is fast enough, the LED blink looks continuous to the eye. This is because the retina cells somewhat integrate the energy coming and this creats an averaging of the incoming light.

Integration? Averaging? This can hint about the use of a capacitor as a low pass filter. That's exactly what we are going to do.

The principle

When increasing the duty ratio of a square wave, its average value increases proportionally. In this program, we are going to use a timer both in PWM (i.e. without interrupt) and as a simple timer (with interrupt), and in the interrupt routine, we will change the duty ratio and leave the period as is.

In order to create a sine wave (or any other shape), we are going to store that wave in an array. This is quite easy, it can be done with any c program.

The program

We simply use one timer and set it for output and also for interrupt. I have also used one GPIO output to verify what happens. It gives a pulse everytime the index passes 0. The frequency 24MHz divided by the array length and the number of periods per second gives us the max frequency of the final signal. Concretely, if we use 24 MHz, 256-tap array and 256 possible steps, it gives us 24000000 / (256*256) or about 366 Hz. It can of course be adapted by varying the increment (sinindex) or the timer frequency.

In order to actually have an analog output out of a digital pin, we need to filter the output. Here is the filter:











After filtering the output, we get the following wave. There is a glitch I don't explain. Probably something wrong in the data. The filter is a simple RC filter, 220 Ω, 1µF. Note that it's not a real sine, but 1+sine. If we want the sine to be centered, it would be easy by using a high pass RC filter.

The yellow pulse indicates when the counter is set back to 0. Note that we could simply increment a 8-bit integer and let it roll back to 0.









Download the C code

A summary of the first tutorials has been added as a downloadable zip file here.