paulv
Posts: 563
Joined: Tue Jan 15, 2013 12:10 pm
Location: Netherlands

HOWTO: Add an analog output to the Pi (PWM)

Sat Oct 24, 2015 7:10 pm

In this post I will show you how to add an analog output to the Pi.
In an earlier post, I showed how you can add an analog input to the Pi, I suggest you read that as well.
viewtopic.php?f=37&t=123962

There are at least two different methods to add analog outputs to the Pi, and in this post we will cover the use of the Pulse Width Modulation feature, or PWM method. In a later separate post, we’ll cover the use of a real Digital to Analog Converter chip, or DAC.
Here is that post : viewtopic.php?f=37&t=124184

The selection of which method you should choose depends on your application. To keep it simple, we will use the PWM method to create a variable but steady (static) voltage level. An example would be to drive a power supply, where the output voltage or current depends on a DC voltage input level. Typically the input voltage for such an application would range from 0 to 10V DC to create voltage levels from 0 to 30V, or from 0 to 3Amps. Driving a frequency generator with a DC voltage level to produce varying frequencies is another example. Driving a dimmer to control main lights is yet another application.

In contrast, we will use an DAC chip to create very precise voltage levels or dynamic analog wave forms. This is something that is either difficult, or even impossible to do with the PWM method.

Using Pulse Width Modulation or PWM.

With PWM, we use a principle frequency, and change the on-off duration, or pulse width. The on-off duration or pulse width can typically be varied between 0 to 100%. We will use the on period (positive pulse period) to create a varying voltage level. The trick is to use the “energy” of the positive pulse period, and store that in a capacitor. By using a low-pass filter to remove the principle frequency, we can actually create a variable voltage across the capacitor, and use that to drive our application.
The schematic below shows how simple this actually can be:
D-A-PWM-1.png
D-A-PWM-1.png (21.29 KiB) Viewed 39613 times
The combination of R1 (1K) and C1 (4.7uF) creates a low-pass filter to reduce the principle frequency of the PWM wave forms. Because we only need a rather static output, the filter is not very critical. With the application I’m discussing here, you can just about use any value between 1uF and 47uF, and it will still work. However, if you want to use more dynamic outputs, the filter becomes more and more critical and the calculation is a science by itself. If you’re interested, Google for “rc low-pass filter design for pwm”.

The filter works well if the following circuit, the one you are driving, does not hamper the filter with a low input impedance load. In that case, the capacitor is loaded and may not reach the full voltage at the 100% duty cycle setting. The solution is easy, you can use a simple “voltage follower” circuit that is just one Op Amp. Op Amps have very high input impedance's, and very low output impedance's. The circuit then becomes like this:
D-A-PWM-2.png
D-A-PWM-2.png (28.42 KiB) Viewed 39613 times
I use an MCP603 here, because that chip will work with supply voltages as low as 3V3. You can use a lot of different Op Amp versions, as long as they work at 5V. You don’t need a more expensive rail-to-rail one, because with 5V there should be enough headroom to create a 3V3 output.
R2 is optional and used to balance the amplifier inputs somewhat.

In many cases, you will most likely need more than 0 to 3V3 as the output to drive your application, and in that case we’ll modify the voltage follower into an amplifier with some gain, without losing the impedance features.
In order to create higher voltage level outputs, we also need to increase the supply voltage for the Op Amp. Let’s assume you need an output of 0-10V DC for your application. In that case, select a supply voltage for the Op Amp of 12V. By using 12V, you again don’t need to use a rail-to-rail Op Amp because we have some headroom. If you only have access to 10V, you need to look for an Op Amp that has an output that can go as high as the supply voltage (rail-to-rail).

We now set the gain of the Op Amp to 10V / 3.3V = 3. The circuit below will show that solution:
D-A-PWM-3.png
D-A-PWM-3.png (40.04 KiB) Viewed 39613 times
R4 is a 10K-50K trimmer that you can use to set the gain from 1 to various other levels. In our case, it needs to be set to 5K for a gain of 3. You can also use two 10K resistors in parallel to create the 5K value. In this configuration, R2 becomes a bit more important for the input balancing, but is still optional.

One caution.
If you use voltages above 3V3, be very careful, because a mistake with 12V will ruin your Pi.

OK, so much for the hardware.

In order to create our PWM signal, we’ll use a little program that will do that for us.
The comments in the code will explain what it does in detail.

Code: Select all

#!/usr/bin/python
#-------------------------------------------------------------------------------
# Name:        D2A.py
# Purpose:     PWM driver for an AtoD application
#
# Author:      paulv
#
# Created:     24-10-2015
# Copyright:   (c) paulv 2015
# Licence:     <your licence>
#-------------------------------------------------------------------------------

import RPi.GPIO as GPIO
from time import sleep

GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)    # set GPIO 25 as output for the PWM signal
D2A = GPIO.PWM(25, 1000)    # create object D2A for PWM on port 25 at 1KHz
D2A.start(0)                # start the PWM with a 0 percent duty cycle (off)

try:

    while True:
        dutycycle = input('Enter a duty cycle percentage from 0-100 : ')
        print "Duty Cycle is : {0}%".format(dutycycle)
        D2A.ChangeDutyCycle(dutycycle)
        sleep(2)

except (KeyboardInterrupt, ValueError, Exception) as e:
    print(e)
    D2A.stop()     # stop the PWM output
    GPIO.cleanup() # clean up GPIO on CTRL+C exit


def main():
    pass

if __name__ == '__main__':
    main()
If you run it with
sudo python D2A
You can enter a duty cycle value, and if you connect a DMM to the output, you can verify the voltage output. The software works with all three circuits, so you can start with just the resistor and the capacitor, and have some fun.
With a simple circuit like this, the resulting accuracy may actually surprise you.

I'll leave it up to you to modify the program to experiment and create a ramp-up and ramp-down version by using two for-next loops, but make it so that you can follow the output on your DMM.

In a next post I’ll cover a true Digital to Analog Converter (DAC) to create some dynamic analog wave forms and also very precise output levels.

Stay tuned,

paulv

Return to “Automation, sensing and robotics”