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?