I2C master volume control with digipot AD5122A/AD5142A

First forum post for me so excuse any blunders.

I'm trying to use dual wiper digital potentiometer AD5122A (128 taps) or AD5142A (256 taps) as a master volume control for an audio project with dual stereo inputs but I'm having trouble understanding the datasheet's instructions for how to program the device (I2C communication).

Datasheet for AD5122A: https://www.analog.com/media/en/technical-documentation/data-sheets/AD5122A_5142A.pdf

My circuit diagram is attached. I'm using the Arduino MKRZero so all digital pins are operating on 3.3V.

There is an IC-switch selecting one of the two stereo inputs and feeding the left channel to the digitpot's A1 pin and the right channel to the A2 pin. The corresponding wiper outputs W1 and W2 are then fed to an audio amplifier. I want to be able to raise and lower the volume by adjusting the wiper positions.

I started out just trying to adapt the code from this digipot tutorial: https://www.arduino.cc/en/Tutorial/DigitalPotentiometer

// I2C Digital Potentiometer
// by Nicholas Zambetti <http://www.zambetti.com>
// and Shawn Bonkowski <http://people.interaction-ivrea.it/s.bonkowski/>

// Demonstrates use of the Wire library
// Controls AD5171 digital potentiometer via I2C/TWI

// Created 31 March 2006
// This example code is in the public domain.


#include <Wire.h>

void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
}

byte val = 0;

void loop()
{
  Wire.beginTransmission(44); // transmit to device #44 (0x2c)
                              // device address is specified in datasheet
  Wire.write(byte(0x00));            // sends instruction byte  
  Wire.write(val);             // sends potentiometer value byte  
  Wire.endTransmission();     // stop transmitting

  val++;        // increment value
  if(val == 64) // if reached 64th position (max)
  {
    val = 0;    // start over from lowest value
  }
  delay(500);
}

Since the ADDR1 and ADDR0 pins are disconnected in my circuit, I think the device address will be 0101010 (42 in decimal), but I'm not sure what command byte to send to increase volume by +6 dB or decrease it by -6dB.

How would I change the code above such that both wiper positions went to maximum resistance in 6 dB increments, then went to minimum resistance in 6 dB increments?

I ended up figuring this out myself, but posting solution for anyone else who might be struggling.

The device address was indeed decimal number 42 since I have ADDR1 and ADDR0 pins disconnected (see Table 9 in the datasheet), so compared to the tutorial, I needed to change Wire.beginTransmission(44) to Wire.beginTransmission(42).

The second part that I asked about was how to change the wiper positions. This is done by using Command 1 from Table 10 in the datasheet, where the value of A0 is found in Table 11. Since this is a dual channel digipot, you need to specify which of the two wiper values you want to change. To change W1 (RDAC1): A0=0, and to change W2 (RDAC2): A0=1, so Command 1 for W1 in binary is 0001 0000 (0x10 in hexadeximal) and for W2 it is 0001 0001 (0x11 in hexadecimal). Also, you can give this digipot values from 0-255. Functioning code is below:

//tests digipot AD5142A by looping through all 256 positions of both wipers
#include <Wire.h>

void setup() {
  Wire.begin();
}

byte vol = 0;

void loop() {
  Wire.beginTransmission(42); // transmit to device #42 (ADDR0 and ADDR1 not connected, see table 9 in datasheet)                
  Wire.write(byte(0x10));            // sends instruction byte to wiper 1 (RDAC1. Command 1 in datasheet table 10. 
  Wire.write(vol);             // sends potentiometer value byte  to wiper 1
  Wire.write(byte(0x11));            // sends instruction byte  to wiper 2 (RDAC2). Command 1 in datasheet table 10. 
  Wire.write(vol);             // sends potentiometer value byte to wiper 2
  Wire.endTransmission();     // stop transmitting

  vol++;        // increment value
  if(vol == 255) // if reached 255th position (max)
  {
    vol = 0;    // start over from lowest value
  }
  delay(500);
}

As some may have noticed my circuit diagram did not have V_logic connected to a power supply. That was a mistake that made troubleshooting a lot harder since the device wasn't powered up. Connecting V_logic to 3.3V (same as V_dd) was needed.

Nice post for a Newbie. :slight_smile: Code tags, datasheet link, circuit diagram and solved by yourself.

Welcome to the forum.