TI Battery Controller Chip (BQ34Z100) I2C Data

I'm trying to get useful data from this chip via the i2c bus: http://www.ti.com/lit/ds/symlink/bq34z100-g1.pdf

This is my sample code that I'm using: bq34z100/bq34z100_status_arduino.ino at master · samuelvanderwaal/bq34z100 · GitHub

Except it seems to be giving me garbage data. I also check the battery chip using an EV2300 and it's giving me valid data there with the correct registers.

After 8 hours working on this, I am lost of words as to what I should do?

This is the data it produces:

Battery Charge: 4294967039%
Remaining Capacity: 4294967039 mAh
Battery Pack Voltage: 4294967039 mV
Average Current Draw: -257 mA
Instantaneous Current Draw: -257
Instantaneous Current Draw LSB: 4294967295
Instantantous Current MSB: 4294967295
Battery Temperature: -298 C
Power Draw: -1103806.50 W

The datasheet is not 100% clear, but I think that two-byte data can be written at once (probably more) and it is allowed to read multiple bytes. A repeated start is allowed between writing the command (the register address) and reading data.

For the control register the datasheet says that it “…requires a subsequent two-byte subcommand”. The word “requires” could indicate that it must be done that way.

The hard part is to retrieve data and the different modes of the chip. Sometimes data has to be copied before it can be read.

In the setup() there is no initialization for the chip ? Does it need to be awaken from a sleep mode or is some kind of initialization needed ?
It can be in “SEALED”, “UNSEALED”, “BOOTROM”, “FULL SLEEP”, “CALIBRATION” or “FULL ACCESS” mode, but I don’t know what they are. There is even a “NORMAL” mode :o

You can start to check if you are at least communicating with the chip.

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

  Wire.beginTransmission( BQ34Z100);
  byte error = Wire.endTransmission();
  if( error == 0)
  {
    Serial.println("The chip is found");
  }
  else
  {
    Serial.println("Error, not connected to the chip");
  }
}

If that does not work, try a I2C scanner until it works.

The next step would be to read fixed data, for example a WHO_AM_I register. The “Manufacturer Info Block” can not be read without selecting that page in the control register. Maybe you can add that later.

The first thing you do is read two bytes, but SOC data is only one byte. You are combining the “ME” register data with it.

Perhaps it is easier to start with the temperature. You can add this to setup(), but only after that is confirmed that you are communicating with the chip.

  Wire.beginTransmission( BQ34Z100);
  Wire.write( 0x0C);       // command for temperature register
  Wire.endTransmission();
  
  Wire.requestFrom( BQ34Z100, 2);  // temperature is two bytes
  uint16_t x = Wire.read();  // MSB first
  x <<= 8;
  x |= Wire.read();

  float celcius = (float( x) / 10.0) - 273.15;
 
  Serial.print( "Temperature = ");
  Serial.print( celcius);
  Serial.print( " Celcius (0x");
  Serial.print( x, HEX);
  Serial.println( ")" );

The hexadecimal value should be around 0x0B73 for 20 degrees.

Oops, it is lowest byte first.
uint16_t x = Wire.read() ; // lowest byte first
x |= Wire.read() << 8 ;

Running the I2C scanner gets me the following:

But when I use your first set of code, I get "Error, not connected to chip." So it's kind of weird that the chip can be detected but I cannot communicate with the chip. using beginTransmission.

I changed BQ34Z100 to 0x55 and 55 and 00110011 but all of it is still returning the same request.

Please give a link to the I2C Scanner that you have used.
Which Arduino board do you use ? I assumed that you were using an official Arduino board.
To which pins is the I2C bus connected ?

The I2C bus for the ESP8266 could be started with Wire.begin(4,5)

I'm using this: i2c_port_address_scanner/i2c_port_address_scanner.ino at master · jainrk/i2c_port_address_scanner · GitHub

It works now!!! Thank you! The board I'm using is the Leonardo, but I was working on the ESP board.

The Wire.begin(2, 14); wasn't configured so it was returning garbage data.

The hard part is yet to come.
To read the manufacturer block, you can use this: BQ34Z100/bq34z100.cpp at master · Ralim/BQ34Z100 · GitHub.

My example for the temperature is wrong. Reading the datasheet I thought that the highest byte was transferred via the I2C as the first byte. The code at Github assumes that the lowest byte is the first byte that is received.
After some more reading, the first received byte is indeed the lowest bytes.