Successfully writing, but not reading, I2C device

My sketch steps both pots on the Maxim DS1882 down in volume incrementally, pauses 2 seconds when the chip reaches mute, and then starts down again from full volume. From the WiperSetValue output in the serial monitor (and from actually hearing the output) I can tell this part is working, but I’m also attempting to read back from the wiper memory on each pot, and it continues to print “0” for both pots for each read operation, regardless of the wiper setting.

From the datasheet, the LSB on the Slave Address Byte needs to be "1’ to read, and that byte sent to the chip for it to respond to a read request. However, using the Wire library there’s no option to set that bit…and I’m not even sure what the library does send when I call the Wire.requestFrom function.

Do I need to step outside of the the Wire library to execute a read? Or is something else faulty in either my bitmath or how I’m calling the request function?

Datasheet: Maxim DS1882 Datasheet

/*
DS1882 Test Sketch

---------------------------------
DS1882 I2C Command Byte Structure
---------------------------------
SLAVE ADDRESS BYTE
        Base        A2 A1 A0 ... R/W (LSB=1 for Read request)
Bin     0  1  0  1  0  0  0  ... 0
Bitval  64 32 16 8  4  2  1
Hex        0x28                (<-----This is the slave address base)
Dec         40

COMMAND BYTE
Bin     0  0  0  0  0  0  0  0
POT0    0  0  0  POT0WiperPos   <---BIT6 toggles POT0 or POT1
POT1    0  1  0  POT1WiperPos   <┘
CONFIG  1  0  X  X  X  0  0  0  <---BIT7 flags CONFIG register
                       |  |  |
                       |  |  POTConfig(BIT0): 0(0x0)=63 positions & mute, 1(0x1)=33 positions & mute(default)
                       |  POTZeroCrossing(BIT1): 0=disabled, 1=enabled(default)
                       POTNVM Volatile/Nonvolatile(BIT2): 0=nonvolatile, 1=volatile(default, potentiometer powers up in mute pos.)

Read Protocol: Start SLAVEADDR POT0BYTE POT1BYTE CONFIG Stop
Write Protocol: Start SLAVEADDR (POT0BYTE, POT1BYTE, CONFIG can be sent in any order after SLAVEADDR) Stop

*/

#include <Wire.h>

byte CONFIG = B10000010;   //set configuration byte for write
byte RDCONFIG = B10000011; //set configuration byte for read req.
byte POT0 = 00;            //flag for pot 0
byte POT1 = 01;            //flag for pot 1
int POT0SET = 1;           //initialize pot 0 wiper set  (63 = mute, 0 = no attenuation)
int POT1SET = 1;           //initialize pot 1 wiper set
byte POT0CMD;              //initialize pot 0 command byte
byte POT1CMD;              //initialize pot 1 command byte

byte POT0RD;               //initialize pot 0 read byte
byte POT1RD;               //initialize pot 1 read byte
byte CONFIGRD;             //initialize configuration byte read
unsigned char POT0GET;     //initialize pot 0 wiper position reading
unsigned char POT1GET;     //initialize pot 1 wiper position reading


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


void loop()
{ 
  POT0SET++;        // increase attenuation 
  POT1SET++;
 
  POT0CMD = ((POT0 << 6) | (POT0SET >> 2));  //assemble pot 0 command byte
  POT1CMD = ((POT1 << 6) | (POT1SET >> 2));  //assemble pot 1 command byte  
  
  Wire.beginTransmission(40); // transmit to device #40 (0x28)
  Wire.write(POT0CMD);       // sends pot 0 command byte  
  Wire.write(POT1CMD);       // sends pot 1 command byte
  Wire.write(CONFIG);         // sends configuration byte  
  Wire.endTransmission();     // stop transmitting

  Serial.print("Pot0 WiperSetValue = ");
  Serial.println(POT0SET);
  Serial.print("Pot1 WiperSetValue = ");
  Serial.println(POT1SET);

//  Not working yet - returns "0" on every POT#GET print

  Wire.beginTransmission(40);
  Wire.write(RDCONFIG);
  Wire.endTransmission();
  Wire.requestFrom(40, 3);     //request 3 bytes from device #40
  while (Wire.available()) {
     POT0RD = Wire.read();          //read pot0 byte
     POT1RD = Wire.read();          //read pot1 byte
     CONFIGRD = Wire.read();        //read configuration register byte
  }

  delay(750);

  POT0GET = POT0RD & B00111111;  //mask pot0 flag and extract wiper value
  POT1GET = POT1RD & B00111111;  //mask pot1 flag and extract wiper value 
  Serial.print("Pot0 Position = ");
  Serial.println(POT0GET);
  Serial.print("Pot1 Position = ");
  Serial.println(POT1GET);
  Serial.println();
  
  if(POT0SET == 255)  // if reached position 63(???!) (mute)
  {
    delay(2000);   // hold mute for 2 seconds
    POT0SET = 0;   // start over from full volume
    POT1SET = 0; 
  }
  delay(100);
}

What is the below bit of code doing and what happens if you comment it out.

  Wire.beginTransmission(40);
  Wire.write(RDCONFIG);
  Wire.endTransmission();

The below code is probably not suitable to read data back and store in separate variables but you should get something.

  while (Wire.available()) {
     POT0RD = Wire.read();          //read pot0 byte
     POT1RD = Wire.read();          //read pot1 byte
     CONFIGRD = Wire.read();        //read configuration register byte
  }

or you could try the wire read example way to confirm your getting stuff.

  while (Wire.available()) { // slave may send less than requested
    char c = Wire.read(); // receive a byte as character
    Serial.print(c);         // print the character
  }

First of all, you should run a I2C Scanner sketch. It in the Arduino IDE, seach in the menu under 'Examples'.
Then you need an example of someone who has it working. For example: volume1882/volume1882.ino at master · iverasp/volume1882 · GitHub.
In that sketch, the 'potAddress' should be set to the I2C address that the I2C Scanner found.
In the setup(), you can copy most things.
The 'adjustAttenuation()' function sets a new value.

Can your cat tell us which Arduino board you use ?

Simply run the following sketch to see that your Arduino detects the sensor.

#include<Wire.h>

void setup()
{
    Serial.begin(9600);
    Wire.begin();
    Wire.beginTransmission(40);  //roll calling the Slave at address 40 = 0x28 = 100 1000 (7-bit)
    byte busStatus = Wire.endTransmission();
    if(busStatus != 0)
    {
         Serial.print("Slave is not found on I2C Bus...!");
         while(1);     //wait for ever
    }
    Serial.println("Slave is found.");
}

void loop()
{

}

Riva:
What is the below bit of code doing and what happens if you comment it out.

  Wire.beginTransmission(40);

Wire.write(RDCONFIG);
 Wire.endTransmission();




The below code is probably not suitable to read data back and store in separate variables but you should get something.


while (Wire.available()) {
    POT0RD = Wire.read();          //read pot0 byte
    POT1RD = Wire.read();          //read pot1 byte
    CONFIGRD = Wire.read();        //read configuration register byte
 }



or you could try the wire read example way to confirm your getting stuff.


while (Wire.available()) { // slave may send less than requested
   char c = Wire.read(); // receive a byte as character
   Serial.print(c);         // print the character
 }

The resend of Wire.beginTransmission right before the Wire.requestFrom was my lame attempt to force a read request from the perspective of the datasheet (my RDCONFIG variable is has the read request bit set). The sketch behaves the same whether it's commented out or not.

I'm not getting anything back from either my Wire.reads or your last snippet of code. Here's my output in the serial monitor for a few loops:

Pot0 WiperSetValue = 19
Pot1 WiperSetValue = 19
Pot0 Position = 0
Pot1 Position = 0

Pot0 WiperSetValue = 20
Pot1 WiperSetValue = 20
Pot0 Position = 0
Pot1 Position = 0

Pot0 WiperSetValue = 21
Pot1 WiperSetValue = 21
Pot0 Position = 0
Pot1 Position = 0

The behavior should be it reads back the same wiper value that it set the pot to.

Koepel:
First of all, you should run a I2C Scanner sketch. It in the Arduino IDE, seach in the menu under ‘Examples’.
Then you need an example of someone who has it working. For example: volume1882/volume1882.ino at master · iverasp/volume1882 · GitHub.
In that sketch, the ‘potAddress’ should be set to the I2C address that the I2C Scanner found.
In the setup(), you can copy most things.
The ‘adjustAttenuation()’ function sets a new value.

Can your cat tell us which Arduino board you use ?

I scanned for the chip and it indeed resides at the default address (40).

Thanks for finding that sketch–funny it never came up when I was searching “DS1882.”

My cat says I’m using an Arduino MEGA2560. :stuck_out_tongue:

Very often, the solution with me ends up being a lot less complicated than I think it will be. Updating the variables and applying the bitmask outside the scope of the “while” loop was causing problems. For some reason the Wire.available function only returned true on the very first read, thus the variables were never updated thereafter. Just removing the “while” loop fixed the problem This, in the main loop:

  Wire.requestFrom(potAddress, 3);     //request 3 bytes from device #40
  POT0RD = Wire.read();          //read pot0 byte
  POT1RD = Wire.read();          //read pot1 byte
  CONFIG = Wire.read();          //read configuration register byte
  POT0RD = POT0RD & B00111111;  //mask pot0 flag and extract wiper value
  POT1RD = POT1RD & B00111111;  //mask pot1 flag and extract wiper value 
  Serial.print("Pot0 Position = ");
  Serial.println(POT0RD);
  Serial.print("Pot1 Position = ");
  Serial.println(POT1RD);
  Serial.println();

Now outputs:

Pot0 WiperSetValue = 7
Pot1 WiperSetValue = 7
Pot0 Position = 1
Pot1 Position = 1

Pot0 WiperSetValue = 8
Pot1 WiperSetValue = 8
Pot0 Position = 2
Pot1 Position = 2

Pot0 WiperSetValue = 9
Pot1 WiperSetValue = 9
Pot0 Position = 2
Pot1 Position = 2

Pot0 WiperSetValue = 10
Pot1 WiperSetValue = 10
Pot0 Position = 2
Pot1 Position = 2

Pot0 WiperSetValue = 11
Pot1 WiperSetValue = 11
Pot0 Position = 2
Pot1 Position = 2

Pot0 WiperSetValue = 12
Pot1 WiperSetValue = 12
Pot0 Position = 3
Pot1 Position = 3

And, nice to see my bitmasking actually worked. But this brings up another issue: As you can see the difference between what I’m writing to the chip and what I’m getting back, something is faulty in how I’m writing to the chip, because I should be sending a value of 0-63 and instead I ended up having to send 0-254 to run the pot through its entire scale. What’s wrong with this picture? Here’s how I’m constructing the control bytes I send (from the data sheet and what you’ll see in my notes, bits 0-5 set the wiper, bit 6 flags which potentiometer the byte is for):

void loop()
{ 
  POT0SET++;        // increase attenuation 
  POT1SET++;
 
  POT0CMD = ((POT0 << 6) | (POT0SET >> 2));  //assemble pot 0 command byte
  POT1CMD = ((POT1 << 6) | (POT1SET >> 2));  //assemble pot 1 command byte  
  
  Wire.beginTransmission(40); // transmit to device #40 (0x28)
  Wire.write(POT0CMD);       // sends pot 0 command byte  
  Wire.write(POT1CMD);       // sends pot 1 command byte
  Wire.write(CONFIG);         // sends configuration byte  
  Wire.endTransmission();     // stop transmitting

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.