Python Script

This ~100 line python script can be pasted into an editor and saved on your raspberry pi. You can also grab it directly from the pi if it's connected to the Internet by running git clone git://

The script is fairly simple. Half of the code (the readadc function) is a function that will 'talk' to the MCP3008 chip using four digital pins to 'bit bang' the SPI interface (this is because not all Raspberry Pi's have the hardware SPI function).

The MCP3008 is a 10-bit ADC. That means it will read a value from 0 to 1023 (210 = 1024 values) where 0 is the same as "ground" and "1023" is the same as "3.3 volts".  We don't convert the number to voltage, although its easy to do that by multiplying the number by (3.3 / 1023).

We check to see if the pot was turned more than 5 counts - this keeps us from being too "jittery" and resetting the volume too often.

The raw analog count number is then converted into a volume percentage of 0%-100%. When the trimpot is turned up or down it will print the volume level to STDOUT and adjust the audio level of the playing file by telling the mixer to adjust the volume.

#!/usr/bin/env python

# Written by Limor "Ladyada" Fried for Adafruit Industries, (c) 2015
# This code is released into the public domain

import time
import os
import RPi.GPIO as GPIO


# read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7)
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
        if ((adcnum > 7) or (adcnum < 0)):
                return -1
        GPIO.output(cspin, True)

        GPIO.output(clockpin, False)  # start clock low
        GPIO.output(cspin, False)     # bring CS low

        commandout = adcnum
        commandout |= 0x18  # start bit + single-ended bit
        commandout <<= 3    # we only need to send 5 bits here
        for i in range(5):
                if (commandout & 0x80):
                        GPIO.output(mosipin, True)
                        GPIO.output(mosipin, False)
                commandout <<= 1
                GPIO.output(clockpin, True)
                GPIO.output(clockpin, False)

        adcout = 0
        # read in one empty bit, one null bit and 10 ADC bits
        for i in range(12):
                GPIO.output(clockpin, True)
                GPIO.output(clockpin, False)
                adcout <<= 1
                if (GPIO.input(misopin)):
                        adcout |= 0x1

        GPIO.output(cspin, True)
        adcout >>= 1       # first bit is 'null' so drop it
        return adcout

# change these as desired - they're the pins connected from the
# SPI port on the ADC to the Cobbler
SPICS = 25

# set up the SPI interface pins

# 10k trim pot connected to adc #0
potentiometer_adc = 0;

last_read = 0       # this keeps track of the last potentiometer value
tolerance = 5       # to keep from being jittery we'll only change
                    # volume when the pot has moved more than 5 'counts'

while True:
        # we'll assume that the pot didn't move
        trim_pot_changed = False

        # read the analog pin
        trim_pot = readadc(potentiometer_adc, SPICLK, SPIMOSI, SPIMISO, SPICS)
        # how much has it changed since the last read?
        pot_adjust = abs(trim_pot - last_read)

        if DEBUG:
                print "trim_pot:", trim_pot
                print "pot_adjust:", pot_adjust
                print "last_read", last_read

        if ( pot_adjust > tolerance ):
               trim_pot_changed = True

        if DEBUG:
                print "trim_pot_changed", trim_pot_changed

        if ( trim_pot_changed ):
                set_volume = trim_pot / 10.24           # convert 10bit adc0 (0-1024) trim pot read into 0-100 volume level
                set_volume = round(set_volume)          # round out decimal value
                set_volume = int(set_volume)            # cast volume as integer

                print 'Volume = {volume}%' .format(volume = set_volume)
                set_vol_cmd = 'sudo amixer cset numid=1 -- {volume}% > /dev/null' .format(volume = set_volume)
                os.system(set_vol_cmd)  # set volume

                if DEBUG:
                        print "set_volume", set_volume
                        print "tri_pot_changed", set_volume

                # save the potentiometer reading for the next loop
                last_read = trim_pot

        # hang out and do nothing for a half second

After you have pasted this script into a file, make it executable:

chmod +x
This guide was first published on Jul 29, 2012. It was last updated on Jul 29, 2012. This page (Python Script) was last updated on May 04, 2015.