SPI.transfer(val) help

I'm trying to control MCP4251 dual 5k digital potentiometer, but when I put in values between 0-257 it only controls one of the potentiometers. How do I control the other?

Did you read the datasheet of your device? Also it may be a mistake in your code.

Wait, what code?

How to use this forum

but when I put in values between 0-257

How did you get more than 255 into one byte?

Okay, okay...you guys have made your point. Below is my code, which is not much, just trying to figure out how to control each pot before actually doing any real coding. I have the Arduino Uno, and have it connected as shown below.

MCP Pin 1/CS - Arduino Pin 8
MCP Pin 2/SCK - Arduino Pin 13
MCP Pin 3/SDI - Arduino Pin 11
MCP Pin 4/Vss - Arduino 5V
MCP Pin 14/Vdd - Arduino GND

According to the data sheet (couple snapshots of it attached, over 1MB so couldn't attach the whole thing), it says the SPI string should be 16 bits, with the first 6 identifying which potentiometer to control and the next 10 for the "data".

In the below code you can see I'm currently trying to send 16 bits, but I was previously sending decimal 17 or 18 based on the below link...that would sort of let me control 1 of the pots, but not consistently.

SPI HOW-TO: MCP42XX

Anyone know what commands to send to accurately control this chip?

#include <SPI.h>

int tempCSPin = 8;

void setup() 
{
SPI.begin();
pinMode(tempCSPin, OUTPUT);
digitalWrite(tempCSPin, LOW);
}

void loop() 
{
//Write to volatile wiper 0 "000000", data "xxxxxxxxxx"
SPI.transfer(0000000001000000);
//Write to volatile wiper 1 "000100", data "xxxxxxxxxx"
SPI.transfer(0001000001000001);
}

MCP data sheet p48.JPG

MCP Pinout.JPG

To answer this, I was going off the data sheet saying the digital pot is "8-bit: 256 Resistors (257 Steps)"...

//Write to volatile wiper 0 "000000", data "xxxxxxxxxx"
SPI.transfer(0000000001000000);
}
  1. You are not driving the chip select pin - you have to do this for every transaction in SPI.
  2. SPI library moves just 1 octet per call to transfer
  3. You don't understand binary constants. 0b0000000001000000 is binary,
    0000000001000000 is octal (and overflows 16 bit integer value anyway

Perhaps something more like this is needed (read the datasheet for definitive
information):

  digitalWrite(tempCSPin, LOW);
  SPI.transfer (0b00000000) ;
  SPI.transfer (0b01000000) ;
  digitalWrite(tempCSPin, HIGH);

To control two devices. you need two CS connections.

You need to set the CS connection low, for the device you are trying to contact. Then you set the CS connection high, and set the other CS connection low, for the other device you are trying to contact.

michinyon:
To control two devices. you need two CS connections.

You need to set the CS connection low, for the device you are trying to contact. Then you set the CS connection high, and set the other CS connection low, for the other device you are trying to contact.

It is just one single chip that has two separate digital potentiometers in it, so there is only one CS pin on the chip.

There is more to the usage of this strange device, than meets the eye.

It does indeed claim in the datasheet to have 257 different position settings.

Although at Table 5-1 on page 37, they seem a bit confused. In the table, it shows that 0 = 0x00, 1 = 0x01, and so on, to 255 = 0xFE, 256 = 0xFF, and 257 = 0x100, which is wrong and silly. I noticed this made no sense years ago.

Reading further along in the datasheet, it seems the device uses 9 bits of memory to store its position setting, and numbers up to 0x101 are valid, with 0x100 and 0x101 both representing the maximum setting, with different other behavior.

Furthermore, the data you send to the device to set its position needs to be 10 bits, of which it uses the least significant 9 bits.

The SPI command message to this device is supposedly 16 bits, where the 10 bit data component consists of 2 bits on the first byte and 8 bits in the second byte ( of which it then uses 9 bits ).

Apart from the mistake in their drawing, it appears that this device does actually have 257 output settings.

If you are using the version of the device with two potentiometers on the same chip, the instructions for controlling one, or the other, are pretty clear in the datasheet. I assume that you have read more than one page of it.

MarkT:

  1. You are not driving the chip select pin - you have to do this for every transaction in SPI.

I was setting the chip select pin low in the void setup() since I only have 1 chip currently...will this not work? I'll try your method tonight when I get home from work just in case though.

MarkT:
2) SPI library moves just 1 octet per call to transfer
3) You don't understand binary constants. 0b0000000001000000 is binary,
0000000001000000 is octal (and overflows 16 bit integer value anyway

You are correct, I do not know binary constraints (new to this programming thing all together). From your code, it looks like I need to only send 8 bits per SPI.transfer()? Also, I have to preface those 8 bits with a "0b" to signify that it's binary? I've actually never heard of octal until now and had to look it up. Why is that an octal string instead of decimal?

Thanks for taking the time to answer some newb questions...

michinyon:
If you are using the version of the device with two potentiometers on the same chip, the instructions for controlling one, or the other, are pretty clear in the datasheet. I assume that you have read more than one page of it.

Yes, I read more than one page of the datasheet (though I admittedly didn't understand a lot of it). The code I posted showed the first 6 bits of the SPI.transfer() changing from 000000 to 000100 to switch between the two wipers.

You guys are harsh, just looking for a little help to get my first ever Arduino project off the ground...

Try fixing your posted code to at least use the right numbers (with the 0bxxxx prefix). Then try again. Also post your amended code.

I have a page on SPI: http://www.gammon.com.au/spi

Do you really have SS on pin 8? Normally you use pin 10 on a Uno. Do you in fact have a Uno? Stating what Arduino you have would help us.

According to the data sheet (couple snapshots of it attached, over 1MB so couldn't attach the whole thing), ...

You can always give us a link to the datasheet. Helping you shouldn't be like extracting teeth, newbie or not.

SCEV:
I was setting the chip select pin low in the void setup() since I only have 1 chip currently...will this not work? I'll try your method tonight when I get home from work just in case though.

SPI is transaction based and chips often rely on CS
being toggled. As I said in all cases the datasheet is definitive - read that carefully
before believing what we say!

You are correct, I do not know binary constraints (new to this programming thing all together). From your code, it looks like I need to only send 8 bits per SPI.transfer()? Also, I have to preface those 8 bits with a "0b" to signify that it's binary? I've actually never heard of octal until now and had to look it up. Why is that an octal string instead of decimal?

Thanks for taking the time to answer some newb questions...

SPI.transfer transfers 8 bits - that's all it does. You can use whatever value you
like, binary, octal, decimal, hexadecimal constant or the value in a variable. SPI.transfer
transfers 8 bits, so if a chip needs 16 bit SPI transaction you call it twice.

"constraint" is not "constant"!

Yes, it was on pin 8, but I have moved it to pin 10 just to keep it standard to what most other use. However, once I got the circuit working, I tried going back to pin 8 just to see if it works and it does. Yes, I have the Uno...I mentioned that above.

Below is my new code, using the "0b" prefix, changing the CS pin to 10 (just to standardize, not necessary) and moving the CS Low/High into the main loop (which after testing I believe is necessary). Everything is working now...appreciate all the help.

#include <SPI.h>

int tempCSPin = 10;

void setup() 
{
SPI.begin();
pinMode(tempCSPin, OUTPUT);
}

void loop() 
{
digitalWrite(tempCSPin, LOW);
  //Write to volatile wiper 0 "000000", data "128" 
SPI.transfer(0b00000000);
SPI.transfer(0b10000000);
//Write to volatile wiper 1 "000100", data "1"
SPI.transfer(0b00010000);
SPI.transfer(0b00000001);
digitalWrite(tempCSPin, HIGH);
}
1 Like