BLOG > Tutorial 8 for Arduino: SPI Interfaces

This tutorial was featured on the official Arduino blog on 3/9/2011

In this week’s arduino tutorial, we’ll be taking a look at SPI device control using the arduino.  Specifically, we’re going to be using the Analog Devices 5204 Digital Potentiometer to control the brightness of several LEDs.  Enjoy the video!

You can download the files associated with this episode here:

GNU GPL License Distributed under the GNU General Public (Open-Source) License. Please Attribute and Share-Alike.


Notes on this episode:

In this tutorial, I mistakenly called the adjusting element in a digital potentiometer the “washer.” It’s actually called a “wiper.”


  1. hi Jeremy
    thank you for the outstanding quality tutorials.
    i’m following all of your tutorials, it’s all very helpful for beginners like me.
    The last tutorial (8) on SPI was gave me little start on my SD card project.
    but I’m having hard time on finding a good example. I’m using Arduino UNO and SD card and some resistors for voltage divider. can you please make one tutorial on this it will be very helpful.

    thank you

  2. Thanks for your reply.

    I’m using micro SD card reader that i found on sparkfun

    which has the following pins

    and i’m using 4 photo resistors same ones you used for the youtube tutorial (03). i need to store all 4 light values (Serial.prints) on the SD card real-time text document (.txt).

  3. Warning: Dumb question incoming. :)

    In the schematic you have B1, 2 and 3 each going to their own 10K resistor, and then tied together at ground.

    What would be the practical implications/problems of tying all three together first, and then going through a single resister to ground?

    1. Not a dumb question at all! The 10k pull down resistors are creating a voltage divider with each of the internal 10k potentiometers. If we just used one resistor for all of them, then all the 10k potentiometers would be connected in parallel, effectively changing the values we would expect to see.

  4. Thanks for the great video, clear and simple!

    I was wondering, how do you control speaker volume with this? Any example?


  5. Awesome tutorial Jeremy.
    Just a small correction: eagle is not open source.
    Thanks dude, I’m anxious for you new tutorials …

  6. Hi Jeremy,
    very great tutorial(s). Awesome.
    I was wondering if maybe you as a pro could help me with this one:

    I am using a TLC 5490 on a Mega board. The TLC requires following SPI PINs:
    Mega pin 51 (MOSI) -> SIN (Tlc pin 26)
    Mega pin 52 (SCK) -> SCLK (Tlc pin 25)
    Mega pin 11 (OC1A) -> XLAT (Tlc pin 24)
    Mega pin 12 (OC1B) -> BLANK (Tlc pin 23)
    Mega pin 9 (OC2B) -> GSCLK (Tlc pin 18)
    However it is not using a CS.

    Now I would like to add the Ethernet ENC28J60 Breakout Shield which also uses SPI:
    NT Digital 2
    SO Digital 12
    SCK Digital 13
    SI Digital 11
    CS Digital 10
    VCC 3,3V
    I know that the MEGA uses different PINs for SDI than the smaller brothers, thats not the prob.
    The problem I see is that the TLC doesnt use SC which (I think) means that the TLC will always be called and I cannot call the ENC.

    Anyways, I am not a pro at all, I got most of my knowledge out of forums and tutorials.
    SO thats why Id like to ask you whethter you can help me on this one with a few ideas to solve the double SPI usage for these specific devices on a MEGA board.

    One more thing:
    the ENC requires 3.3v with (as I heard and read) about 250mA. Do you think I can try the 3.3v output of the MEGA anyways (though only gives up to 40 mA)? Instead, can I use the 5v Output without a voltage converter? As I read the ENC board is 5v tolerant. Some use 2x 1N4007 diodes between 5vOut and 3.3vIn but I am not quite sure if this is necessary or not. Others talk about a LM317 (which has a too big Drop Out) or rather a LM 3940 but I am still not sure if this is necessary at all.

    Hope you can hellp me, especially on the SPI usage.
    Would be great


    1. For the TLC 5490, how about you hook the 5V supply up through a transitor to a digital logic pin, and physically switch of power to the device when you are talking to Ethernet shield? As for the ENC, you should use an external supply regulated to 3.3V to power it. Don’t use 5V directly, and don’t bother trying to use the built-in 3.3V regulator. It won’t provide enough current.

  7. Well, might be an idea to think about. Just wondering – when turning off power of the tlc, even for 1-5secs, while communicating with the encshield – what will happen to my LEDs connected to the TLC? will they stay as they are? (e.g. at 50% PWM = 2048)?

    Anyways – if this would work – can you be more specific why I would need a transistor? COuldnt I just use the PIN as voltage instead of 5v and not using a transitor?
    Anyways – Would Pin21/Vcc ( be the one you mean?
    Would this transistor work (since I still have these in my electronic supply box): BC 337-40 Transistor NPN TO-92 45V 0,5A 0,625W

    For the Encboard I bought myself a LM1117 Low Dropout Voltage Regulator 3.3V, that should work since it provides up to 800mA. Will use two 22 F 6V Tantalum Capacitors – on each side one. You think 6v will work for this, even on the 5v Vin? (hope so cause i have these available)

    Thx a lot for helping me out on this

    1. No, the LEDs would turn off, because you removing power to the board. Presumably, this is not what you want…. If programmed effectively, it might be so fast that you don’t notice them turn on then off again.

      I suggested a transistor, because using the current provided by a logic pin will not be enough to light the LEDs. You can use that current to switch a transistor, that will then provide power to the LED board. You wouldn’t use the Vcc pin, you’d use a logic pin that you should switch in software.

      The TO-92 will work fine for this purpose.

      I’m confused by your 6V question. What in your system is 6V? Is there a 6V battery? Feed anything beteween 4.75 and 10V into the LM1117, and you’ll get the 3.3V output that you need.

  8. Could you have programmed the maximum voltage to the LEDs to ~3V and gotten rid of the resistors going into them?

  9. Hi Jeremy, Excellent tutorial, i have been looking for something like this for a while.

    I am a complete noob and was planning on adapting this method to use on a 8 channel dac chip. Im trying to send analogue signals to 6 servo amplifiers. The desired values for the signals will be calculated from a flight sim software. For the SPI registers and levels Is it possible to use real time values from another program instead of just using predetermined values? Thanks

  10. Hi Jeremy,
    I am an absolute beginner and I just have to say I am really enjoying this series, I have learned so much!

    I am having trouble deciding which components are suitable or better then others for certain circuits. For my first major project I want control multiple leds (30+), more then the arduino would allow. Would a digital pot like this be suitable or is this more of a shift register thing? Can I still use PWM on either method?

    Any help would be greatly appreciated.

    FYI. I have looked into multiplexing but I dont understand how it works.

  11. Alro Heating and Cooling, air conditioning service sites, air conditioning service
    Alro installs and maintains residential furnaces and air conditioners in the St. Louis, Missouri metropolitan area.
    find air conditioning service,

  12. hi Jeremy, i have a question.
    i tried to use hardware spi for a pcd8544 nokia 5110 display but it wasn’t a success. but it worked pretty well with software spi ( ) until i added a SD card with the project, (using the typical SD.h library). both work perfectly individually but when combining it doesn’t work. it would be great if u can explain why it is not compatible and any solutions for this issue ??

  13. Hey jeremy, firstly awesome tutorial and can we use the same code for the tlc5940 ic also follows the spi bus

  14. I noticed that after awhile you relaxed a bit and instictively used the correct term “Wiper”
    at 6.28 on the elapsed timer when you said “coming out of the wipers….”
    I knew that it was impossible for someone with so much knowledge to not know the correct term.

  15. On the “6V” question, I believe he was asking you if using caps rated for 6V on a 5V circuit is
    cutting it too close. Obviously there is more than enough margin on the 3.3V side but
    generally you want to use caps that are rated for at least 15% more than your circuit
    circuit requires to allow for the case of a cap that is slightly “below spec”.
    Since 15% above 5V=5.75V, 6V should be ok because that leaves another 5% margin.

    1. How much margin you leave should depend upon how tightly your system specs are constrained. I always like to think: “What’s the dumbest way that somebody could try to use this circuit?”, and then I design for that scenario. That often involves picking higher voltage rating capacitors to account for conceivable overvoltage events. Of course, you have to balance that with size and cost constraints, both of which increase with the voltage rating.

      1. I ran into the same problem. I wasn’t smart enough to realize I was ordering an SOIC version (which the link in Jeremy’s parts list took me too). The good thing is that I learned about SOIC and DIP and a variety of stuff, and that’s the purpose of all this. I ordered 2 of the duals that Jeremy pointed to, and I plan to experiment with daisy-chaining when they arrive (tomorrow, I hope).

        Meanwhile, I *think* I found the quad at digikey. I know Jeremy wants to remain loyal to element14, and that’s reasonable. Take a look at this

      2. OK. I got the MCP42010. I had mapped the pins to the corresponding ones on the AD5204, and tried Jeremy’s code as is. It did not work. I spent a lot of time checking connections, etc., but utlimately decided that there was some other difference between the devices. I did some research and found this thread on the Arduino forum There is a library at for the MCP4XXXXXX. I have more research to do to see why, but the RS pin (which I had assumed mapped to the PR pin on the AD5204) goes to arduino pin 8 and the SHDN pin to arduino pin 9. These are evidently used in the init and setValue routines. Jeremy’s setLed does not work.

        Next is to try daisy-chaining.

        1. The routine setvalue in the library mentioned above works, but it only uses the 2 pots on one mcp42010. Since my next step is to daisy-chaining I needed an alternative. I modified Jeremy’s setLed routine (and the for/next loop that invokes it) to pass byte 17 or 18 for pots 0 and 1. MCP42010 wants B000100001 for pot0 and B00010010 for pot2. FYI, B0010011 sets both.

          That works fine. Through trial and error, I learned that I did not need the initialization routine, or to use pins 8 and 9 for RS and SHDN, so I took the code out, including the include for the library, and sent the pins to Vcc as Jeremy suggested.

          I’ll report back when I figure out how to daisy chain these things to replicate Jeremy’s tutorial.

          1. Here’s the Code:

            // 2014-01-22 SPI using digital POT to contol 3 LEDs
            /* 2014-01-27 Jeremy’s quad POT was not available as a DIP. Ordered
            2 duals instead (MCP42010),first step is do two LEDs, then we’ll try modify code for daisy-chaining.
            //include SPI library */
            /* 2014-01-30 I could not Jeremy’s example to work with the MCP42010. Research
            showed others with similar results. I found some code to use
            with the following libary. One difference–I had the RS and SHDN pins going
            to Vcc. The example had them on pins 8 and 9 and uses the init_MCP42xxx routine
            to initialize them in Setup.
            Thank you
            /* 2014-01-31 OK, above works, but I want to know why.
            First step is to see if I can get Jeremy’s setLed routine to work by changing
            arguments to bytes and using different values for command byte (B00010001 and B00010010 for pots 0 and 1).
            Learned that int works fine for level, and passed byte 17 (00010001) and 18 (00010010) in the for/next loop.
            Next step: find out what all that pin 8/9 for RS and SHDN was about. Learned I didn’t need it, so I took
            out the include for the library and the references.
            However, I did learn what my problem was: I was sending the wrong value for POT (different from AD5204).
            Now for daisy-chain.

            //set SPI slave select pin
            //By Default, 11 = MOSI, 12 = MISO, 13 = CLK
            //int Slave = 10;
            //discovered define command (defines constants
            #define Slave 10
            //2014-01-30 I assume this specifies which pot–dual or single (MCP4101)
            // need to research. 2014-01-31 don’t need it.
            //AH_MCP41xxx mcp42010;

            void setup() {
            //set Slave (others automatic)
            pinMode(Slave, OUTPUT);
            // initialize SPI
            // mcp42010.init_MCP42xxx (Slave, SHDN, RS); //initialisation [not needed]
            //function to set led to given level
            //2014-01-31 argument for reg is byte for MCP42010; set to 17 or 18
            //void setLed (int reg, int level)
            void setLed (byte reg, int level)

            digitalWrite(Slave, LOW);
            digitalWrite(Slave, HIGH);

            void loop()
            //loop through registers (using 1-3 which rep as 0-2)
            //2014-01-29 dual only has 0-1
            // for(int i=0; i <=2; i++) –original per Jeremy
            //2014-01-31 one difference is that MCP42010 wants bytes instead of ints and needs
            // B00010001 (17) for PA0 and B00010010 (18) for PA1

            for(byte i=17; i <=18; i++)
            //loop through levels (start at 50 because <50 not perceptible
            for(int j=50; j=50; j–)
            // mcp42010.setValue(j,i);

      3. The datasheet for the MCP4231 covers the MCP42010 that I am trying to use (It’s for MCP42XXX).

        As I describe below, I got it to work with one MCP42010 and 2 LEDs, one on each POT. To fully replicate the example in this tutorial, I went on to daisy-chain. I cannot get that to work. I have a thread on the arduino forum (, but I’m not getting anywhere. I posted schematics and code there.

        I’m hoping someone here has had success with daisy-chaining and could give me some guidance. It’s been a good learning experience–I’ve spent a lot of time with the datasheet and communicating with other users–but I am still where I started.

        Has anyone had success with daisy-chaining?

        Thank you. Virgil

        1. OK. I got it to work, but not by daisy-chaining. See the arduino forum for schematic and code:

          Rather than connect MISO on device 1 to MOSI on device 2, float MISO on device 1 and connect CS on device 2 to a free digital pin on the arduino, then reference the devices in code by their respective CS pin designations. SCK and SDI on #2 get wired to the same pins as #1 in parallel.


          1. Update: daisy-chaining works! I contacted MicroChip Technology Tech support. The answer is SPI Clock speed, which defaults to 4mhz on the Arduino. That’s too fast and the MCP42010 can’t keep up.

            I added this line to setup:

            That divides the Arduino speed of 16mhz by 16 to yield 1mhz for SPI–works like a charm

  16. Hi Jeremy, (thanks for the tutorials)

    My first go at this,
    I’m using a digital pot (the same as in your book but only 1) and I want to feed the PWM signal from the code to the digital pot. I’m getting stuck on the array bit.
    It is to drive a speed controller for a robot.
    Thanks again


    Servo ForwardAndReverse;
    Servo Braking;

    int Pot = A1; // Analog Input Pot from accl pedal to Arduino (split 50% forward + 50% reverse)
    int revSwitch = 12; // Digital input from Reverse Switch

    int potVal;

    int valForward;
    int valBraking;

    const int forwardSwitch = 9; // Output Pin for Speed Control (#15 of Kelly Controller)
    const int reverseSwitch = 10; // Output Pin for Speed Control (#14)
    const int brakeSwitch = 11; // Output Pin for Speed Control (#13)

    const int slaveSelectPin = 53; // Slave Select Pin

    const byte REG0=B00000000; //Register 0 Write command
    const byte REG1=B00010000; //Register 1 Write command

    void setup ()
    pinMode (slaveSelectPin, OUTPUT);

    ForwardAndReverse.attach(45); // pin for forward & reverse servo on Digipot
    Braking.attach(46); // pin for braking servo on Digipot

    pinMode (forwardSwitch, OUTPUT); //to 5 volt relay which switches Kelly Controller #15
    pinMode (reverseSwitch, OUTPUT); //to 5 volt relay which switches Kelly Controller #14
    pinMode (brakeSwitch, OUTPUT); //to 5 volt relay which switches Kelly Controller #13

    pinMode (Pot, INPUT);
    pinMode (revSwitch, INPUT);

    digitalWrite (forwardSwitch, LOW); //set the internal pull-down resistors
    digitalWrite (reverseSwitch, LOW);
    digitalWrite (brakeSwitch, LOW);
    digitalWrite (revSwitch, LOW);
    void setSpeeds(int slaveSelectPin, int reg, int level)
    digitalWrite(slaveSelectPin, LOW);
    digitalWrite (slaveSelectPin, HIGH);

    void loop ()
    int potVal = analogRead (Pot); // read the input value of the pot

    Serial.print(“Pot Value = “);

    if (potVal > 512) // adjust to neutral value of pot (Midway)
    digitalWrite (forwardSwitch, HIGH);
    digitalWrite (brakeSwitch, LOW);
    digitalWrite (reverseSwitch, LOW);
    valForward = analogRead (Pot);
    valForward = map(valForward,512,1023,0,1023); //values from Pot to Forward Digipot
    Serial.print (“\t Forward Val = “);
    Serial.print (valForward);
    Serial.print(“\t Forward Switch = High”);
    digitalWrite (forwardSwitch, LOW);
    digitalWrite (brakeSwitch, LOW);
    digitalWrite (reverseSwitch, LOW);
    Serial.print (“\t Forward Val = “);
    Serial.print (valForward);
    Serial.print(“\t Forward Switch = Low”);
    if (potVal < 512) // adjust to netural value of pot (Midway)
    digitalWrite(forwardSwitch, LOW);
    digitalWrite (brakeSwitch, HIGH);
    digitalWrite (reverseSwitch, LOW);
    valBraking = analogRead (Pot);
    valBraking = map(valBraking,512,0,0,1023); //values from Pot to Braking Digipot
    Serial.print ("\t Braking Val = ");
    Serial.print (valBraking);
    Serial.println ("\t Brake Switch = High");
    digitalWrite (forwardSwitch, LOW);
    digitalWrite (brakeSwitch, LOW);
    digitalWrite (reverseSwitch, LOW);
    Serial.print ("\t Braking Val = ");
    Serial.print (valBraking);
    Serial.println ("\t Brake Switch = Low");
    if (revSwitch == HIGH && potVal 512) // For Reverse using Forward Digipot
    digitalWrite (forwardSwitch, LOW);
    digitalWrite (brakeSwitch, LOW);
    digitalWrite (reverseSwitch, LOW);
    valForward = analogRead (Pot);
    valForward = map(valForward,512,1023,0,1023); //values from Pot to Forward Digipot
    digitalWrite (forwardSwitch, LOW);
    digitalWrite (brakeSwitch, LOW);
    digitalWrite (reverseSwitch, LOW);


    for (int i=0; i<=1023; i++)
    setSpeeds(slaveSelectPin, REG0, i);
    setSpeeds(slaveSelectPin, REG1, i);
    delay (10);

  17. Hi Jere,
    I am doing Weighing Scale project. I have searched for circuit, found few with AD7780 (24-bit) and AD7781 (20-bit) ADC. As per Data Sheet, it’s 2-wire serial interface (read only) and SPI compatible. I am confused how to connect AD7780/81 to Arduino. Please help me to resolve the issue.
    Thnak you.

    1. A 24-bit ADC is an option. You could also use a wheatstone bridge composed on four strain gauges feeding into an instrumentation amp, and then into the Arduino ADC.

  18. in the transfer() func. in the setLED func. how does the chip diffrentiates between the regester value and the level value and set them right ?

    1. With the CS pin set low, you do 2 spi.transfers, the 1st is the reg value and the second is the led level, both get transferred when the pin is set high. The settled function does that.

  19. Hi Jeremy,
    As everyone has said already, I love your tutorials! I am pretty new to using arduinos but picked it up pretty quick with a single unit. However there is an area I want to do, but I am struggling. I would like to use the speed of SPI communication but would like to know how hard it would be to control and read data from one arduino by another over the SPI lines. For instance turn a pot on master arduino and control a PWM pin on the slave arduino. And read an analog value on the slave arduino and display it on a LCD attached to the master arduino. Is this even possible or am I chasing a dragon? The reason for this is to control an underwater ROV (slave arduino) from a control board on the surface (the master arduino) over only a few wires (the SPI coms) via the tether cord. Any help on this would be greatly appreciated. If this is possible, maybe you could share a tutorial on how to achieve it. Thanks so much!

  20. Hi Jeremy,

    I want to replace 4 analogue potentiometers by digipots. The potmeters are 1k, 10k and 2x 100k. I wonder which digipot I could use for that? Preferably a quad digipot. All pots must have a range from 0 to its max resistance. Is it fine to use a 100K digipot (for example AD5204) and limit the resistance range in the code (0-1k, 0-10k,0-100k)?

  21. Hi Jeremy,

    Thanks so much for your tutorials. You are da man. I had an idea for a project and was wondering if SPI is a good way to do it.

    I want to have multiple LED matrices all individually controlled by one Arduino. I was thinking SPI or I2C could solve it. So I’d have one Arduino device controlling each LED panel and then one master Arduino to control all the slave Arduinos. Is there a better way to do this? I want to create an animated face, but based on human interaction the panels would change so they won’t be in a looping animation.

    Thanks so much for any help you can offer!

    – John

  22. hi jerremy,,
    i was wonder if you can help me about to read a specific line of data stored in sd card by enter specific number location in a serial communication input;

    for example i type 5 and click send in serial communication give me 5th line of data in text file,,
    i have been trying but i kind stack somewhere
    this my code


    File myFile;
    const int chipSelect = 4;
    int a;
    int sd[10]={};

    char b = 0; // for incoming serial data
    char c =0;
    void setup()
    pinMode(SS, OUTPUT);
    if (!SD.begin(chipSelect)) {
    Serial.println(“initialization failed!”);
    Serial.println(“initialization done.”);

    void ser()
    if (Serial.available() > 0)
    b =;


    void sdoku()
    myFile =“test.txt”);
    if (myFile) {

    while (myFile.available()) {

    for(int a =0;a<50;a++){



    else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
    void loop()

  23. Firstly great tutorial.
    I’m trying to communicate between an arduino uno and a arduino mega using SPI.I want to be able to send some bytes of data from the serial monitor at the master end and receive the same on the serial monitor at the slave end.How do I code?

  24. how to connect BMA180 accelerometer with arduinouno using SPI communication? Can u help me with circuit diagram and code????

  25. Hi Jeryme,
    I want to interface AD7780 (24 Bit ADC) and MAX7221 (Seven Segment Display Driver). AD7780 is 2 wire SPI and MAX7721 is 3 wire SPI. Can you please let me know how to connect with Arduino?

  26. Hello jeremy,
    there is no tutorial on GSM sim900 without using library effectively.
    can you help me in this?
    i’m using softwareSerial library for GSM modem as SerialEvent is not active in softwareSerial library so i’m facing so much problem in receiving SMS on sim900 without using GSM library.
    also i need your help in nRF24L01 RF sensor using arduino.

  27. Hi Jeremy

    I am trying to do the same with AD5203. I make the connections according to your diagram but I got no result. Can you help me ?

  28. Hello Jeremy,

    Im having problem in interfacing the Current sensor TLI4970 because no specific library. Could you help me?

  29. Hi Jeremy I was wondering if you are still around, I have a blow-by meter project. Wondering if you are still around to help.


    Jose Lozada

  30. Hi,
    Very good tutorial.

    ¿Can you esplaing how do the code for SPI arduino and ADE7758?

    I’m trying to read the temperature with this IC, but for me is impossible.

    (sorry for my English)

  31. hey man!I am using a DDS chip that is generating a wave with a fixed ampitude.I plan to control this amp with the help of the digipot(AD5206). I was hoping to find a conversion formula which will take the voltage input from the user and convert the value amongst the 256 levels of the digipot.Plz help

  32. Hello Jeremy,

    Please, i need your help.i am using L6474 Stepper motor Driver, so I want to send configuration registers to the IC By SPI Protocol please can you help me by sending a small code. Thank you

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.