MCP4251

Digital Potentiometer

The MCP4251 is a digital potentiometer with a resistor network that can be controlled using SPI. This article explores on how to develop a driver in C that interacts with this component and how can you adjust the driver according to a microcontroller of your choice.

The datasheet of the MCP4251 is a bit confusing to follow at first but let's go over it and get the important information in order to control it.

As always, I recommend you having the datasheet opened at the same time you read this article and follow along the pages that I will indicate throughout the article.

I got the MCP4251 - 10k Dual Potentiometer SOIC package

The block diagram on page 2 shows a bit more information of what is inside this IC.

  • I found this block diagram particularly useful because it shows the registers names that we will be interacting with when using the SPI commands.
  • We can also see the pins that we need to interact with: the two resistor networks pins, the SPI pins, the power pins and the hardware shutdown pin.

To get the pins description we need to go to Table 3-1 on page 31.

  • The maximum supply voltage for this IC is 5.5V (Table on page 4) and it will be connected to pin 15 (VDD).

I think we have the necessary information for now to start connecting the MCP4251 to a microcontroller.

For simplicity, I am going to use an Arduino Uno to interact with the MCP4251. The connections are below.

For some initial testing, I am going to set up Pot 0 as a voltage divider and measure the voltage across P0W (Pin 9) and I will also measure Pot 1 resistance between P1W and P1A (Pin 6 and 7 respectively). With these two tests I can see the voltage changing and the impedance changing for different resistor network settings.

Let's go over the code to interface the MCP4251.

For the SPI code, I will be using the standard SPI library for the Arduino Uno:

  • SPI.begin
  • SPI.transfer

Under section 7.0 - Device Commands (page 4), the MCP4251 supports 16 memory address locations and 4 commands.

On Table 7-1, we can see that 2 commands are 16 bits long and the other 2 commands are 8 bits long.

The general SPI command formats are under Figure 7-1. Notice that the command bits from Table 7-1 are bit 2 and 3 from the Command Byte.

With this in mind, we can write two functions that send commands and data bytes.

Note: For this particular device, the CS pin allows you to control the device into two additional sub-modes: normal serial commands (CS pin is driven to LOW), and high-voltage serial commands (CS pin is driven HIGH).

void command_8Bit(uint8_t cmd){
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(cmd);
  digitalWrite(CS_PIN, HIGH);
}

void command_16Bit(uint8_t cmd, uint8_t data){
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(cmd);
  SPI.transfer(data);
  digitalWrite(CS_PIN, HIGH); 
}

From the SPI point of view, that is it. Now we just need to start constructing the commands and data fields according to what we want to do with the MCP4251.

The commands are summarized on Table 7-2 (page 48).

The 4 MSB bits of the command Byte (from Figure 7-1) are going to hold the memory address value.

For example, if we want to set Pot 0 at 50% we will send the following SPI command and data Byte:

  • Command Byte: b0000 00xx (0x00)
  • Data Byte: b0001 0000 (0x80)

I will give another example, set Pot 1 at 75% (192/256):

  • Command Byte: b0001 00xx (0x10)
  • Data Byte: b1100 0000 (0xC0)

With this information we can build a simple test to control Pot 0 and Pot 1.

#include <SPI.h>

// Volatile Memory (RAM)
#define MCP4251_WIPER_0_WRITE_ADD   0x00
#define MCP4251_WIPER_1_WRITE_ADD   0x10

#define CS_PIN  10

void setup() {
 
  // initialize SPI:
  SPI.begin(); 

  // Configure Pot
  command_16Bit(MCP4251_WIPER_0_WRITE_ADD, 0); // wiper values from 0 to 255
  command_16Bit(MCP4251_WIPER_1_WRITE_ADD, 192); // wiper values from 0 to 255
}

void loop() {
}

void command_8Bit(uint8_t cmd){
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(cmd);
  digitalWrite(CS_PIN, HIGH);
}

void command_16Bit(uint8_t cmd, uint8_t data){
  digitalWrite(CS_PIN, LOW);
  SPI.transfer(cmd);
  SPI.transfer(data);
  digitalWrite(CS_PIN, HIGH); 
}

soon...


Leave a Reply

Your email address will not be published.