0

I'm having trouble reading the I2C data from the CPS8200, that has a 32 bit Register Address. Since I'm not too familiar with I2C register addresses more than 8 bits, and right now I'm not sure if I'm doing it correctly. My main goal is to be able to read and write from Register Address 0x2000 003C, and I don't believe I am doing this properly since when I read the data in the Serial Monitor, what I'm getting is 0xC4, when I should be getting 0x0000 0AFF. I wanted to post here to understand what I'm doing wrong, and how to properly read from the 32 bit register address.

enter image description here

#include <Wire.h>
uint32_t FUNC_EN_REG = 0x2000003C;
uint32_t FUNC_EN_REG_DATA;
void setup() {
 Wire.begin(4, 5);
 Serial.begin(115200);
 Wire.beginTransmission(0x30);
 Wire.write(0x20);
 Wire.write(0x00);
 Wire.write(0x00);
 Wire.write(0x3C);
 Wire.endTransmission();
}
void loop() {
 Wire.requestFrom(0x30, 4);
 FUNC_EN_REG_DATA = Wire.read();
 Serial.println(FUNC_EN_REG_DATA, HEX);
 delay(500);
}
asked May 28 at 13:20
3
  • 2
    This is not a part of I2C spec. Read the datasheet for your IC (the-one-you-don-name-for-some-obscure-reason). It could be 20-00-00-3c or 3c-00-00-20, who knows? Commented May 28 at 13:52
  • To hammer home Matt's point: please link documentation or tell us what device this is! There is no universal answer for the question you are asking Commented May 28 at 17:42
  • @InBedded16 Noted, the post has been updated Commented May 28 at 18:23

2 Answers 2

2

You are almost there. The line where you have Wire.endTransmission(); should actually be

Wire.endTransmission(false);

As described in the documentation :

The endTransmission() method accepts a boolean argument changing its behavior for compatibility with certain I2C devices. If true, endTransmission() sends a stop message after transmission, releasing the I2C bus. If false, endTransmission() sends a restart message after transmission. The bus will not be released, which prevents another controller device from transmitting between messages. This allows one controller device to send multiple transmissions while in control. The default value is true.

The endTransmission(false) is crucial because it allows you to switch from a write operation (sending the register address) to a read operation (getting the data) without releasing the bus.

When you are reading your response from the external device, you do not allow it to return all of the 4 bytes in the response before you ask for the response again. Wire.read() should be run 4 times to read the 4 bytes of the response.

Your loop function should look something like this:

void loop() {
 Wire.requestFrom(0x30, 4); // request 4 bytes from peripheral device #0x30
 char a = Wire.read(); // receive a byte as character
 Serial.print(a, HEX); // print the character in hex
 char b = Wire.read(); // receive a byte as character
 Serial.print(b, HEX); // print the character in hex
 char c = Wire.read(); // receive a byte as character
 Serial.print(c, HEX); // print the character in hex
 char d = Wire.read(); // receive a byte as character
 Serial.print(d, HEX); // print the character in hex
 Serial.println("");
 delay(500);
}

Or like this using a while loop:

void loop() {
 Wire.requestFrom(0x30, 4); // request 4 bytes from peripheral device #0x30
 while (Wire.available()) { // peripheral may send less than requested
 char c = Wire.read(); // receive a byte as character
 Serial.print(c, HEX); // print the character in hex
 }
 Serial.println("");
 delay(500);
}

Side note:
If you want to make youre code a little more fancy and a little more robust, test the result of the endTransmission() like so:

byte endTransmissionStatus = Wire.endTransmission(false);
if (endTransmissionStatus != 0) {
 Serial.print("Error sending register address (Status: ");
 Serial.print(endTransmissionStatus);
 Serial.println(")");
 return 0; // Return 0 or handle the error appropriately
}

The meaning of the status that is returned can be found on the documentation page link mentioned above.

Edgar Bonet
45.1k4 gold badges42 silver badges81 bronze badges
answered May 28 at 15:58
5
  • 1
    What's the difference in having endTransmission(false) and just not calling endTransmission? Commented May 28 at 16:16
  • 1
    @sa_leinad this isn't actually always true. Some I2C slave devices have separate read and write commands, requiring you to release the bus using endTransmission(), and then a read command will fetch the previously set register. The correct way for this device will be in the documentation, so OP will either have to find it themselves or tell us what device this is. Commented May 28 at 17:35
  • 1
    @J.Street endTransmission(false) sends a restart message, not calling it at all will not. It is necessary to send a stop or a restart message to the slave so that it knows the current read/write command is over. Read the documentation to better understand that nuance. Commented May 28 at 17:39
  • The part about the loop for Wire.read() is important, if you edit the answer to reflect my first comment then I will +1 :) Commented May 28 at 17:43
  • @InBedded16 Some I2C slave devices have separate read and write commands, requiring you to release the bus using endTransmission(), and then a read command will fetch the previously set register. Actually, all i2c slaves require that and all i2c slaves must keep current register number (with maybe autoincrement) until powered off. I2c start-without-stop is good and recommended practice but it is not critical, unless one runs multi-master i2c bus config. Commented May 29 at 3:46
2

The answer to your question lies in Fig8 of the document you linked.

Fig of the CPS820 datasheet This is the order of I2C commands to run. First, AW:30 which is a beginTransmission(0x30), starting a write transmission. Then, DW:FF DW:FF DW:FF DW:00, the 4 bytes of the register address using MSBFirst. This part you already were doing correctly. You need to have an endTransmission() because:

This function ends a transmission to a peripheral device that was begun by beginTransmission() and transmits the bytes that were queued by write().

Then without releasing the bus lines it launches right into AR:30 which is the beginning of a read transmission. Therefore your endTransmission() function should be passed a false argument, so that you don't release the bus in between.

Next is DR:0E DR:00 DR:00 DR:00, which you receive using wire.requestFrom(0x30, 4) and then wire.Read() 4 times, one for each byte. Make sure to store each byte or use a different variable for each read, don't overwrite them with the next read. Notice that the correct value for this register should be 0x0000000E. The data is transmitted using LSBFirst notation. Incidentally, if you want to write data to a register (refer to Fig 7 or 9), you should also transmit the data in LSBFirst, but the register addresses are always done using MSBFirst.

Then just end with an endTransmission()!

Also, it's a little unclear whether you have to follow Steps1-3 (Fig 7-9) in order to read registers or just to write to them, but if you still aren't having success then that might be your issue.

answered May 28 at 19:53

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.