Labels

Monday, March 17, 2014

Arduino - Using digital potentiometers part 2 (MCP4251)

This is part two in a series of posts about using digital potentiometers with Arduino boards. Part one covered the AD8403 digital pot. This post will go over the MCP4251 from Microchip. The MCP4251 is a dual pot chip with the capability to individually disconnect the terminals of each wiper through software and a hardware shutdown pin that shuts down both wipers simultaneously. Communication with the chip is done over SPI. The chip is available in DIP and surface mount configurations. I bought the DIP version so I could use them on a breadboard. The specific part number I bought is MCP4251-103E/P which is a 10k ohm model with an 8 bit resistor network. The 8 bit versions have 256 possible positions for the wiper which works out to approximately 39 ohms increase in resistance for each wiper position on a 10k ohm model.

Since there wasn't a preexisting library that would work for me I began figuring out how to talk to this chip. I started with the Arduino example in File > Examples > SPI > DigitalPotControl. The AD840x and AD520x series pots work right out of the box with this example but the MCP4xxx pots use different memory addresses so I started tweaking the example.

Understanding how to talk to the MCP4251

So lets start with the very basics of how to talk to these pots. Sending a command over SPI requires four steps:
1. Take the slave select pin LOW. This tells the chip to listen for commands.
2. Send the memory address for the item we want to change using SPI. This is the memory address for a wiper or terminal connections. This tells the chip what we want to change.
3. Send the new value for the item we specified in step 2. Wipers on the MCP4251 have 256 possible positions so this would be a decimal number between 0-255 or binary B00000000 - B11111111.
4. Take the slave select pin HIGH. This tells the chip to execute the changes.

The AD8406 covered in part 1 used decimal numbers 0-5 as memory addresses for each of the wipers which was very easy to understand. The MCP4251 doesn't use sequential values so I had to go digging in the data sheet to find the right values. Here is the memory map table from the data sheet:

Looking at the data sheet you can see the memory address and the data is made up of a total of 16 bits. The sheet says the data is 10 bits and the memory address is 6 bits but in practice you can send the data in two 8 bit chunks which allows you to use the 'B' binary formatter. The maximum possible value for a wiper is 255 which would be B11111111 in binary. So here is the list of memory addresses and tcon values I was able to determine:

The Wiring

Now that I had memory addresses figured out I wired up the digital pot on a breadboard with some LED's. I'm using LED's in this example because it's a good way to visualize the pots changing resistance values. I wired the shutdown pin to a 4.7k pull down resistor so the pot would go into shutdown mode if digital pin 7 wasn't HIGH. My example code also uses the software disconnects (TCON) to turn the LED's off and on.

The code

Up next

Part 3 in my series of digital potentiometer posts will cover reading data from the MCP4251 to determine the wiper positions and the tcon status. Part 4 will cover using multiple SPI digital potentiometers. I will add a links here as I complete those posts.

11 comments:

If you trying to control the speed of a motor it would be better to use pulse width modulation and a transistor. Motors draw a lot of current which most digital pots can't handle. A TIP120 transistor can handle 5 amps. I found this how-to page that might be useful for you:

You will certainly have to modify it some. How much I suppose depends on what programming language you will be using on the Pi and if that language has an SPI library. My understanding is Arduino code is similar to C.

I found this page after getting writing to the pots to work by hacking someone else's non-working example code, but I can't get reading the status byte to work. It should just return one of two values, depending on the shutdown pin, but I only get one value, whether I ground it or not, though the chip does go into shutdown when I do.

FWIW, the write (and read) should be a 16 bit transfer, according to the datasheet, but it seems it doesn't need to be, since your code apparently works (I haven't tried it).

I have the write command like this:

SPI.transfer16((potNumber<<12) | value);

- where potNumber is 0 or 1.

For reading the status, I tried:

const int readSTATUScmd= 0x5fff; // only the top six bits matter

...

unsigned int statusByte() { // Return the contents of the status register of the chip delay(10); // Probably not necessary, just there until I see it working. return SPI.transfer16(readSTATUScmd);}

- The datasheet shows an overlap of the command word being sent, and the 9 bit data value being sent back, so after receiving the important first six bits, it should be sending back the data bits. For me, that doesn't work.

Writing to them is the important thing, definitely. Mostly, I was determined to get reading to work as well because this is the first time I've tried using an SPI device, and I wanted to get the hang of it properly.