Intro: Using an Arduino to Control or Test an SPI Electronic Device
There are many electronic devices that use the SPI bus, or Serial Peripheral Interface bus, for communications (e.g. various sensors, LCD displays, digital potentiometers, D/A and A/D converters, wireless transmitters and receivers, audio volume controls). The devices receive data serially from a microcontroller using a 3-wire set-up that includes a chip select signal (usually titled CS - when this signal is at logic 0, a chip recognizes it will be receiving or sending data), a clock signal for clocking the serial data into the device, and the serial data stream itself.
Many hobbyists use microcontrollers such as the Arduino to control and use SPI devices. Oftentimes, you just want to test the electronic device to make sure it and its associated circuitry is working properly. This Instructables will show you how to set up and program a simple proto board circuit using the Arduino Uno to drive SPI data to a peripheral circuit which, in this case, is an Analog Devices AD7376 digital potentiometer. It could be any 8-bit SPI device using this circuit.
For this Instructables, I used an Arduino Uno board, a proto-board, some DIP (Dual Inline Package) switches (they are optional), a variety of jumper wires, a DC power supply, an ohm meter, a few capacitors for DC power supply smoothing, and a few pull-up resistors for the digital potentiometer. The AD7376 digital potentiometer is a surface mount device so I soldered it onto a surface-mount proto-PCB so it could be plugged into the proto-board. I used an oscilloscope to display the signals for this Instructables.
Assemble the Circuit: Place the Arduino board on the proto board in a convenient location. Next insert the DIP switches with all the pins on one side connected to ground (these DIP switches will provide the 8 bits of data that will be read by the Arduino and then sent serially to the AD7376). Wire digital pins 2 through 9 of the Arduino to the other side of the DIP switch, one wire per switch element.
Next, look at the datasheet of the device you wish to drive to find its pin-outs. Then connect Arduino pin 13 to the SPI devices Clock pin, Arduino pin 11 to the SPI device's SDI (Serial Data In) pin, and Arduino pin 10 to SPI device's CS (Chip Select).
Next, you must set a few parameters on the SPI operation - whether the LSB (Least SIgnificant Bit) or MSB (Most Significant Bit) is sent first, if the data is clocked into the peripheral on a rising or falling edge of the clock, and if you want to slow the transmit speed of the data by reducing the frequency of the clock). This data is explained well on the Arduino site (www.arduino.cc) and in Wikipedia so will not be covered here. For this example, the MSB is sent first, it is clocked on a rising edge.
Now it is time for the software. You must download the Arduino IDE (Integrated Development Environment) from www.arduino.cc. This development tool allows you to write code that can be uploaded to the Arduino board and then executed.
Insert the following code into the Arduino IDE. Note the comments in the code which tell you what each part of the code is doing.
* SPI test (Driving a Digital Potentiometer in this case)
* This module uses the Arduino SPI library (comes bundled with
* the Arduino IDE) to enable communication between an
* Arduino program and an SPI enabled peripheral chip.
* The routine reads in 8 bit values, stores the value
* in variable “pot”, and then sends “pot” out via the SPI.
* The SPI library uses pin 13 of the Arduino Uno for clock.
* Serial data is sent out on pin 11.
* This routine uses pin 10 as the chip select for the
* SPI device to be programmed.
* Pins 2-9 are used to read in values of the 8 bits for the byte
* to be sent via SPI
#include <SPI.h> // Links prewritten SPI library into the code
pinMode(2, INPUT); // Set pins 2-9 as inputs
pinMode(10, OUTPUT); // Set SPI pins to be outputs
digitalWrite(2, HIGH); // Set Arduino pull-up resistors active
digitalWrite(3, HIGH); // This sets an internal to the chip
digitalWrite(4, HIGH); // pull-up resistor on so an unconnected pin
digitalWrite(5, HIGH); // is reliably at logic 1
SPI.begin(); // Initialize SPI parameters
SPI.setBitOrder(MSBFIRST); // MSB to be sent first
SPI.setDataMode(SPI_MODE3); // Set for clock rising edge
SPI.setClockDivider(SPI_CLOCK_DIV64); // Set clock divider (optional)
// See Arduino site or Wikipedia for more info on these settings
int val = 0; // “val” is a test variable used when reading pins
int j = 0; // “j” is a variable used in data read operation
byte pot = B00000000; // Zero all bits in byte "pot"
for (int i = 0; i < 8; i++) // Loop to read each of 8 input pins
j = i + 2; // Add 2 to loop count to match input pins
val = digitalRead(j); // Read appropriate pin
if(val == HIGH)
bitSet(pot, i); // Set appropriate bit to 1 based on loop count i
} // Otherwise leave it at 0
digitalWrite(10,LOW); // Drop SPI chip-select to 0 (Arduino pin 10)
SPI.transfer(pot); // Do SPI transfer of variable pot
digitalWrite(10,HIGH); // Raise chip-select to 1
delay(10000); // Delay loop 10 seconds (pick your time frame)
} // Data will be read and sent once every 10 seconds based on this
Upload the program: Now, connect your Uno to one of your computer’s USB ports (your computer’s USB is used to power the Arduino). Make sure that under the IDE’s menu item Tools --> Board that the Uno is selected. Click on the Upload button in the IDE. You may get an error saying a COM port is busy, and a suggestion will be made to use an alternate COM port. Just click OK. Your program will then be sent to the Uno, the IDE will say it is complete, and the program will begin executing. If this does not happen, check your code for a typo as the code must be very precisely entered.
I also connected +/- 15 VDC to the AD7376.
Now all you need to do is to flick the DIP switches to the bit levels you want, either connected to ground for logic 0 or disconnected from ground and pulled up by Arduino internal pull-up resistors to logic 1. (You can optionally skip the DIP switch entirely and just connect the jumper wires to ground for the pins you want to be set as zero’s, and leave them unconnected for a logic one).
The above picture shows the actual signals (clock top, serial data middle, chip select bottom) on an oscilloscope and the resultant resistance of the potentiometer from its wiper to one of its arms.
This picture shows a different serial bit stream based on different DIP switch settings and the resultant different resistance of the potentiometer from one its wiper to one of its arms.
Using this simple setup, you can test and control virtually any 8-bit capable SPI device, as well as those that may use less than 8 bits).
(Note, some SPI devices require less than 8 bits. If the device you are interested in is one of these, just make sure the last "N" bits sent are the ones you want. For, example, the AD7376 requires only 6 bits. The first 2 bits of the 8 sent in the example are ignored - only the last 6 are stored and used.