This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Arduino BQ34Z110 / BQ34Z100 program to read and write flash

Other Parts Discussed in Thread: BQ34Z100, BQ34Z110, BQ27520-G4, BQ34Z100-G1

Hey,

here is a little program to access the dataflash with an arduino over I2C... I just used it with BQ34Z110 but it should work with BQ34Z100 as well but no guarantee for that. I could solve many problems by reading posts from this forum so it's just fair to give something back:

// Write flash to BQ34Z110 Gas Gauge Chip
// by Clemens Zange

#include <Wire.h>      // Wire library for communicating over I2C

#define BQ34Z110 0x55 // I2C address of the BQ34Z110

#define voltageDeviderH 0x3d  // 15180 mV in decimal is 0x3b4c in HEX     to calibrate: NewVoltDiv=VoltDiv*VoltMess/VoltDisplayed
#define voltageDeviderL 0x8e

#define designCapH 0x05  
#define designCapL 0xdc

#define designEnergyH 0x23
#define designEnergyL 0x28

#define packConfiRegH 0x09
#define packConfiRegL 0x70

#define ledChgReg B10001011

#define alertConfigRegH B11011011
#define alertConfigRegL B01100111

uint8_t flashbytes[32] = {0};

// BQ34Z110 flash Functions

// Reading the 32 Flashbytes of the subclass you enter
void readFlash(uint16_t subclass)
{
  delay(300);
  Wire.beginTransmission(BQ34Z110);
  Wire.write(0x61);
  Wire.write(0x00);
  Wire.endTransmission();
 
  Wire.beginTransmission(BQ34Z110);
  Wire.write(0x3e);
  Wire.write(subclass);
  Wire.endTransmission();
 
  Wire.beginTransmission(BQ34Z110);
  Wire.write(0x3f);
  Wire.write(0x00);   // change this to 0x01 if offset is >31
  Wire.endTransmission();
 
  Serial.print("Flash: ");
 
  for (int i = 0; i < 32; i++)
  {
    
 
    Wire.beginTransmission(BQ34Z110);
    Wire.write(0x40+i);
    Wire.endTransmission(false);
    
    Wire.requestFrom(BQ34Z110,1);
    
    flashbytes[i] = Wire.read();
    //Serial.print(i);
    //Serial.print(": ");
    Serial.print(flashbytes[i],HEX);
    Serial.print(" ");
  }
  Serial.println(" ");
  delay(300);
}


void chgFlash(uint8_t index, int value)
{
  //  change flashbyte first
  flashbytes[index] = value;   
  //flashbytes[1] = 0x60;
 
  // write flashbyte
  Wire.beginTransmission(BQ34Z110);
  Wire.write(0x40 + index);
  Wire.write(flashbytes[index]);
  Wire.endTransmission();
 
/*  Wire.beginTransmission(BQ34Z110);
  Wire.write(0x41);
  Wire.write(flashbytes[1]);
  Wire.endTransmission();
  */
}

void checkSum()
{
  //calc checksum
  int chkSum = 0;
  for (int i = 0; i < 32; i++)
  {
   chkSum += flashbytes[i];
  }
  //Serial.println(chkSum);
  int chkSumTemp = chkSum / 256;
  //Serial.println(chkSum);
  chkSum = chkSum - (chkSumTemp * 256);
  //Serial.println(chkSum);
  chkSum = 255 - chkSum;
  //Serial.println(chkSum);
 
  //write checksum
  Wire.beginTransmission(BQ34Z110);
  Wire.write(0x60);
  Wire.write(chkSum);
  Wire.endTransmission();
}

void writeConfig()
{
  //changing voltagedivider

  Serial.print("Change voltagedivider to:");
  Serial.print((voltageDeviderH<<8)+voltageDeviderL);
  Serial.println("mV max");
  readFlash(104);
  chgFlash(14,voltageDeviderH);
  chgFlash(15,voltageDeviderL);
  checkSum();
  delay(500);
  readFlash(104);

  //changing design capacity & energy

  Serial.print("Change design capacity to:");
  Serial.print((designCapH<<8)+designCapL);
  Serial.print("mAh and design energy to:");
  Serial.print((designEnergyH<<8)+designEnergyL);
  Serial.println("mWh");
  readFlash(48);
  chgFlash(21,designCapH);
  chgFlash(22,designCapL);
  chgFlash(23,designEnergyH);
  chgFlash(24,designEnergyL);
  checkSum();
  delay(500);
  readFlash(48);

  //changing pack configuration register & led charge indication & Alertconfig

  Serial.println("Change pack config register to:");
  Serial.println(packConfiRegH,BIN);
  Serial.println(packConfiRegL,BIN);
  Serial.println("Change LED charge indication register to:");
  Serial.println(ledChgReg,BIN);
  Serial.println("Change alert config register to:");
  Serial.println(alertConfigRegH,BIN);
  Serial.println(alertConfigRegL,BIN);
  readFlash(64);
  chgFlash(0,packConfiRegH);
  chgFlash(1,packConfiRegL);
  chgFlash(4,ledChgReg);
  chgFlash(5,alertConfigRegH);
  chgFlash(6,alertConfigRegL);
  checkSum();
  delay(500);
  readFlash(64);



}

void readFlags()
{
  Wire.beginTransmission(BQ34Z110);
  Wire.write(0x0e);
  Wire.endTransmission();
 
  Wire.requestFrom(BQ34Z110,1);
  Serial.println(Wire.read(),BIN);
 
  Wire.beginTransmission(BQ34Z110);
  Wire.write(0x0f);
  Wire.endTransmission();
 
  Wire.requestFrom(BQ34Z110,1);
  Serial.println(Wire.read(),BIN);
}


void run_command(uint8_t command)
{
  int readln = 0;
  switch (command)
  {
    case 1:
      Serial.println("Which flashregister do you want to read? Type subclass in DEC!");  // enter subclass decimal
      while (Serial.available() <= 0)
      {
      }
      readln = Serial.parseInt();
      Serial.println(readln);
      readFlash(readln);
      delay(500);
      break;

    case 2:
      Serial.println("Writing configuration...");
      writeConfig();      
      break;

  }
  print_menu();

}

void print_menu()
{
  Serial.println();
  Serial.println("*******************Menu*******************");
  Serial.println("Press 1 to read flash.");
  Serial.println("Press 2 to write configuration.");
  Serial.println();
}

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

void loop()
{
 if (Serial.available()>0)           // check for input
    {
      int user_command;
      user_command = Serial.read()-48;      // read command
      //Serial.println(user_command);
      run_command(user_command);
    }
}

  • Clemens

    Thank you for providing this to the forum.

    Tom

  • Hello Clemens
    Could You explain how does the SubClass locators and Offsets works? Datasheet does not provide clear enough description. I don't understand how I can according to offset and subclass values know what is the data location in hex.
  • The bq27520-G4 Technical Reference Manual has an example of accessing the Dataflash using the Subclass and offset method in the "Data Flash Parameter Update Example" section.
  • There is always possibility that I am doing it wrong. Could You tell me someone how to change for example DataCapacity() (command code is 0x3c/0x3d) using "Accessing data flash" procedure? Design Capacity has Subclass ID = 48 and Offset = 21. I want to mention that I am not using TI software - only my IC. So far I can read only these data.
  • There is a code example of reading a block from a Subclass on page 11 of our Going to Production document. SLUA665 You will read the 32 bytes of data and the data will be located at the offset within that block.
  • Could You send me some theory about subclass and offset or write in short something about it? I do not know what it is and how it is interrelated with data location.
  • I currently have a backlog of issues to support, but will try to send something within the next 3 to 5 business days.
  • I have got a huge request. I would be greatfull If You ask someone else to give me the answer or just tell where I should look for it. My time is also out of limit and I need to finish that issue in my school.
    Thanks for reply
  • The data classes are divided into Subclasses. e.g. calibration, gauging, protection, etc. The Subclass section of data is divided into 32 byte blocks. e.g. block 0, 1, 2, etc. The number of blocks in a Subclass with vary depending on how much data is in the data class. You do not have access to the exact address in the data flash memory, so you have to access data via these Subclasses, Blocks and Offsets. The device has a map that finds the data within the memory. Command 3E will identify the Subclass that you want to access and 3F will identify the Block within that Subclass. You will send the commands to select the Subclass and Block and then data will be read from that section when you read the memory. The Offset will tell you where the specific data is located within that 32 byte block of data. You should be able to figure out how this works with this information and the example from the SLUA665 document. I hope that this helps.
  • Many, many thanks. I am very grateful this time - not great-full :)


    EDIT:

    OK, now I can read all data flash but I can't save it. I know that I have to send chcecksum to BlockDataChecksum but it doesn't work. I have notticed few strange things:
    - everytime when i read the checksum of default parameters on my pc via my software it has not equal value

    -I have done checksum like in program code above, is it proper one?

    - Thomas You wrote that
    You have to enter the codes that I mentioned. This can be done through your uC, but you will have to send the data byte swapped. e.g 1404 7236, etc.
    I have entered it but anyway I have to do the checksum, right?

    How to get data from Control register?


    Can anyone tell me how to unseal the device step by step - frame by frame using my IC only? It would be great to get this information as a hex values with addresses, data and comments? If I want to do the checksum do I have unseal the device firstly?
    I am so close to the end, can anyone help me, please?

  • Hi,
    I am not able to write in data Flash memory, the reading is ok but I want to modify my configuration.
    Best regards

    Alr
  • Alr,

    I provided some communications examples in the attached file. There are also some examples of programming the data flash in the bq34z100-G1 datasheet and it can be downloaded from the bq34z100-G1 product folder.

    Tom

    2330.bq34z100 DF access.pdf

  • Hi Alr,

    please discribe your problem exactly. Did you modify the code? It works fine without any issues for me. You need to execute the writeConfig()  command to change flash.


    Greetz,

    Clemens

  • Thanks for this example, do you know why would my BQ34Z110 only respond to address 0x0b and wont even send acknowledge at 0x55, faulty ic ?

  • Hello,

    I never experienced a problem like this. Does the IC work with that wrong address? Can you read voltage or anything or do you just get ack?

    Regards,

    Clemens

  • The device should not acknowledge address 0b. The address word when in normal mode is 1010101x, where the last bit is the R/W bit. The address when in ROM mode is 0001011x, where the last bit is the R/W bit

  • Got it figured out, in fact I don't know what happened, next day after changing the address back to 0x55 its started to work properly.
    I wasn't able to read any register, but the I2C scanner found only 1 connected device at address 0x0b, one more question, why is the Battery Charge reads 25700% ?
  • Actually 0001011x make sense, in Arduino you define the address not including the least significant bit, like 0x55 = 01010101 only 7 bit used and shifted left to add 0 or 1 (0xAA = 10101010), 0x0B = 00001011 << 1 = 00010110