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.

DesignCapacity() is correct but FullChargeCapacity() is incorrect

Other Parts Discussed in Thread: CC2541, BQSTUDIO

Hi,

I am using a BQ27421 with a 120 mAh Li-Ion Polymer battery. I am programming the Design Capacity to 120 mAh and the Design Energy to 444 mWh using the TI CC2541. After programming, the DesignCapacity() reads correct (120) but the FullChargeCapacity() reads 240 mAh. When I do a full discharge and charge cycle, StateOfCharge() only reaches 50%. Please let me know what I may be doing wrong. Thanks for your help!

Bryan

  • Hi,

    I'm still having issues with this. I have also tried setting the Discharge Current Threshold to 10 mA and the Charge Current Threshold to 10 mA. I also programmed the quit current to 50 mA since it said it should be above the standby current of the system. The normal standby current of my system is about 13 mA, the normal discharge current is 110 mA, and the charge current is 100 mA. After I program the Design Capacity, Design Energy, and the current thresholds, the DesignCapacity() reads 120 mAh but the remaining capacity reads 240 mAh. Within a few minutes of discharging the battery, the SOC drops to 0% and the remaining capacity drops to 0 mAh. After a full discharge, I let the system run in standby for a few minutes then fully charged the battery. After a few minutes of charging, the SOC jumps to 100% and the remaining capacity ticks up as expected. When the battery was near a full charge, the remaining capacity dropped back to 0 mAh then started to tick up again from 0. I'm not sure if it reached 120 mAh then dropped to 0 or it dropped to 0 before reaching 120. Please let me know if there is something I'm doing wrong.

    Any help would be appreciated!

  • Have you set the no. of parallel cells correctly?

    Please post the programming files for better help

  • Hey Bryan,

    Were you able to solve it ?

    My problem has been more elementary. On the BQ-27441 gas gauge, I am trying to update design capacity based on user input thru I2C via a connected microcontroller. My code is here: github.com/.../gauge.c

    I am able to read the parameters like voltage, current correctly. But I am not able to update the design capacity. Can you review this code for errors, or show me yours ?

    Thanks
    Chintan Pathak
  • Good evening.
    I use bq27532 and have had the same problem.
    In my fuel gauge datasheet (SLUUB04.pdf), I have found follow example.
    I understand that it's not the same, but, probably you may find something useful (at least their approach).

    Modify WRTEMP of OpConfigB Register
    1. Unseal the device by using the Control() (0x00 and 0x01) command if the device is SEALED.
    (a) Write the first 2 bytes of the UNSEAL key using the Control(0x0414) command.
    (wr 0x00 0x14 0x04)
    (b) Write the second 2 bytes of the UNSEAL key using the Control(0x3672) command.
    (wr 0x00 0x72 0x36)
    2. Write 0x00 using BlockDataControl() command (0x61) to enable block data flash control.
    (wr 0x61 0x00)
    3. Write 0x40 (OpConfigB SubClass) using the DataFlashClass() command (0x3E) to access the
    registers subclass.
    (wr 0x3E 0x40)
    4. Write the block offset location using DataFlashClass() command (0x3F). To access data located at
    offset 0 to 31 use offset = 0x00. To access data located at offset 32 to 41 use offset = 0x01.
    For example, OpConfigB (offset = 4) is in the first block so use:
    (wr 0x3F 0x00)
    5. To read the data of a specific offset use address 0x40 + mod(offset, 32).
    For example, OpConfigB (offset = 4) is located at 0x44, read 1 byte starting at 0x44 address.
    (rd 0x44 old_OP_CONF_B_BYTE)
    In our example, assume WRTEMP(MSB) is cleared.
    6. To read the 1-byte checksum use the BlockDataChecksum() command (0x60).
    (rd 0x60 OLD_checksum)
    7. In this example, set WRTEMP by setting the most-significant bit of OP_CONF_B_BYTE.
    8. The new value for OP_CONF_B_BYTE can be written by writing to the specific offset location.
    For example, to write 1-byte OP_CONF_B_BYTE new value with MSB set to OpConfigB (offset = 4)
    located at 0x44, use command: (wr 0x44 new_OP_CONF_B_BYTE)
    9. The data is actually transferred to the data flash when the correct checksum for the whole block (0x40
    to 0x5F) is written to BlockDataChecksum() (0x60).
    (wr 0x60 NEW_checksum)
    The checksum is (255 – x) where x is the 8-bit summation of the BlockData() (0x40 to 0x5F) on a byteby-
    byte basis. A quick way to calculate the new checksum is to make use of the old checksum:
    (a) temp = mod(255 – OLD_checksum – old_OP_CONF_B_BYTE, 256)
    (b) NEW_checksum = 255 – mod(temp + new_OP_CONF_B_BYTE, 256)
    10. RESET the gauge to ensure the new data flash parameter goes into effect by using Control(0x0041).
    (wr 0x00 0x41 0x00)
    If previously sealed, then the gauge automatically becomes sealed again after RESET.
    11. If not previously sealed, then SEAL the gauge by using Control(0x0020).
    (wr 0x00 0x20 0x00)

    Good luck!

    Alexander.
  • Hey Alexander, 

    The 11 steps you outlined for BQ27532 translate to roughly similar 14 steps in BQ27441, and I implemented them in my code, checking the output of each step against the expected output as given in datasheet, which matches. That makes the problem hard to debug, as I dont understand why my code is not working.

    Anyway, does your code work ? Can you share it ?

    Thanks 

    Chintan Pathak 

  • I just wanted to make sure everyone knew about the sample code available to do exactly what you are all trying to do.

    There is a Linux bq27xxx driver and bqTool linked from here:

    http://processors.wiki.ti.com/index.php/Linux/Android_Software_Solutions_for_TI_Single-cell_Gas_Gauges

    Some new features were recently added to bqTool (which may not be fully documented yet) that allow you to update dataflash / data-memory parameters by parsing a gg.csv file.  The gg.csv file must have "all" columns, so set it up like this:

    1. In bqStudio, go to the Window menu and select Preferences.
    2. Select the Data Memory section in the Preferences window.
    3. Select "Export All Columns".  If you want to also view all columns in the Data Memory plugin, go to the "All Global Settings" section in Preferences and select "Show Advanced Views".
    4. Click OK to apply and close the Preferences window.
    5. Now open up the Data Memory plugin in bqStudio.  It will automatically read all from a connected EVM or gauge
    6. In the Data Memory plugin, you can double-click on the value of a parameter that you want to change, type the new value, and then hit enter to write it to the IC.
    7. Once you've changed all the values you need, click "Read All" to save it as a gg.csv file which will include the addresses and data lengths/types which bqTool can parse.
    8. Simply delete any lines in the gg.csv file which you don't want to program (since they are default) and leave only the lines you want to be programmed by bqTool.
    9. Now get that file into your Linux file-system and you can use bqTool to program the values contained therein.

    Even for those of you not using Linux, hopefully the code in the bq27xxx driver and bqTool will be helpful references.

    This is most useful for anyone using the ROM-based gauges like bq274xx or bq27621, since this is a common method to configure the gauges.  An alternative to using the gg.csv file is to use the .gm.fs file exported by the Golden Image plugin.  bqTool also has code to parse that file, which is basically an I2C script to update all data memory parameters.

    For those of you using one of TI's flash-based gauges, like bq275xx or bq277xx, simply modifying dataflash parameters alone is typically not enough.  You should use the .df.fs file exported by the Golden Image plugin to update the entire dataflash block.  SLUA541A describes the contents of these Flashstream files, while bqTool is an example of how to parse and program them.

    On another slightly related topic, note that directly opening and saving a gg.csv file with Excel is dangerous.  Do not directly open a gg.csv file in Excel or it will automatically convert the text data to numbers.  Excel will strip off leading zeros and trailing decimal places with zeros.  Once this happens and you save it you will not be able to import that file into bqStudio anymore.  To avoid this you must import the gg.csv into Excel as text, and then you can copy and paste columns and edit the file and save it in Excel while maintaining the text formats.  Here is the detailed procedure:

     

    You can import a gg.csv file as text into Excel by following these steps:

    1. Open a new blank sheet
    1. Click on the Data tab
    2. From the toolbar select “From Text”
    3. Select the gg.csv file
    4. In the first dialog, “Delimited” radio button will be automatically selected. Click Next to go ahead.
    1. Unselect “Tab” and select “Comma” as the delimiter.
    1. In the next screen you can select the format of the columns. Scroll down in the “Data Preview” area a bit and you will see all the columns. I press shift and use the mouse to select all the columns. Now, select the “Text” radio button.
    1. Click “Finish”
    2. Now you can save the gg.csv file and all fields will retain the correct formatting so that it can subsequently be imported into bqStudio.

     

    Advantages:

    1. Now you can copy/paste the column with the parameter values between sheets.

     

    Drawbacks:

    1. Instead of opening the gg.csv we are importing the data to a new sheet, which has to be then saved by a different name or should be over-written on the existing one.
    1. On saving there will be extra commas in the information rows at the beginning. Although this doesn’t affect bqStudio, the saved file is not exactly same as the original file.

  • // Read Control Status
    subcmd = bq27532CMD_CTRL_STAT;
    Power_Blocking_Write_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*)&subcmd);
    CtrlStat = 0;
    Power_Blocking_Read_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*)&CtrlStat);

    FG_Access_State = (CtrlStat & bq27532MASK_CTRL_STAT_SEALED) ? FG_SEALED : FG_UNSEALED;

    // unseal FG
    if (FG_Access_State == FG_SEALED)
    {
    subcmd = bq27532VAL_UNSEAL_KEY_1;
    Power_Blocking_Write_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*)&subcmd);

    subcmd = bq27532VAL_UNSEAL_KEY_0;
    Power_Blocking_Write_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*)&subcmd);

    // Read Control Status
    subcmd = bq27532CMD_CTRL_STAT;
    Power_Blocking_Write_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*)&subcmd);
    CtrlStat = 0;
    Power_Blocking_Read_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*)&CtrlStat);

    FG_Access_State = (CtrlStat & bq27532MASK_CTRL_STAT_SEALED) ? FG_SEALED : FG_UNSEALED;
    }


    // unseal FG
    if (FG_Access_State != FG_SEALED)
    {
    // enable Block Data Flash control
    val = bq27532CMD_BDFC_ENABLE_GENERAL_ACCESS;
    Power_Blocking_Write_Command(BQ27532CMD_BLOCK_DATA_CONTROL, 1, &val);

    dataSubclass = FG_DESIGN_CAPACITY_SUBCLASS;
    dataOffset = FG_DESIGN_CAPACITY_OFFSET;
    dataSize = FG_DESIGN_CAPACITY_SIZE;

    // set Data Flash class
    Power_Blocking_Write_Command(BQ27532CMD_DATA_FLASH_CLASS, 1, &dataSubclass);

    // set Block offset
    val = dataOffset/32;
    Power_Blocking_Write_Command(BQ27532CMD_DATA_FLASH_BLOCK, 1, &val);

    // read Data
    Power_Blocking_Read_Command(BQ27532CMD_BLOCK_DATA_BASE + dataOffset%32, dataSize, (uint8_t*)&oldCapacity);

    // read CS
    Power_Blocking_Read_Command(BQ27532CMD_BLOCK_DATA_CHECKSUM, 1, &oldChecksum);


    oldCapacitySum = (oldCapacity & 0x00FF) + (oldCapacity & 0xFF00) >> 8;
    newCapacitySum = (newCapacity & 0x00FF) + (newCapacity & 0xFF00) >> 8;

    uint8_t tmp = (0xFF - oldChecksum - oldCapacitySum) % 0x100;
    newChecksum = 0xFF - (tmp + newCapacitySum) % 0x100;

    // write Data
    Power_Blocking_Write_Command(BQ27532CMD_BLOCK_DATA_BASE + dataOffset % 32, dataSize, (uint8_t*)&newCapacity);

    // write CS
    Power_Blocking_Write_Command(BQ27532CMD_BLOCK_DATA_CHECKSUM, 1, &newChecksum);

    // reset FG
    subcmd = bq27532CMD_RESET;
    Power_Blocking_Write_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*) &subcmd);

    // seal FG
    if (FG_Access_State != FG_SEALED)
    {
    subcmd = bq27532CMD_SEALED;
    Power_Blocking_Write_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*) &subcmd);
    }

    // Read Control Status
    subcmd = bq27532CMD_CTRL_STAT;
    Power_Blocking_Write_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*)&subcmd);
    CtrlStat = 0;
    Power_Blocking_Read_Command(BQ27532CMD_CONTROL_LSB, 2, (uint8_t*)&CtrlStat);

    FG_Access_State = (CtrlStat & bq27532MASK_CTRL_STAT_SEALED) ? FG_SEALED : FG_UNSEALED;

    }
  • Good day, Chintan.

    Was it helpful for you ?

    Alexander.

  • Hey Alexander, 

    Sorry about being out of touch. I actually was sidetracked by dMax's answer where he mentioned the use of bqTool and the linux driver. As it turned out I did understand what needs to be done with the driver, but alas it is non-trivial and I haven't gotten around to implementing it. 

    Also, your code without the starting and finish is a little cryptic for a newbie like me, but I am able to understand the pattern of sequentially following the steps outlined in the datasheet that // unseal the gauge .... etc. and have myself implemented it.

    What would be interesting to learn is, how to debug my code, or any such code, where there are interactions with the gauge registers? 

    - Thanks 

    Chintan Pathak 

  • Good day, Chintan.

    I'm glad if it's useful even a bit.
    Do you think, that I can help you more?
    Don't hesitate.

    Alexander.
  • Dear Alexander, 

    It would be great if you could share your whole code, letting me understand the 'includes', constants etc. Also, if you can review my code for errors https://github.com/chintanp/i2c-charger/blob/master/BQ-27441-Gauge/c/gauge.c . And finally what are your thoughts on the TI linux kernel updates related to fuel gauges etc. found here: https://git.ti.com/bms-linux