Raspberry Pi Zero PWM Audio Interface

The Raspberry Pi Zero (I’m talking about V1 here, with no wireless.  At the time of writing, V2 has just been released and I’ve yet to have a play with that!) has capabilities on par with the first generation “full” Raspberry Pi, so I was keen to try my “Bare Metal” Raspberry Pi Synth on one.

But it doesn’t include any built-in audio (unless you use the HDMI output), so the first step is to add some circuitry that can hook into the GPIO and give you some audio out.  There are a number of off-the-shelf options for adding I2S digital to analog converters.  Here are a few that look particularly interesting, but I don’t have any of these to try (yet):

So this post is about a DIY option using the PWM capabilities of some of the GPIO pins on the Pi Zero, mirroring what happens with the built-in headphone socket on the original “full” Pi.

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

These are the key tutorials for the main concepts used in this project:

If you are new to microcontrollers and single board computers, see the Getting Started pages.

Parts list

  • Raspberry Pi Zero (probably any version, but I’m using the original “non wireless” v1)
  • RasPIO AnalogZero (as described here)
  • 15×5 hole protoboard or solderless breadboard
  • 2x 270Ω resistors
  • 2x 150Ω resistors
  • 2x 33nF capacitors
  • 2x 10uF capacitors (I used non-polar, but normal electrolytic should be fine too)
  • 3.5 mm TRS stereo jack socket
  • 1x 40 way (2×20) “stacking” header (optional).
  • 4x 10kΩ potentiometers
  • Header pins and connecting wires

The Circuit

Raspberry Pi PWM Audio Out_schem

This is the circuit that can be found here: Adding Basic Audio to Raspberry Pi Zero (Adafruit).  I have a solderless breadboard version and a “protoboard” version which you can see in the diagrams below.

Raspberry Pi PWM Audio Out_bb

PWM Output on the Pi Zero

The “full” Raspberry Pi (v1) has a headphone socket for audio output.  This uses PWM from some of the Pi’s “built-in” IO pins – i.e. pins that aren’t exposed on the GPIO header.  For the default device on a normal (v1) Pi this uses GPIO40 and GPIO45.  For later versions of the Pi, it uses various combinations of GPIO40, 41 or 45.

But as stated in the Adafruit article, the Pi Zero has no “built in” PWM audio device, but we can use the PWM capabilities of some of the IO pins that can be accessed from the 40-way GPIO header.  There are two PWM channels (0 and 1) and each channel gives us a choice of pins to use to access it as follows (see https://pinout.xyz/pinout/pwm):

Via the GPIO header:

  • GPIO 12 – PWM 0 (ALT 0)
  • GPIO 13 – PWM 1 (ALT 0)
  • GPIO 18 – PWM 0 (ALT 5)
  • GPIO 19 – PWM 1 (ALT 5)

Not broken out via the GPIO header:

  • GPIO 40 – PWM 0 (ALT 0)
  • GPIO 41 – PWM 1 (ALT 0)
  • GPIO 45 – PWM 1 (ALT 0)

You can see a full breakdown of all the GPIO pins and their “alternative functions” here: https://elinux.org/RPi_BCM2835_GPIOs.

The circuit above is using GPIO 12 and 13 to give a left and right channel of PWM audio.

Pi Zero PWM Output Circuit – First Version

Raspberry Pi PWM Audio Out 2_bbI’ve built the circuit onto a small (15×5) piece of protoboard then hot-glued it to a 40-pin stackable header so I can insert it between a Pi Zero and my AnalogZero add-on board.

Here are some photos of the final build.  I’ve tweaked the spacings a little compared to the original (above) so I can fold the 10uF capacitors down flat.

And here are some photos of it attached to the 40-way header ready for use:

You can see I’ve attached three wires directly to the long pins on the headers for GPIO 12, GPIO 13 and GND.  If you plan on using this with other hardware, you need to make sure GPIO 12 and 13 aren’t being used elsewhere.

Finally here it is in use with the AnalogZero and four potentiometers, using the set up described in the previous project blog.  You can see it in action in the video.

Pi Zero PWM Output Circuit – Second Version

Raspberry Pi PWM Audio Out 3_bb

This is an alternative proto board version of the circuit.  The aim here is to build it in a manner it can be permanently attached to a Raspberry Pi Zero without adding additional height for the GPIO connectors.  This includes a set of jumpers that allows the circuit to be disconnected from GPIO 12/13 if required, and also to select the alternative pin functions to use GPIO 18/19 as an option.

I’ve cut out a 24×18 piece of protoboard (and trimmed the edges) and created four mounting holes to align with those of the Pi Zero.

IMG_5564

The idea is that the 40-way header will have five of the pins replaced with longer pins to allow a connection to be made from the Zero to the protoboard underneath in the appropriate place.

The circuit is built across the top of the protoboard and then connected to the protruding longer GPIO pins on the underside of the protoboard (and them trimmed off).  Note that the Pi is mounted onto the protoboard using a short M2.5 screw with a nut and washer.  The washer acts as a separator to ensure nothing on the protoboard will short any of the conductive points on the underside of the Pi Zero.

The jumpers select between the two pairs of GPIO pins (the connections shown in yellow).

The Code

I’m using the same code as used before, but the circle environment has to be configured to use PWM for the Pi Zero.  This involves editing the file circle/include/circle/sysconfig.h and uncommenting the following line:

#define USE_PWM_AUDIO_ON_ZERO

By default this will enable PWM on GPIO 12 and 13, but there are also options to switch it over to GPIO 18 and 19 if preferred.

Once this change has been made, then the circle environment has to be rebuilt, the sample code has to be rebuilt and then the new kernel installed over onto the SD card.

:~$ cd src/circle
:~/src/circle$ ./makeall
:~/src/circle$ cd sample
:~/src/circle/sample$ ./makeall
:~/src/circle/sample$ cd ../src/circlesynth
:~/src/circle/src/circlesynth$ make
:~/src/circle/src/circlesynth$ cp ./kernel.img /media/path/to/sd/card/root

The circle environment will be able to detect if it is running on a Pi Zero or a “full” Pi and switch between GPIO 12/13 and the built-in headphone socket as required. If you want to see the gory details, have a look at the function GetGPIOPin in machineinfo.cpp.

Find it on GitHub here.

Closing Thoughts

I’m really pleased with this, and it is a bonus that the same SD card will work in a “full” Pi v1 and a Zero. I need to get back to the code though, as I want to do something more sophisticated with the modulation – it is all quite basic still at present.

In terms of developing the hardware, there are a couple more avenues to follow:

  • I like the idea of the Pimoroni Audio SHIM and I’m now wondering if it is possible to build the PWM output in a similar manner.
  • I’m also toying with the idea of adding the circuitry to the prototyping area of the AnalogZero, to make a nice “self contained” Pi Zero synth solution.
  • Next up is also to start experimenting with some I2S DACs to get a better sound output.

Kevin

IMG_5559

Leave a comment