Help using I2C to read a register value

Hey guys!
First time trying to use an I2C device to read a value from a register.

We have an evaluation board which is basically a wireless power transfer pad, and will send out power when an object is present to charge.

We are using an Arduino Uno to program an ATMega328P microcontroller that will go onto our breadboard. We have a connection going from the SDA of the P9242-R evaluation board we are using, going into pin 27 on our breadboard, which would be the SDA pin.

Basically we are trying to read from the state register. Attached is the image from the data sheet of the register values, and some information about the registers and addresses.

For example, if nothing was being charged, we wanted to see the value of the idle state which is function 1. The code below shows an example of what we have tried, but all that is printed to the serial monitor is 255, and we aren’t sure why.

Any and all help would be great! Thanks!

#include <Wire.h>

byte ADDRESS = 0x06E0, REGISTER;

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

void loop() {
  Wire.beginTransmission(ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(ADDRESS, byte(2));
  REGISTER = Wire.read();
  Serial.println(REGISTER);
}

Why not start by defining the problem with specifications. What is the expected outcome. Purchase the Arduino cookbook and read it, this will give you some basics. also use the online tutorials and videos available, there are many good ones on this web site. Pay close attention to the I2C sections, especially the hardware portion. At this point you will be able to define the problem and may have already solved it. Download one of the many I2C scanners and use it. Do not burn time trying to program until you can actually read the part with the scanner.

Thanks, I didn’t know that I2C scanners existed haha!

I have the Arduino Uno connected by itself to the evaluation board, with the microcontroller back in the Uno also so its all running there.

I ran this scan → https://forum.arduino.cc/index.php?topic=197360

And it gave me two hex values 0x61 and 0x62. According to the data sheet, 0x61 is the slave address so that makes sense, but I don’t get where the 0x62 came from.

I was messing with the code, and had increase the loop count for address from 120 to 255, and then it found two more hex values, 0xE1 and 0xE2, but I’m not sure what those address are for.

Thanks for the help man!

The maximum is 127, there is no higher address.
The values 0xE1 and 0xE2 are the same as 0x61 and 0x62.

Page for P9242-R : https://www.idt.com/us/en/products/power-management/wireless-power/wireless-power-transmitters/p9242-r-wpc-122-compliant-wireless-charging-transmitter-15w-applications.

I assume that the P9242 runs internally at 3.3V. The Arduino Uno has a 5V I2C bus, but according to the datasheet the maximum voltage for SDA and SCL is 6V, so that should be okay.

In your sketch, you do just one Wire.write(0); for the register address, but it requires two bytes.
To read data, it needs a repeated start.

You could try to read the identifier:

Wire.beginTransmission(ADDRESS);
Wire.write(0x01); // MSB of Device ID Register
Wire.write(0x04); // LSB of Device ID Register
Wire.endTransmission(false);  // do not send a stop to make a repeated start

Wire.requestFrom(ADDRESS, byte(2));
Serial.println(Wire.read(), HEX);      // is it 42 hex ?
Serial.println(Wire.read(), HEX);      // is it 92 hex ?

The I2C Address 0x62 is not mentioned in the datasheet. Perhaps it is a service mode or a glitch or a bug or undocumented. I suggest to ignore it. Use 0x61 as is written in the datasheet.

So we changed our code to this, and then in the serial monitor showed “FFFFFFFF”. Not really sure what’s happening at this point.
You did mention plugging into 5V, right now the only connections going from the Uno into the evaluation board are from A5 going into SCL, A4 going into SDA, and GND going into GND. So not sure if that 5V needs to be plugged into the evaluation board also.
Thanks!

#include <Wire.h>

byte ADDRESS = 0x06E0;

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

void loop() {
  Wire.beginTransmission(ADDRESS);
Wire.write(0x01); // MSB of Device ID Register
Wire.write(0x04); // LSB of Device ID Register
Wire.endTransmission(false);

Wire.requestFrom(ADDRESS, byte(2));
Serial.println(Wire.read(), HEX);   
Serial.println(Wire.read(), HEX);  
}

I overlooked that you had a impossible I2C address.
When you request data from something that does not exist, then the Wire.read() returns -1, which will be shown as FFFFFFFF when printing it as HEX number. It is not data returned by the module, it indicates an error.

The highest possible I2C address is 0x7F or 127dec.

Can you try this:

#include <Wire.h>

byte ADDRESS = 0x61;

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

void loop() 
{
  Wire.beginTransmission( ADDRESS);
  Wire.write( 0x01); // MSB of Device ID Register
  Wire.write( 0x04); // LSB of Device ID Register
  int error = Wire.endTransmission( false);  // no stop, to create a repeated start.
  if( error != 0)
    Serial.println( "Error, no device found at 0x61");

  int n = Wire.requestFrom( ADDRESS, byte(2));
  if( n != 2)
  {
    Serial.println( "requestFrom failed");
  }
  else
  {
    Serial.println(Wire.read(), HEX);
    Serial.println(Wire.read(), HEX);
  }

  delay(5000);
}
1 Like

That worked! Thanks so much!
Once I changed the address, all the register values came in. I changed it to the state register to confirm it could get the values I wanted, and it did!
Thanks for all your help man!

Some registers have a single byte and some have two bytes. When there are two bytes the LSB comes first according to the datasheet.
Have you seen the ‘uint16_t’ names before ? That is to specify a 16 bit unsigned variable.
For 8 bits without sign-bit it is ‘uint8_t’ or ‘byte’.

The ‘HEX’ is an option for the Serial.println().
https://www.arduino.cc/reference/en/language/functions/communication/serial/println/
All the documentation (often with small examples) is online. To learn what the functions can do, you have to read it a lot when starting with Arduino.

// single byte
Wire.requestFrom( ADDRESS, byte(1));
byte myDataByte = (byte) Wire.read();
Serial.println( myDataByte, HEX);
// two bytes
Wire.requestFrom( ADDRESS, byte(2));
uint16_t myData = Wire.read();      // LSB into the lower byte
myData |= Wire.read() << 8;    // shift the data into the MSB and do bitwise OR with myData
Serial.println( myData, HEX);

Arduino has a macro ‘word()’, you can use that as well.

// two bytes
Wire.requestFrom( ADDRESS, byte(2));
byte lsb = Wire.read();
byte msb = Wire.read();
uint16_t myData = word( msb, lsb);
Serial.println( myData, HEX);   // print as HEX