Fortunately, there are many analog input chips that use the SPI or I2C bus, making it almost trivial to add analog inputs to the Pi. I chose the MCP3008, an 8 channel 10 bit ADC available from Adafruit.com. Add a bi-directional logic level converter and some connectors and you're ready to go.
The level converter is on my main interface board which provides two SPI bus connectors. The analog interface is a simple board which includes a connector for SPI, the MCP3008 chip, a jumper to choose the analog reference, and screw terminals for the inputs. I ended up adding several more screw terminals connected to 5V in order to power thermistors.
The SPI serial bus is full duplex, but the way it works may seems odd to a programmers point of view. (It makes perfect sense if you understand how the hardware works.) You may be familiar with how full duplex works on an RS-232 line: data can be sent and received at the same time, but independently. That independence is due to the fact that RS-232 is an asynchronous protocol. SPI is a synchronous protocol; meaning everything is driven by a clock pulse.
Data bits will be sent out the MISO line on each cycle of the CLOCK line. At the same time data bits are being read in on the MOSI line. The number of bits out is the number of bits you will read back in. This means that you may have to write more bits than expected for a given command and you may read bits that are unused.
Fortunately, we don't have to worry much about the ugly details at the lower level. There is a device driver for SPI that is included with the recent versions of Raspbian and the WiringPi library provides support for SPI I/O. The functions wiringPiSPISetup and wiringPiSPIDataRW are all that is needed. Here is the source code for a program that I used when testing and calibrating sensors.
#include <stdio.h>
#include <stdint.h>
#include <wiringPi.h>
#include <gertboard.h>
// read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7)
int readadc(adcnum)
{
uint8_t buff[3];
int adc;
if ((adcnum > 7) || (adcnum < 0))
return -1;
buff[0] = 1;
buff[1] = (8+adcnum)<<4;
buff[2] = 0;
wiringPiSPIDataRW(0, buff, 3);
adc = ((buff[1]&3) << 8) + buff[2];
return adc;
}
int main(int argc, char *argv[])
{
int i, chan;
uint32_t x1, tot ;
printf ("SPI test program\n") ;
// initialize the WiringPi API
if (wiringPiSPISetup (0, 1000000) < 0)
return -1 ;
// get the channel to read, default to 0
if (argc>1)
chan = atoi(argv[1]);
else
chan = 0;
// run until killed with Ctrl-C
while (1)
{
tot = 0;
for (i=0; i<100; i++)
{
// read data and add to total
x1 = readadc(chan);
tot += x1;
delay(10);
}
// display the average value
printf("chan %d: %d \n", chan, (tot/100)) ;
}
return 0 ;
}
Note: The SPI device is not loaded by default. The easy way to get it loaded is to used the "gpio" utility that comes with the WiringPi library. Just enter
gpio load spi
and the drivers will be loaded and ready to use.