Using I2C for SMBus device communications

I made the changes but still get compile errors.

In the Particle DEV I get compile errors but no details on the reason for the compile failure which you can see below:

So I tried to compile it using the Particle Build online using the same code and it does provide a reason for the errors which you can see below:

The exact code I used is below:

The .ino :

// This #include statement was automatically added by the Particle IDE.
#include "BQ20Z45.h"

#include "application.h"
#include "BQ20Z45.h"            //Include BQ78350 Header File

// Store an instance of the BQ20Z45 Sensor
BQ20Z45 bms;

//char strBuffer[33];    // This is a Buffer to store 32 bit data strings read from the BQ78350 Fuel Gauge. Not Sure if this is the best place for this code.

uint16_t GaugingStatus = 0;

void setup(void)
{
  // We start the serial library to output our messages.
  Serial.begin(115200);

  // Start i2c communication.
  Wire.begin();
}


void loop(void)
{

//Serial.print("Device Name: ");
bms.GaugingStatus(result);


delay(4000);

}

The .CPP :

#include "application.h"
#include "BQ20Z45.h"
//#include "Arduino.h"
#include "application.h"

/////////////////////////////////////////////////////////////////////////////
// Functions Below


// Fuel gague function to read Manufacturer Access Data registers when in sealed mode.
int BQ20Z45::readBytes(uint8_t address, void* buffer, size_t len, boolean exactLen)
{
  int pos;
  int cnt;                                            // to hold the actual length the address would hold

  // Read the length of the string
  Wire.beginTransmission(BQ20Z45_Address);            //Setup Write to Gauge
  Wire.write(0x44);                                   //Manufacturer Block Read
  Wire.write(0x02);                                   //How Many Bytes to expect Next
  Wire.write(address);                                //Manufacturer Access Command - Example 0x01 Device Type
  Wire.write(0x00);                                   //First Byte of Command
  Wire.endTransmission(true);                         //Repeated Start = True

  Wire.beginTransmission(BQ20Z45_Address);            //Setup Write to Gauge
  Wire.write(0x44);                                   //Manufacturer Block Read
  Wire.endTransmission(true);                         //Repeated Start

  Wire.requestFrom(BQ20Z45_Address, 1, true);         //Setup Reading of Returned Data
  cnt = Wire.read();                                  // length of the string thats about to return
  cnt++;                                              // plus one to allow for the length byte on the reread

  cnt = Wire.requestFrom(BQ20Z45_Address, cnt, true); // readRequest returns # bytes actually read

  if (cnt == len+3 || !exactLen && cnt > 3)
  {                                                   // we got the expected read count
    cnt -= 3;                                         // drop the first three bytes
    Wire.read();                                      //   length received lsb
    Wire.read();                                      //   length received msb (always 0) ???
    Wire.read();                                      //   address from which we just read
    memset(buffer, 0, len);                           // clear the buffer for safe measure
    for (pos = 0; pos < cnt; pos++)
    {
      if (pos < len) buffer[pos] = Wire.read();       // as long we have room in the buffer add to it
      else Wire.read();                               // otherwise just drop it
    }
    return cnt;
  }
  else
  {                                                   // drop them all
    for(pos = 0; pos < cnt; cnt++)
      Wire.read();
  }

  return -cnt;                                        // includes the extra three bytes
}


/////////////////////////////////////////////////////////////////////////////
// Class Methods Below



int BQ20Z45::GaugingStatus(uint16_t* result) //int BQ20Z45::GaugingStatus(char *result)
{

  return readBytes(BQ20Z45_GaugingStatus, (void*)result, sizeof(*result));
   // for platforms with incompatible endianness you may want to
   // add some code to correct the byte order
}

The .H :

#ifndef BQ20Z45_h
#define BQ20Z45_h


#define BQ20Z45_Address           0x0B
#define BQ20Z45_ManBlockAccess    0x44
#define BQ20Z45_ManAccess         0x00

#define BQ20Z45_GaugingStatus     0x56



class BQ20Z45
{
    public:

    int GaugingStatus(uint16_t *result);
    
    protected:

    private:

  int readBytes(uint8_t address, void* buffer, size_t len, boolean exactLen = true);
  
};
#endif

The mismatch errors I could probably figure out but the others are beyond my current understanding.

Sucks that Particle DEV does not provide the same detailed error list and that the online build does. Any idea on why that happens?

That was my bad :blush:
This should have been

if (pos < len) ((uint8_t*)buffer)[pos] = Wire.read(); 

Because Dev (as it currently is) sucks all together. I rather use CLI.

To get rid of the warnings (which don't harm) you could slightly alter some lines

  if ( (cnt == (int)(len+3)) || (!exactLen && cnt > 3) )
 ...
  if (pos < (int)len) ((uint8_t*)buffer)[pos] = Wire.read(); 
1 Like

You also need to change the above line in loop() to,

bms.GaugingStatus(&GaugingStatus);

To be more consistent with naming conventions though, I would name that variable gaugingStatus (with a lowercase g).

1 Like

@ScruffR Success!

That was a long road to travel, but it's working now :smile: Feels good :wink:

THANK YOU SO MUCH FOR HELPING ME WITH THIS!

@Ric Thanks for that tip also! One less than I had to ask ScruffR for help with, which is nice :smile:

I would have figured out to add the GaugingStatus but adding the & sign in front of it is something I have not fully grasped yet, although @ScruffR did mention this to me in a post above:

1 Like

And the more important point IMHO is not the success but the insight you gained on the way :wink:
The success is one benefit, but the lessons learnt will benefit you over and over when you run into similar questions.


Give a starving man a fish or teach him how to fish.

1 Like

@ScruffR I agree 100% :smile:

I have come a long way over the past few years thanks to all the wonderful and helpful people on the forums and internet.

Are you located in Germany?

Salzburg in Austria acutally, but just 5 minutes from the border to Germany.

Sweet! I've never visited Germany but hope to in the future. Crazy how the internet can bring people together from all over the world.

I'm located in Indiana, USA.

2 Likes

@ScruffR Another question :smiley:

I have one command that is returning 34 bytes of data and I’m saving that in a StrBuffer that is sized to 34 bytes in size so it can actually hold that much data. Even though I increased the buffer size I now see that the Wire.RequestFrom function is coded to max out to only return 32 bytes max.

I found this on the Arduino forums:


So it sounds like I have to manually change the count BUFFER_Legnth line in the Wire.H file?

Does this apply the same to the Particle product line?

Here is the 34 byes the chip is sending back to the PC evaluation software:

The Photon’s Wire.RequestFrom function is cutting off the data at 32 bytes which is causing me to miss the reading for 3 variables that are important:

What do you think?

You may want to look in these threads

[SOLVED] I2C requestFrom() - how to read > 32 bytes?
I2C - Increasing buffer size to 258 compilation error

1 Like

Thanks! Not sure why I didn’t search this forum first and assumed I was the first to have this problem :confused:

2 Likes

Hello can some body tell is it possible to reset bq20z45 using arudino.i want to clear the Flags,mosfet status,capacity,current,cycle count,…
here i found software http://be2works.com which does it but in my country related hardware is not available.
any help is appreciated

It’s possible but you need the register map and maybe SMBus formatting to get it to work.

To make life easier just source the TI EV2300 or EV2400 adapter somehow.

thank you for replay but i know only soldering no programming .also sourcing TI EV2300 or EV2400 to bhutan will cost around $350 which is way expensive to me afford..

can you guide any way to do..this will help alot..
thank you..!

You would need the Datasheet for the TI chip your trying to read and then create some code to read and write those registers you need to change using a Microcontroller of your choice.

hey i got datasheet with registers can you create an example code how to read and write those registers…?

I do not have time to help you with this.

You’re going to have to learn this yourself or search the web for Arduino code that is already written for this line of BQ devices. Search for the BQ40z50 and see if anything comes up, its a popular chip.

Hello RWB!!!

Great fault finding so far :slight_smile:
I am working on the same project.But i need to pass battery voltage and current data from BMU to my arduino.My bmu has the BQ40z50. Im little bit lost… Can you repost your working code or give some basic example as reference point?

Thank you

There will be plenty of examples out there like this https://github.com/ArminJo/Smart-Battery-Module-Info_For_Arduino but also others for other processors. You should also be able to get some ideas by looking at Particles code for their PMIC, or samples for other TI devices, many of them are similar.

For non-arduino style systems they won’t have the convenience of the Wire library so will implement I2C at quite a low level, the Wire library hides a lot of complexity.
If you find a full library it will include methods for every feature on the device, however (presumably) you only want a few select figures and you can get those with a few select commands.

I would recommend reading how to use Wire.read/write and experiment with reading some of the values off the chip. Once you can do that the only thing left is probably some maths to turn the values into numbers you can read.
Lastly I can also tell you that Linear BMU/PMICs typically have what they call “Linduino” libraries for their products in with their documentation, they need a little tweaking to work on a photon as they re-implement some I2C stuff for no apparent reason .

Could you access to the bq with a valid response? if so, is the source code accessible?