|Raspberry Pi IoT In C - AtoD With The SPI Bus|
|Monday, 01 August 2016|
Page 2 of 2
Connecting MCP3008 To The Pi
The connection to the PI's SPI bus is very simple and can be seen in the diagram below.
The only additional component that is recommended is a 1uF capacitor connected between pins 15 and 16 to ground mounted as close to the chip as possible. As discussed in the previous section you might want a separate voltage reference for pin 15 rather than just using the 3.3V supply.
Now we come to the configuration of the SPI bus.
We have some rough figures for the SPI clock speed - 10kHz to a little more than 1.35MHz. So an initial clock divider of 4096 giving a frequency of 61kHz seems a reasonable starting point.
From the data sheet the CS has to be active low and the most significant bit first is the default for both the master and the slave. The only puzzle is what mode to use? This is listed in the data sheet if you look really carefully and it can be mode 0,0 with clock active high or mode 1,1 with clock active low.
For simplicity we can use mode 0,0 which is mode0 in the bcm2835 library.
We now have enough information to initialize the slave:
Now we have the SPI initialized and ready to transfer data but what data do we transfer? The SPI bus doesn't have any standard commands or addressing structure. Each device responds to data sent in different ways and sends data back in different ways. You simply have to read the data sheet fo find out what the commands and responses are.
Reading the data sheet might be initially confusing because it says that what you have to do is send five bits to the slave - a start bit, a bit that selects its operating mode single or differential and a three bit channel number. The operating mode is 1 for single ended and 0 for differential. So to read channel 3 i.e. 011, in single ended mode you would send the slave
where xxx means don't care. The response from the slave is that it holds its output in a high impedance state until the sixth clock pulse it then sends a zero bit on the seventh followed by bit 9 of the data on clock eight. That is the slave sends back:
where x means indeterminate. The remaining 9-bits are sent back in response to the next nine clock pulses. This means you have to transfer three bytes to get all ten bits of data.
This all makes reading the data in eight bit chunks confusing.
The data sheet suggests a different way of doing the job that delivers the data more neatly packed into three bytes. What it suggests is to send a single byte
the slave transfers random data at the same time which is ignored. The final 1 is treated as the start bit. If you now transfer a second byte with most significant bit indicating single or differential mode, then a three bit channel address and the remaining bits set to zero the slave will respond with the null and the top two bits of the conversion. Now all you have to do to get the final eight bits of data is to read a third byte:
You can do it the first way that the data sheet describes but this way you get two neat bytes containing the data with all the low order bits in their correct positions.
Using this information we can now write some instructions that read a given channel. For example to read channel zero we first send a byte set to 0x01 as the start bit and ignore the byte the slave transfers. Next we send 0x80 to select single ended and channel zero and keep the byte the slave sends back as the high order two bits. Finally we send a zero byte so that we get the low order bits from the slave i.e.
Notice you cannot send the three bytes one at a time using transfer because that results in the CS line being deactivated between the transfer of each byte.
To get the data out of readBuf we need to do some bit manipulation:
The first part of the expression extracts the low three bits from the first byte the slave sent and as these are the most significant bits they are shifted up eight places. The rest of the bits are then ored with them to give the full 10 bit result.
To convert to volts we use:
assuming that VREF is 3.3V.
In a real application you would also need to convert the voltage to some other quantitiy like temperature or light level.
Some Packaged Functions
This all works but it would be good to have a function that read the AtoD on a specified channel:
Notice that this only works if the SPI bus has been initialized and set up correctly. An initialization function is something like:
Once you have the basic facilities working the next question is always how fast does something work. In this case we need to know what sort or data rates we can achieve using this AtoD converter.
The simplest way of finding this out is to use the fastest read loop, for channel 5 say:
With the clock divider we used earlier:
we get a measured clock rate of 61kHz the sampling rate is measured to be 2.26kHz. This is perfectly reasonable as it takes at least 24 clock pulses to read the data. Most of the time in the loop is due to the 24 clock pulses so there is little to be gained from optimization.
Increasing the clock rate to around 900kHz by setting the divider to 256 pushes the sampling rate to 36kHz which is just fast enough to digitize audio as long as you don't waste too much time in the loop in processing.
Changing the clock rate to 2Mhz, divider 128, pushes the sampling up to 70kHz which is plenty fast enough for most audio.
The fastest sample rate achieved with the samples of the device to hand was a clock rate of 4Mhz, divider 32, and a sampling rate of 216kHz - however the readings became increasingly unreliable in the low order bits. Perhaps this could be improved with the use of a buffer and careful layout but for a prototype board a sampling rate of 70kHz is the limit. Also notice the clock rate goes up you have to ensure that the voltage source is increasingly low impedance to allow the sample and hold to charge in a short time.
Making SPI work with any particular device has four steps
Raspberry Pi And The IoT In C
By Harry Fairhead
This is a chapter from our ebook on using the Raspberry Pi to implement IoT devices using the C programming language. The full contents can be seen below and note that the full book is hosted on our sister site IoT Programmer.
Notice this is a first draft and a work in progress.
or email your comment to: firstname.lastname@example.org
|Last Updated ( Monday, 01 August 2016 )|