I picked up some digital potentiometers, partly as a building block for making a programmable filter for the ukulele tuner, but also just to play around with, as they seem pretty cool.
They act exactly like a traditional potentiometer (i.e. there's an end-to-end resistance of 10KΩ, with a 'wiper' that can travel from one end of the resistance to the other), but the position of the wiper can be controlled via digital signals. It seems that they do actually use physical resistors internally, in some fancy switched network. Anyway, these can normally be used to generate a variable voltage, but I'm also interested in being able to dynamically change resistance in order to tune a filter.
Originally, I assumed these would be an I2C interface (previous models I'd seen were), and didn't pay too much attention to the datasheet. I2C is great, because you can use 2 pins to control a whole string of devices, so long as they all have unique addresses. But it turns out that they're actually SPI, which is not so good for small microcontrollers, as even in its minimal form, it uses 3 wires per slave device. I'd ideally like to control 4 digital potentiometers with a single ATTiny85 - with just 5 data pins available (6 if I don't care about being able to reprogram more than once).
So - is it possible to control 4 or more SPI devices, using a single ATTiny85? Yeah, of course it is - with a bit of jiggery-pokery.
The trick, as it so often is when you don't have many pins, is to use a shift register (in my case, a 74HC595 that I happened to have around). This allows you to use 2 pins to clock in a serial binary data stream, and have it represented as a set of parallel output lines. In this case, I have an 8-bit shift register, so can turn 2 output pins into 8.
SPI defines a handy SS' pin, which is used to enable the SPI interface on any given device. If that is at a high logic level, then the device will ignore any SPI activity. On the digipots, this happens to be labelled CS', but that's fine - it's the same thing.
I therefore use
a single DATA line to drive the data input on both the shift register and all the digipots.
a single SPI CLK line to drive the SPI clock on all the digipots.
a dedicated SRCLK line to drive the shift register clock (tied together with the shift register data latch clock - as per the datasheet, this means that the shift register outputs are always updated, 1 cycle behind the internal register value).
I drive the CS' lines on each digipot from a separate output line on the shift register. That way, I can choose which one is active at any one time - or even program them all to the same value at once, if desired.
So, I'm using 3 digital output pins on the microcontroller, and I can individually address and program each SPI device - while still having 4 additional output lines available on the shift register, for driving LEDs or other devices. Pretty good! That leaves me with 2 pins on the microcontroller, which I can use for analogue input on the ukulele tuner - that should be just enough. Phew.
Here's the circuit showing how it all fits together.
And some demo code, showing how to address each potentiometer.
And finally, a video of it in action. I ran out of space on the breadboard to use all 4 potentiometers, but you can see it running here with 3. The red LEDs show which of the digipots is currently being addressed, and the RGB LED shows the wiper position being written to it : Red = 0, Yellow = midpoint, Green = max. The multimeter is measuring the resistance from the wiper to one end of the potentiometer, in KΩ.