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.

BQ27425-G2A: RESET command works on some devices but not on others

Part Number: BQ27425-G2A

Hi, we are using the bq27425YZFR-G2A battery fuelgauge.  Sometimes we have to swop batteries and in those cases have to reset the State of Health (SoH).  So I implemented the RESET (0x0041) in code.  What is find is that on some products it resets the SoH but on others the SoH stays the same.  All other commands sent to the chip works so I'm very confident that the hardware works.  I looked at the chip codes to see if when "working" chip is different from the others that does not reset SoH.  

TI 46AXXC1 BQ27425 (SOH doesn't reset)
TI 85C9HV1 BQ27425 (SOH doesn't reset)
TI 34A0XC1 BQ27425 (SOH reset works)

Regards
Johann

  • Hello Johann,

    If you perform a reset or the gauge losses power briefly, all the values like SOH, SOC, FCC will be recalculated based on the ROM default memory. What are the values before and after the reset?

    Sincerely,

    Wyatt Keller

  • Hi Wyatt, in one of units, the "SOH reset works" one, the SoH and SoC goes to 0 after a RESET command and then after a full charge-discharge cycle it has a value somewhere above 90%. With the other units I tested the value remains exactly where it was after a RESET command, e.g. 87%. I swopped the CPU PCBs around to confirm that it is not some difference in firmware that causes the issue - but it is specific to the fuelgauge chip.

    To confirm I have just removed and re-inserted the batteries of the 3 units that do not reset their SoH with the RESET command. And even after removing the battery for about 1 minute they still remember their SoH. So is it possible for the SoH and SoC to be written into non-volatile memory?

    regards
    Johann

    PS: Apologies for the delayed reply. I posted a reply 2 days ago but instead of posting it my browser gave an error which I didn't see.

  • Hi Wyatt, while waiting for you I implemented code to set the fuelgauge to UNSEAL mode before sending the RESET command, but it didn't make a difference to the problem described above.  I used the default KEY as specified in the datasheet.  The one thing I'm not sure about it what return to expect from the UNSEAL command.

    #define SUB_UNSEAL_KEY 0x36720414 //4byte unseal key default
    #define SUB_UNSEAL_KEY0 0x3672 //Host must send: 72 36
    #define SUB_UNSEAL_KEY1 0x0414 //Host must send: 14 04

    static void send_unseal_keys(const HANDLE i2c_handle)
    {
      // Set-up transmission buffer.
      tx_buffer[0] = (uint8_t) CMD_CONTROL;
     
      tx_buffer[1] = (uint8_t)(SUB_UNSEAL_KEY1 >> 8);
      tx_buffer[2] = (uint8_t)(SUB_UNSEAL_KEY1);
      tx_buffer[3] = (uint8_t)(SUB_UNSEAL_KEY0 >> 8);
      tx_buffer[4] = (uint8_t)(SUB_UNSEAL_KEY0);
      
      // We send 5 bytes and expect X bytes in return
      fuelgauge_command(i2c_handle, 5, 2);
    }

  • The way this works is:

    SOH is stored in RAM. It is not stored in EEPROM. So if you reset the gauge, it will reset SOH.

    The gauge will, however, calculate SOH based on parameters that are stored in EEPROM. Therefore SOH itself will "follow" the gauge, not the battery.

    SOH is calculated with a virtual reference load (SOH load I) at 25 deg.C. The gauge runs a discharge simulation from a full charge down to terminate voltage with these parameters.

    This discharge simulation uses QMax and Ra, both of which are learned parameters and stored in EEPROM, hence SOH will follow the gauge and not the battery. If you connect a gauge that has learned QMax and Ra from battery "A" to battery "B" and reset the gauge, the gauge will calculate SOH for battery "A" because it learned QMax and Ra for battery "A". It will eventually learn QMax and Ra from battery "B" and then SOH will change accordingly.

    If SOH is zero, then the gauge either learned very high Ra or very low QMax or it detected incorrect charge termination (because that defines the starting point of the discharge simulation for SOH purposes (and for FCC)). I'd check Ra, QMax and VatChgTerm for the gauge that reports 0% SOH.

  • Thank you.  I am out of the office currently and will give this full attention when I'm back on 17 May.  Please keep this issue open until then.

    Regards Johann

  • Hi Dominik, I have the following follow up questions:
    1.   Getting to the unseal command - how can I be sure my unseal command executed and that I even have the right KEYs? (Also see my previous post.)
    2.  By VatChgTerm (Voltage at Charge Termination) do you mean check the CHG bit?
    3.  After a RESET was executed, how quickly is Rs and QMax learned again (how many seconds)?
    How much time or charge-discharge-cycles (more or less) will it take to update Rs and QMax after a new battery has been connected?

    FYI:
    After issuing a RESET command on the fuelgauge that does reset, the LOW byte of CONTROL_STATUS goes through all the following values in hex:  61 60 61 66 68 6A 6B 6C 6D 6E.  I don't understand why it seems to count up.  I checked the code again and don't see anything that would increment it - it only reads it from the chip using the simple code.
    The HIGH byte stays at 0x0B (indicating QMAX and R-TABLE has been updated).

    static void update_control_status(const HANDLE i2c_handle)
    {
    // Set-up transmission buffer.
    tx_buffer[0] = (uint8_t) CMD_CONTROL;
    // Control status sub-command low byte.
    tx_buffer[1] = (uint8_t) SUB_CONTROL_STATUS;
    // Control status sub-command high byte.
    tx_buffer[2] = (uint8_t) (SUB_CONTROL_STATUS >> 8);

    // We send three bytes and expect 2 bytes in return when requesting the control status.
    fuelgauge_command(i2c_handle, 3, 2);

    // Update the control status information in the status structure if the error flag is not set.
    if (fuelgauge_state.internal_error == 0) {
    fuelgauge_state.control_status[0] = rx_buffer[0];
    fuelgauge_state.control_status[1] = rx_buffer[1];
    }
    }

    Regards  Johann