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.

BQ27531-G1: Unable to charge battery or enable OTG on BQ27531-G1 Fuel Gauge with Charger BQ24196

Part Number: BQ27531-G1
Other Parts Discussed in Thread: BQ24196, , EV2400

We have a embedded linux design project working BQ27531-G1 fuel gauge for control BQ24196, monitoring voltage, SOC, current and enable USB OTG.

In the previous version, we were only working with BQ24196, but over time we realized that we could not save the register values and monitor some values (SOC, voltage etc..). Therefore, we thought that we should switch to the BQ27531-G1 IC.

What materials do we have?

We dont use evaluation board. We communicate with embedded linux. This is the schematic we use:

For communicate, we are using python3 smbus2 and codes exists at below.

from smbus2 import SMBus
from smbus2 import i2c_msg
import time
import RPi.GPIO as GPIO

BQ27531_I2C_ADDRESS                         = 0x55

BQ27531_SS_KEY0                             = 0x3672  
BQ27531_SS_KEY1                             = 0x0414

BQ27531_FAS_KEY0                            = 0x0000  
BQ27531_FAS_KEY1                            = 0x0000

BQ27531_CMD_CNTL							= 0x00
BQ27531_CMD_AT_RATE							= 0x02
BQ27531_CMD_AT_RATE_TIME_TO_EMPTY			= 0x04
BQ27531_CMD_TEMP							= 0x06
BQ27531_CMD_VOLTAGE							= 0x08
BQ27531_CMD_FLAGS							= 0x0A
BQ27531_CMD_NOMINAL_CAPACITY				= 0x0C
BQ27531_CMD_FULL_CAPACITY					= 0x0E
BQ27531_CMD_REMAINING_CAPACITY				= 0x10
BQ27531_CMD_FULL_CHARGE_CAPACITY			= 0x12
BQ27531_CMD_AVERAGE_CURRENT					= 0x14
BQ27531_CMD_TIME_TO_EMPTY					= 0x16
BQ27531_CMD_REMAINING_CAPACITY_UNFIL		= 0x18
BQ27531_CMD_STANDBY_CURRENT					= 0x1A
BQ27531_CMD_REMAINING_CAPACITY_FILTERED		= 0x1C	
BQ27531_CMD_PROG_CHARGING_CURRENT			= 0x1E	
BQ27531_CMD_PROG_CHARGING_VOLTAGE			= 0x20
BQ27531_CMD_FULL_CHARGE_CAPACITY_UNFIL		= 0x22	
BQ27531_CMD_AVERAGE_POWER					= 0x24
BQ27531_CMD_FULL_CHARGE_CAPACITY_FIL		= 0x26
BQ27531_CMD_STATE_OF_HEALTH					= 0x28
BQ27531_CMD_CYCLE_COUNT						= 0x2A
BQ27531_CMD_STATE_OF_CHARGE					= 0x2C
BQ27531_CMD_TRUE_SOC						= 0x2E
BQ27531_CMD_INSTANTANEOUS_CURRENT_READING	= 0x30
BQ27531_CMD_INTERNAL_TEMPERATURE			= 0x32
BQ27531_CMD_CHARGING_LEVEL					= 0x34
BQ27531_CMD_LEVEL_TAPER_CURRENT				= 0x6E
BQ27531_CMD_CALC_CHARGING_CURRENT			= 0x70
BQ27531_CMD_CALC_CHARGING_VOLTAGE			= 0x72

BQ27531_CNTL_CONTROL_STATUS                 = 0x0000
BQ27531_CNTL_DEVICE_INFO		            = 0x0001
BQ27531_CNTL_FW_VERSION			            = 0x0002
BQ27531_CNTL_HW_VERSION			            = 0x0003
BQ27531_CNTL_OTG_ENABLE			            = 0x0015
BQ27531_CNTL_OTG_DISABLE		            = 0x0016
BQ27531_CNTL_DIV_CUR_ENABLE		            = 0x0017
BQ27531_CNTL_CHG_ENABLE			            = 0x001A
BQ27531_CNTL_CHG_DISABLE		            = 0x001B
BQ27531_CNTL_GG_CHGRCTL_ENABLE	            = 0x001C
BQ27531_CNTL_GG_CHGRCTL_DISABLE	            = 0x001D
BQ27531_CNTL_SEALED				            = 0x0020
BQ27531_CNTL_RESET	                        = 0x0041

BQ27531_STATUS_FAS		                    = (1<<14)
BQ27531_STATUS_SS		                    = (1<<13)
BQ27531_STATUS_CSV		                    = (1<<12)
BQ27531_STATUS_CCA		                    = (1<<11)
BQ27531_STATUS_BCA		                    = (1<<10)
BQ27531_STATUS_OCVCMDCOMP	                = (1<<9)
BQ27531_STATUS_OCVFAL		                = (1<<8)

BQ27531_STATUS_INITCOMP		                = (1<<7)
BQ27531_STATUS_HIBERNATE	                = (1<<6)
BQ27531_STATUS_SNOOZE	                    = (1<<5)
BQ27531_STATUS_SLEEP		                = (1<<4)
BQ27531_STATUS_LDMD			                = (1<<3)
BQ27531_STATUS_RUP_DIS		                = (1<<2)
BQ27531_STATUS_VOK			                = (1<<1)
BQ27531_STATUS_QEN			                = (1<<0)

BQ27531_FLAG_OT				                = (1<<15)
BQ27531_FLAG_UT				                = (1<<14)
BQ27531_FLAG_CALMODE		                = (1<<12)
BQ27531_FLAG_DIV_CUR		                = (1<<11)
BQ27531_FLAG_GG_CHGRCTL_EN	                = (1<<10)
BQ27531_FLAG_FC				                = (1<<9)
BQ27531_FLAG_CHG			                = (1<<8)
BQ27531_FLAG_OCV_GD			                = (1<<5)
BQ27531_FLAG_WAIT_ID		                = (1<<4)
BQ27531_FLAG_BAT_DET		                = (1<<3)
BQ27531_FLAG_SOC1			                = (1<<2)
BQ27531_FLAG_SYSDOWN		                = (1<<1)
BQ27531_FLAG_DSG			                = (1<<0)

GPIO_OTG_PIN = 6
GPIO_CE_PIN  = 13
GPIO_PSEL_PIN = 19

def dec_to_bool(value):
    return 1 if value > 0 else 0

def bq27531_print_status(data):
    print(f"Control Status: FAS: {dec_to_bool(data & BQ27531_STATUS_FAS)}, SS: {dec_to_bool(data & BQ27531_STATUS_SS)}, CSV: {dec_to_bool(data & BQ27531_STATUS_CSV)}, CCA: {dec_to_bool(data & BQ27531_STATUS_CCA)}, BCA: {dec_to_bool(data & BQ27531_STATUS_BCA)}, OCVCMDCOMP:   {dec_to_bool(data & BQ27531_STATUS_OCVCMDCOMP)}, OCVFAIL: {dec_to_bool(data & BQ27531_STATUS_OCVFAL)}, INITCOMP: {dec_to_bool(data & BQ27531_STATUS_INITCOMP)}, HIBERNATE: {dec_to_bool(data & BQ27531_STATUS_HIBERNATE)}, SNOOZE: {dec_to_bool(data & BQ27531_STATUS_SNOOZE)}, SLEEP: {dec_to_bool(data & BQ27531_STATUS_SLEEP)}, LDMD: {dec_to_bool(data & BQ27531_STATUS_LDMD)}, RUP_DIS: {dec_to_bool(data & BQ27531_STATUS_RUP_DIS)}, VOK: { dec_to_bool(data & BQ27531_STATUS_VOK)}, QEN: {dec_to_bool(data & BQ27531_STATUS_QEN)}");

def bq27531_print_flags(data):
    print(f"Flags Status: OT:{dec_to_bool(data & BQ27531_FLAG_OT)}, UT: {dec_to_bool(data & BQ27531_FLAG_UT)}, CALMODE: {dec_to_bool(data & BQ27531_FLAG_CALMODE)}, DIV_CUR: {dec_to_bool(data & BQ27531_FLAG_DIV_CUR)}, GG_CHGRCTL_EN: {dec_to_bool(data & BQ27531_FLAG_GG_CHGRCTL_EN)} , FC: {dec_to_bool(data & BQ27531_FLAG_FC)}, CHG: {dec_to_bool(data & BQ27531_FLAG_CHG)}, OCV_GD:{dec_to_bool(data & BQ27531_FLAG_OCV_GD)}, WAIT_ID: {dec_to_bool(data & BQ27531_FLAG_WAIT_ID)}, BAT_DET: {dec_to_bool(data & BQ27531_FLAG_BAT_DET)}, SOC1: {dec_to_bool(data & BQ27531_FLAG_SOC1)}, SYSDOWN: {dec_to_bool(data & BQ27531_FLAG_SYSDOWN)}, DSG: {dec_to_bool(data & BQ27531_FLAG_DSG)}");

def bq27531_prepare_subcommand_packets(subcommand):
    return [subcommand & 0xFF, (subcommand >> 8) & 0xFF]

def bq27531_read_command(i2c_bus, command, len = 2):
    if len == 1:
        return i2c_bus.read_byte_data(BQ27531_I2C_ADDRESS, command)
    else:
        return i2c_bus.read_word_data(BQ27531_I2C_ADDRESS, command); 

def bq27531_read_subcommand(i2c_bus, subcommand):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(subcommand));
    return bq27531_read_command(i2c_bus, BQ27531_CMD_CNTL)

def bq27531_start_otg(i2c_bus):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_CNTL_OTG_ENABLE))

def bq27531_stop_otg(i2c_bus):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_CNTL_OTG_DISABLE))

def bq27531_start_charge(i2c_bus):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_CNTL_CHG_ENABLE))

def bq27531_stop_charge(i2c_bus):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_CNTL_CHG_DISABLE))

def bq27531_start_gg_controller_charge(i2c_bus):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_CNTL_GG_CHGRCTL_ENABLE))

def bq27531_stop_gg_controller_charge(i2c_bus):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_CNTL_GG_CHGRCTL_DISABLE))

def bq27531_reset(i2c_bus):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_CNTL_RESET))

def bq24196_registers(i2c_bus):
    registers = []

    for i in range(-1, 10):
        registers.append(bq27531_read_command(i2c_bus, i + 0x75, len = 1))

    return registers;

def bq24196_print_registers(registers):
    for i in range(len(registers)):
        if i != len(registers) - 1:
            print(f"REG{i - 1}: {hex(registers[i])}, ", end = '')
        else:
            print(f"REG{i - 1}: {hex(registers[i])}")

def bq27531_unseal(i2c_bus):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_SS_KEY1))
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_SS_KEY0))
    time.sleep(2)

    start_time = int(round(time.time() * 1000))
    while (int(round(time.time() * 1000)) - start_time <= 10 * 1000):
        status = bq27531_read_subcommand(bus, BQ27531_CNTL_CONTROL_STATUS);
        bq27531_print_status(status)
        if status & BQ27531_STATUS_SS == 0:
            return True

        time.sleep(2)

    return False;

def bq27531_seal(i2c_bus):
    i2c_bus.write_i2c_block_data(BQ27531_I2C_ADDRESS, BQ27531_CMD_CNTL, bq27531_prepare_subcommand_packets(BQ27531_CNTL_SEALED))
    time.sleep(2)

    start_time = int(round(time.time() * 1000))
    while (int(round(time.time() * 1000)) - start_time <= 10 * 1000):
        status = bq27531_read_subcommand(bus, BQ27531_CNTL_CONTROL_STATUS);
        bq27531_print_status(status)
        if status & BQ27531_STATUS_SS != 0:
            return True

        time.sleep(2)

    return False;

with SMBus(1) as bus:
    print("---------------------------------------------------------------------------------------------------------")    
    print("Started BQ27531 Test!")

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(GPIO_OTG_PIN, GPIO.OUT)
    GPIO.setup(GPIO_CE_PIN, GPIO.OUT)
    GPIO.setup(GPIO_PSEL_PIN, GPIO.OUT)

    GPIO.output(GPIO_OTG_PIN, GPIO.HIGH)
    GPIO.output(GPIO_CE_PIN, GPIO.LOW)
    GPIO.output(GPIO_PSEL_PIN, GPIO.LOW)

    seal_process_result = False;

    device_type             = bq27531_read_subcommand(bus, BQ27531_CNTL_DEVICE_INFO)
    firmware_version        = bq27531_read_subcommand(bus, BQ27531_CNTL_FW_VERSION)
    hardware_version        = bq27531_read_subcommand(bus, BQ27531_CNTL_HW_VERSION)
    print("--------------------")
    charger_status          = bq24196_registers(bus)
    status                  = bq27531_read_subcommand(bus, BQ27531_CNTL_CONTROL_STATUS)
    flags                   = bq27531_read_command(bus, BQ27531_CMD_FLAGS)

    print(f"Device Type: {device_type}, Firmware Version: {firmware_version}, Hardware Version: {hardware_version}")
    bq27531_print_flags(flags);
    bq27531_print_status(status)
    bq24196_print_registers(charger_status)
    print("--------------------")
    
    counter_start_otg = 0;

    while True: 
        try:
            voltage                 = bq27531_read_command(bus, BQ27531_CMD_VOLTAGE)
            prog_voltage            = bq27531_read_command(bus, BQ27531_CMD_PROG_CHARGING_VOLTAGE)
            calc_voltage            = bq27531_read_command(bus, BQ27531_CMD_CALC_CHARGING_VOLTAGE)
            prog_current            = bq27531_read_command(bus, BQ27531_CMD_PROG_CHARGING_CURRENT)
            calc_current            = bq27531_read_command(bus, BQ27531_CMD_CALC_CHARGING_CURRENT)
            temp                    = bq27531_read_command(bus, BQ27531_CMD_TEMP) / 10 - 273.1
            int_temp                = bq27531_read_command(bus, BQ27531_CMD_INTERNAL_TEMPERATURE) / 10 - 273.1
            soc                     = bq27531_read_command(bus, BQ27531_CMD_STATE_OF_CHARGE)
            charger_status          = bq24196_registers(bus)
            status                  = bq27531_read_subcommand(bus, BQ27531_CNTL_CONTROL_STATUS)
            flags                   = bq27531_read_command(bus, BQ27531_CMD_FLAGS)

            print(f"Voltage:     {voltage} mV, Calc. Voltage: {calc_voltage} mV, Prog. Voltage: {prog_voltage} mV")
            print(f"Calc. Current: {calc_current} mA, Prog. Current: {prog_current} mA")
            print(f"Temp:        {temp}")
            print(f"Int. Temp:   {int_temp}")
            print(f"SOC:         %{soc}");    
            bq27531_print_flags(flags);
            bq27531_print_status(status)
            bq24196_print_registers(charger_status)
            print("--------------------")

            counter_start_otg += 1

            if counter_start_otg >= 10:
                print("Setting OTG settings...")
                print("--------------------")
                bq27531_stop_gg_controller_charge(bus)
                bq27531_stop_charge(bus)
                bq27531_start_otg(bus)
                counter_start_otg = 0;

            """
            if status & BQ27531_STATUS_SS:
                print("Sent unseal command.")
                unseal_process_result = bq27531_unseal(bus)
                print(f"Remove Unseal Process: {unseal_process_result}")

                if unseal_process_result:
                    bq27531_print_flags(flags);
                    bq27531_print_status(status) 
            else:
                print("Sent seal command.")
                seal_process_result = bq27531_seal(bus)
                print(f"Remove Seal Process: {seal_process_result}")

                if seal_process_result:
                    bq27531_print_flags(flags);
                    bq27531_print_status(status) 
            """
            time.sleep(0.5)
        except KeyboardInterrupt:
            GPIO.cleanup()
            break
        

    print("Good bye...")

What have we tried ?

1. We sent some commands to test that we can communicate with the BQ27531-G1. Like voltage, SOC, Temperature, Internal Temperature, Device Type, Firmware Version, Hardware Version etc.. We got some informations:

  • Device Type: 1329 (Stable), 
  • Firmware Version: 258 (Unstable sometimes got 65285),
  • Hardware Version: 168 (Unstable sometimes got 65281, 65535)
  • Voltage 3993 mV (Stable), Calculated Voltage: 0 mV, Prog. Voltage: 0 mV (Stable)
  • Calc. Current: 0 mA (Stable), Prog. Current: 0 mA (Stable), Avg. Current: -593 mA (Stable)
  • Temp:        179.8 °C (Stable)
  • Int. Temp:   54.5 °C (Stable)
  • SOC:         %22 (Unstable, data value highly variable)
  • Flags Status: OT:1, UT: 0, CALMODE: 0, DIV_CUR: 0, GG_CHGRCTL_EN: 0 , FC: 0, CHG: 0, OCV_GD:1, WAIT_ID: 1, BAT_DET: 1, SOC1: 0, SYSDOWN: 0, DSG: 1
  • Control Status: FAS: 0, SS: 0, CSV: 0, CCA: 0, BCA: 0, OCVCMDCOMP:   1, OCVFAIL: 0, INITCOMP: 1, HIBERNATE: 0, SNOOZE: 0, SLEEP: 0, LDMD: 0, RUP_DIS: 1, VOK: 0, QEN: 0 (Unstable, very dynamic changes on FAS and SS bits. Sometimes FAS or SS can be 0 or 1. However, even though we have never sent a seal or unseal command)
  • BQ24196 Charger Status: REG-1: 0x80, REG0: 0x37, REG1: 0x1b, REG2: 0x60, REG3: 0x11, REG4: 0xb2, REG5: 0x9a, REG6: 0x3, REG7: 0x4b, REG8: 0x0, REG9: 0x80

2. For start charge or enable OTG, we know we have to changed Charger Configuration bits 01 for charge, 10/11 for OTG at REG01. But we couldnt changed bits. BQ27531-G1 does not allow to change Charger Configurations bits. So for try, we have send different data with different scenario for enable start charge (every scenario result is same):

  • Only send Charge Enable SubCommand (while OTG Pin = 0, CE Pin = 0, PSEL = 0)
  • Send Charge Enable and Gauge Charge Controller Enable (while OTG Pin = 0, CE Pin = 0, PSEL = 0)
  • Send Disable OTG, Charge Enable and Gauge Charge Controller Enable (OTG Pin = 0, CE Pin = 0, PSEL = 0)

or start OTG (every scenario result is same)

  • Only send OTG Enable SubCommand (while OTG Pin = 1, CE Pin = 0, PSEL = 0)
  • Send OTG Enable and Charge Disable Subcommands (while OTG Pin = 0, CE Pin = 0, PSEL = 0)
  • Send OTG Enable, Charge Disable and Gauge Charge Controller Disable Subcommands(OTG Pin = 0, CE Pin = 0, PSEL = 0)

3. As we see when we examine the Control Status information we can see that there is over temperature information. we tried to remove it, thinking it might be the cause of the problem. But this time we noticed that the SEAL and UNSEAL actions are not working properly. When we sent SS keys to open the seal we found that it didn't change anything. But sometimes we can suddenly see that the SS and FAS values are 0 or 1 at the same time.

As a result, we cannot activate OTG, we cannot start charging. We think the problem is over temperature, we think the BQ27531-G1 is not performing any operation due to over temperature but to fix it I can't seal or open the seal. We don't think there is a problem with communication, we can read the display values but we don't know what to do anymore, We've run out of ways?

  • Hi Tarik,

    It seems to be a problem with being able to read the register values reliably. The device should not switch randomly between sealed or unsealed unless a seal command has been entered previously and the device is reset (the gauge will always become sealed after a reset if a sealed command is ever issued to the device). I would recommend using an EV2400 to ensure that my suspicion is correct. I expect that when you use the EV2400, we should be able to narrow down what may be causing this inaccuracy reading the values for SEALED/UNSEALED as I expect the EV2400 to be able to read back these values reliably.

    Best Regards,

    Jackson