Daisy-Chaining MCP42010s

I have been going through Jeremy Blum's Arduino Tuturial Series. Tutoral #8 is on SPI devices. His example used an AD4204 quad digital potentiometer. I could not find a breadboard-friendly version of that one, so I bought two MBP42010s. With some alterations, I was able to get one to work. Since it's a dual, I could not fully replicate the tutorial, since it consisted of alternately raising and lowering the intensity on 3 LEDs.

I am trying to accomplish the replication by daisy-chaining the two MCP42010s, but it is not working. As I understand it, here's what I need to do:
Breadboard

  1. Connect the MISO pin of the first MCP42010 (#1) to the MOSI pin of the second (#2).
  2. Connect the CS and SCK pins on #2 to Arduino pins 10 and 13 via the corresponding pins on #1 via the breadboard (i.e, pin one on #2 is on breadboard row 15 and pin 1 on #1 is on row 26--I used a jumper wire between those rows--same for SCK).
  3. Connect the remaining pins on #2 to VCC, GND, the LED, etc. the same as #1.
    Arduino
    In the two-LED version, I had nested for/next loops: the outeer loop varied the pot, one inner loop varied the level up followed by another loop to vary it back down. That works.
    Since daisy-chaining requires sending two sets of command/data bytes whole CS is LOW, then sending all 32 bits when CS is set HIGH (or at least that's how I understand the datasheet), I removed the outer loop and intended to add code in the routine that sets the LED levels to determine which pot to activate.
    BUT FIRST, I wanted to see if I could get this to work, so I just wrote code to manipulate pot A0 on #2 and both pots on #1. As I understand it, you do one pair of SPI.transfers (command/data) for #2 which loads it into #1,followed by a pair for #1, then when CS is set HIGH the first 2 bytes are shifted to #2 and the third and fourth are loaded into #1.
    Here's the code to loop through levels:

for(int j=50; j<=255; j++)
{
byte i=0; //
setLed(i,j); //this used to use both pot and level, we're leaving pot as a vestige
delay(20);
}
//hold, then same thing in reverse
delay(500);
for(int j=255; j>=50; j--)
{
byte i=0;
setLed(i,j);
delay(20); }

And the code to set LEDs and do the daisy-chain

void setLed (byte reg, int level) //reg is vestigial--not used
{
digitalWrite(Slave, LOW);
SPI.transfer(17); // device 2 pot 0--gets shifted after next spi.transfers (B00010001 says use POT0)
SPI.transfer(level);
SPI.transfer(19); // pots 0&1 device 1 (B00010011 says use both)
SPI.transfer(level);
digitalWrite(Slave, HIGH);
}

This code is successful for #1, but #2 does nothing. I can do either pot, both, or neither on #1, but I cannot get #2 to respond.

Obviously, I am missing something. It could be the code, or the way I have it wired, or both, Any suggestions?

When you send the command to the first MCP42010 it will keep the command buffered, but does not shift it out of the SO pin until it receives a new command. At start-up the buffer is filled with zero's, so when you send the first command only zero's are shifted out to the second device. This means that you need to send the command twice.

When clocking the second command into the first MCP42010 it will shift out the first command to the second MCP42010.
If you want the second device to have a different value than the first one, just send this command first and then send the command for the first device. This way you can have multiple devices daisy chained and each can be set to have a unique resistance

Do keep CS low when sending the commands. Otherwise it won't work.

Thank you very much.

What you told me is what I was trying to do with the code in my original post.:

void setLed (byte reg, int level) //reg is vestigial--not used
{
digitalWrite(Slave, LOW); //Slave = CS
SPI.transfer(17); // device 2 pot 0--gets shifted after next spi.transfers (B00010001 says use POT0)
SPI.transfer(level);
SPI.transfer(19); // pots 0&1 device 1 (B00010011 says use both)
SPI.transfer(level);
digitalWrite(Slave, HIGH);
}

Does this do what you are saying? If not. how should I change it? If so, what else could I be a problem?

Connect the MISO pin of the first MCP42010 (#1) to the MOSI pin of the second (#2).

Depending on what you call the "first" and "second" this seems back to front. Although you are using the wrong pins names do it's hard to tell. That chip has SI and SO, not MISO and MOSI.

Do you have this setup?

CPU/MOSI--->SI/#1/SO--->SI/#2/SO

Plus common SCK and CS?

Are you using the 16-pin version of the chip?


Rob

Rob, thank you.

#1 is the one I had working, #2 is the one I want to daisy-chain to it.

The way I understand this is that by sending the command/data to #2 first, it loads zeroes to the #2 and loads the #1, then the second command/data transfers cause a shift (command/data sent with with first pair of SPI.transfers shift to #2, and new command/data loaded into #1).

Note that I can change the command values on the second set from 19 (for both pots) to 17/18/16 to get pot0 only , pot1 only, or neither and that works. Manipulating the first set of transfers has no effect on anything.

It's a 14-pin version (DIP). Please see attached for the pin configuration and connection.

The result I get is that both LEDs on #1 do what I expect, but #2 does nothing.

Virgil

digital pot mapping.pdf (73.9 KB)

I tried switching the devices in case one was bad. Same result.

See attached for the arduino/breadboard setup. It's not tidy, but the annotations should make it quasi-clear.

OK.

I fussed with the wiring. No change.

Code that I found in a library at http://arduino-projekte.de/ said to assign the SHDN and RS pins to arduino pins 9 and 8 and then set then HIGH in initialization, so I tried that (again). No change.

I must be doing something wrong. I've attached the datasheet and the pin configuration I'm using.

I'd really appreciate some guidance if anyone has gotten this to work.

Thanks.

Virgil

MCP4201 datasheet.pdf (866 KB)

MCP42010 daisy-chain pin assignments.jpg

A schematic is the standard way to show wiring, Excel tables leave a little lot to be desired.

PW0 200Rre->LED->GND

Are you trying to power a LED through the pot? I doubt it will be up to that. EDIT: Wiper current is +-1mA, it ain't going to work.

PW1 10k res->GND

What does this do.

Sorry without a schematic I can't visualise what the heck is going on, I would have to take that conection table and make a drawing which of course I'm not about to do, I have my own problems work on as well :slight_smile:

How have you verified the pots aren't working? Looking at a LED is not the way, have you actually measured the resistance with a meter?


Rob

Thanks.

All 3 pots have the same connections:
Wiper (PWn) goes to a current-limiting resistor to an LED to GND.
Terminal A (PAn) goes to VCC, the 5V connection from Arduino.
Terminal B (PBn) goes to a 10K pull-down resistor to GND.

This works with one MCP42010. My problem is with daisy chaining.

The attached schematic is for the same set-up with one AD5204. I couldn't get that, so I am trying to replicate it with two MCP42010s. The pins are in different order, but I mapped them accordingly.

I would update the schematic, but I'm not great with EagleCAD and I can't find an MCP42010 to replace the AD5204 in the drawing.

For daisy-chaining, I added a device (#2). Pot wired as above. SO pin on # 1 goes to SI pin on #2. Other #2 pins connect to the breadboard rows for corresponding pins on #1.

Does this help?

Revised schematic attached.

I was able to find an Eagle Cad library with a similar device. The pins are the same, except #11 which is labeled ~WP--It's tje RS pin on the MCP42010. so I used it.

Again, the setup on the pots works (on device one). I am trying to get the daisy-chaining to work.

Thank you.

Virgil

MCP42010 daisy-chain schematic cropped.jpg

Sorry I can't stand it, is the attached schematic the equivalent of a single pot?

If so I have to admit I'm lost as to the purpose of the 10k, and according to the specs that pot only has a wiper current of 1mA so trying to pull 13mA through is is asking for trouble.

Still you say it works for a single device so I'll look at the code and data sheet again.

What's the purpose of this circuit, to adjust the brightness of a LED?


Rob

Rob, thank you.

Please trust me that the setup on the pots works when I use only one MCP42010, and continues to work on the first MCP42010 when I daisy-chain 2 together. The schematic I drew was of two MCP42010s, each with 2 pots. 2 LEDs are attached to the first and one to the second (as the schematic shows).

I do not need help with the wiring of the pots. That works. It's possible that I do not need the pull-down resistors, but since they were in the original example and the setup works, I left them in. Because you seem to think it's important, I took them out. No change. So, I'm confident that those resistors had nothing to do with my problem, which is with daisy-chaining.

As mentioned in the original post, this circuit is from a tutorial on SPI devices. The example given in the tutorial used an AD5204 quad digital pot, with LEDs on 3 of the 4 pots. The code loops through the pots consecutively raising and lowering the brightness on each LED.

I could not find an AD5204 so I replicated this example on one MCP42010, but I could only attach 2 LEDS (as the MCP42010 is dual, not quad). Since this is a learning exercise, I decided to go further and see if I could daisy-chain two MCP42010s and fully replicate the example with 3 LEDs.

So, my question is: what do I need to do change, in code and/or wiring, to get daisy-chaining to work?

Virgil

I can't see anything much wrong with the code. It does seem to me that 17 should be 18 because you seem to have POT 1 wired up not POT 0.

Oh, looking at the schematic you have the LED on P1W but NC on P1A and P1B.


Rob

Rob, thanks.

I actually have POT0 wired on #2.

You are right about the schematic--I apologize. I put the LED in the wrong place on the schematic--P1W should be NC and P0W to the resistor and LED. It's in the right place in meatspace. Revised schematic attached.

So, the 17 in the command on the 1st pair of SPI.transfers is correct. FYI. I have fussed with that value and nothing makes a difference. In my current testing, I use 19 in both commands to specify both POTs on both devices, just so I don't confuse myself (further).

Virgil

MCP42010 daisy-chain schematic cropped.jpg

I got this to work, but not by daisy-chaining the way it says it works in the datasheet.

I left the MISO pin on #1 floating instead of wired to MOSI on #2. I wired MOSI on #2 to the breadboard row of MOSI on #1, then wired CS on #2 to arduino pin 9.

In code, I just referenced the device specifically rather than trying to shift data from one data to the next.

In the datasheet for the MCP4231, it says that daisy-chaining is not longer supported, but it appears to mean that MCP42XXX used to support it but MCP42XX devices do not. In any case, I couldn't get it to work.

Schematic: attached. Revised 2014-02-07 for clarity

Here's the functioning program. This steps through the devices, raising and lowering the brightness of one LED , then the other, then both.

// 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).
  Got one working with little problem. Thank you http://arduino-projekte.de/--
  problem with commanf byte. Jeremy had int to say which pot, MCP42010 wants byte.
  Next problem was daisy-chaining.  I never did get it to work per the datasheet.
  Per "SPI by Hand" http://little-scale.blogspot.com/2007/07/spi-by-hand.html
  instead of tying MISO#1 to MOSI#2, float MISO#1 and wire MOSI#2 to an Arduino digital pin. */
//include SPI library 
#include <SPI.h>
//set SPI slave select pin
//By Default, 11 = MOSI, 12 = MISO, 13 = CLK
#define Slave2 10 //(CS pin device 1)
#define Slave1 9  //(CS pin device 2--named them backwards so I can use them in for/next loop)

void setup() {
  //set Slave (others  automatic)
  pinMode(Slave1, OUTPUT);
  pinMode(Slave2, OUTPUT);
  
  // initialize SPI
  SPI.begin();
  digitalWrite(Slave1,HIGH); //disable device to start
  digitalWrite(Slave2,HIGH); //disable device to start
  //by default, MCP42010 ses pots at mid-range. Following sets all 4 to lowest setting to start
  digitalWrite(Slave1,LOW);
  SPI.transfer(19);  // device 1 pot 0--gets shifted after next spi.transfers
  SPI.transfer(0);
  digitalWrite(Slave1,HIGH);
  digitalWrite(Slave2,LOW);
  SPI.transfer(19);  // device 1 pot 0--gets shifted after next spi.transfers
  SPI.transfer(0);
  digitalWrite(Slave2,HIGH);
}
/*function to set led to given level
  2014-01-31 argument for pot is byte for MCP42010; set to 17 (0), 18 (1), or 19 (both) */

void setLed (int device, byte pot, int level)
{
  digitalWrite(device, LOW);
  SPI.transfer(pot);  // device 1 pot 0--gets shifted after next spi.transfers
  SPI.transfer(level);
  digitalWrite(device, HIGH);
}

void loop()
// 3 levels--device, pot, and level. Raises and lowers o, 1, then both on each device
{
for(int i=Slave1; i <=Slave2; i++) 
  {
      //loop through pots (0, 1, both)
    for(byte k=17; k<=19; k++)
      {
      //loop through levels (start at 50 because <50 not perceptible
        for(int j=50; j<=255; j++)
        {
          setLed(i,k,j);
          delay(20);
        }
        //hold, then same thing in reverse
        delay(250);
        for(int j=255; j>=50; j--)
        {
        setLed(i,k,j);
        delay(20);
        }
  delay(100);
    }
  }
}

Virgil

MCP42010 daisy-chain schematic as implemented.jpg

Back to daisy-chaining, I spent some time with Eagle CAD and learned some things. I've attached a new schematic, in case the earlier ones were unclear. [this one is by no means great, but it's better] Revised 2014-02-09 1050AM est

MCP42010 daisy-chain schematic.jpg

The solution: :slight_smile:

I contacted tech support at MicroChip technology. Default clock speed on the Arduino SPI bus is 4mhz, and that's too fast for the MCP42010 to keep up.

I added this line to setup:

SPI.setClockDivider(SPI_CLOCK_DIV16);

That divides the 16mhz Arduino by 16 and sets the SPI speed to 1mhz

All done.

Ha, I know you can never trust a data sheet but it states 10MHz clock speed, there is however a note

When using the device in the daisy-chain configuration, maximum clock frequency is determined by a combination of propagation delay time (tDO) and data input setup time (tSU). Max. clock frequency is therefore ~ 5.8 MHz...

So subject to the clock being in good shape you should have been able to use up to nearly 6MHz, certainly 4MHz should have been ok.

No matter, you've got it working now.


Rob

I saw that too--it did not indicate to me that speed was a problem.
Anyway, I read here: SPI - Arduino Reference
that the default for Arduino is 4mhz. I fussed with the SPI_CLOCK_DIVn argument. 16 gave 1mhz, and that worked. 8 gave me 2mhz and that worked too, so I tried 4---that also worked.

So, either the default is not 4mhz, or I don't know what is meant by "default."

Update: I tried 2, which supposedly sets the speed to 8mhz, that worked, too.

// 2014-01-22 SPI using digital POT to contol 3 LEDs (Jeremy Blum's Arduino Tutorial 8)
/* 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 */
#include <SPI.h>
/* 2014-01-30 I could not Jeremy's example to work with the MCP42010.  
  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) 
  this is different from AD5204).
  Now for daisy-chain.
*/  
//set SPI slave select pin (By Default, 11 = MOSI, 12 = MISO, 13 = CLK)
#define Slave 10
//variables for cycling through devices
byte dev1 = 0;
byte dev2 = 0;
void setup() {
  //set Slave (others  automatic)
  pinMode(Slave, OUTPUT);
  
//initialize SPI
  SPI.begin();
//initialize Serial
  Serial.begin(9600);

//2014-02-17 reduce clock speed (default is 4mhz, 16 makes it 1 (16/16)
//this is the solution from microchip support--otherwise too fast and does not work
/*2014-02-18 evidently I misinterpreted the arduino re fence that says "default is 4mhz" 
  I fussed with this a couple of times and found that using DIV4 to reduce speed to 4mhz works.
  Daisy-chaining did not work without this
*/
  SPI.setClockDivider(SPI_CLOCK_DIV4);
//2014-02-18 device sets at midrange--set all low to start
  digitalWrite(Slave, LOW);
  SPI.transfer(19);  //dev2 both pots
  SPI.transfer(0);   //led level off
  SPI.transfer(19);  //dev1 both pots
  SPI.transfer(0);   //led level off
  digitalWrite(Slave, HIGH);
}
//function to set led to given level
void setLed (int cycle, int level)
{
/*2014-01-31 one difference is that MCP42010 wants bytes instead of ints and needs
  B00010001 (17) for PA0 and B00010010 (18) for PA1, B00010011 (19) for both
  Jeremy's original looped through pots on one 4-way device. We're daisy-chaining so
  we need to do consecutive pairs of SPI transfers and can't control device from for/next
*/
/*2014-02-17 set command byte on each device based on which time we're cycling through
  for/next sends us through 12 times
*/
  switch (cycle)
  {
    case 1:
      dev1 = 17; //pot 0
      dev2 = 16; //none
      break;
    case 2:
      dev1 = 18; //pot 1
      dev2 = 16; //none
      break;
    case 3:
      dev1 = 19; //both
      dev2 = 16; //none
      break; 
    case 4:
      dev1 = 16; //none
      dev2 = 17; //pot 0
      break;
    case 5:
      dev1 = 16; //none
      dev2 = 18; //pot1
      break;
    case 6:
      dev1 = 16; //none
      dev2 = 19; //both
      break;      
    case 7:
      dev1 = 17; //pot 0
      dev2 = 17; //pot 0
      break;
    case 8:
      dev1 = 18; //pot 1
      dev2 = 18; //pot1
      break;
    case 9:
      dev1 = 17; //pot 0
      dev2 = 18; //pot 1
      break;
    case 10:
      dev1 = 18; //pot 1
      dev2 = 17; //pot 0
      break;
    case 11:
      dev1 = 19; //both
      dev2 = 19; //both
      break;      
    case 12:
      dev1 = 16; //none
      dev2 = 16; //none
      break;            
  }
/*Send 2 sets of command/data transfers
  first set loads command/data for second device to first, second sets shifts to 2 and loads 1
*/  
  digitalWrite(Slave, LOW);
  SPI.transfer(dev2);  
  SPI.transfer(level);
  SPI.transfer(dev1);  
  SPI.transfer(level);  
  digitalWrite(Slave, HIGH);
  delay(20);
}

void loop()
{
//2014-02-17 outer loop cycles through 12 scenarios, set on switch/case in setLed
  for(int i=1; i <=12; i++)
  {
    //inner loop through levels (start at 50 because <50 not perceptible
    for(int j=50; j<=255; j++)
    {
      setLed(i,j);
      delay(20);
    }
    //hold, then same thing in reverse
    delay(250);
    for(int j=255; j>=50; j--)
    {
    setLed(i,j);
    delay(20);
    }
    delay(250);
  }
}