主题中讨论的其他器件:BQ24196、 EV2400
我们有一个嵌入式 Linux 设计项目、该项目使用 BQ27531-G1电量监测计来控制 BQ24196、监控电压、SOC、电流并启用 USB OTG。
在之前的版本中、我们仅使用 BQ24196、但随着时间的推移、我们意识到无法保存寄存器值并监控某些值(SOC、电压等)。 因此、我们认为我们应该切换到 BQ27531-G1 IC。
我们有哪些材料?
我们不使用评估板。 我们与嵌入式 Linux 通信。 这是我们使用的原理图:

对于通信、我们使用的是 python3 smbus2、代码位于以下位置。
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...")
我们尝试了什么?
我们发送了一些命令来测试我们是否可以与 BQ27531-G1通信。 例如电压、SOC、温度、内部温度、器件类型、 固件版本、硬件版本等。 我们得到了一些信息:
- 器件类型:1329 (稳定)、
- 固件版本:258 (不稳定有时得到65285)、
- 硬件版本:168 (不稳定有时得到65281、65535)
- 电压3993mV (稳定)、计算得出的电压:0mV、可编程 电压:0mV (稳定)
- 计算 电流:0mA (稳定)、可编程 电流:0mA (稳定)、平均 电流:-593mA (稳定)
- 温度: 179.8°C (稳定)
- 内部 温度: 54.5°C (稳定)
- SoC: %22 (不稳定、数据值高度可变)
- 标志状态: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
- 控制状态:FAS:0、SS:0、CSV:0、CCA:0、BCA:0、 OCVCMDCOMP: 1、OCVFAIL:0、INITCOMP:1、休眠:0、贪睡:0、 睡眠:0、LDMD:0、RUP_DIS:1、VOK:0、QEN:0 (不稳定、 FAS 和 SS 位发生非常动态的变化。 有时 FAS 或 SS 可以为0或1。 但是、即使我们从未发送过密封或解封命令)
- BQ24196充电器状态:REG-1:0x80、REG0:0x37、REG1:0x1b、REG2:0x60、REG3:0x11、 REG4:0xb2、REG5:0x9a、REG6:0x3、REG7:0x4b、REG8:0x0、 REG9:0x80
2.对于开始充电或启用 OTG、我们知道必须在 REG01处更改充电器配置位01以进行充电、更改10/11以用于 OTG。 但我们无法更改位。 BQ27531-G1不允许更改充电器配置位。 因此、为了进行尝试、我们发送了不同的数据、其中有不同的启用启动充电方案(每个方案的结果都相同):
- 仅发送充电使能子命令(当 OTG 引脚= 0、CE 引脚= 0、PSEL = 0时)
- 发送充电使能和电量监测计充电控制器使能(当 OTG 引脚= 0、CE 引脚= 0、PSEL = 0时)
- 发送禁用 OTG、充电使能和电量监测计充电控制器使能(OTG 引脚= 0、CE 引脚= 0、PSEL = 0)
或启动 OTG (每个方案的结果都相同)
- 仅发送 OTG 使能子命令(当 OTG 引脚= 1、CE 引脚= 0、PSEL = 0时)
- 发送 OTG 启用和充电禁用子命令(当 OTG 引脚= 0、CE 引脚= 0、PSEL = 0时)
- 发送 OTG 启用、充电禁用和电量监测计充电控制器禁用子命令(OTG 引脚= 0、CE 引脚= 0、PSEL = 0)
正如我们在检查控制状态信息时看到的、我们可以看到存在过热信息。 我们试图将其删除、认为它可能是问题的原因。 但这次我们注意到密封和拆封操作不能正常工作。 当我们发送 SS 密钥打开密封时、我们发现它没有改变任何东西。 但有时我们会突然看到 SS 和 FAS 值同时为0或1。
因此、我们无法激活 OTG、也无法开始充电。 我们认为问题是过热、我们认为 BQ27531-G1由于过热而未执行任何操作、但为了解决此问题、我无法密封或打开密封件。 我们认为沟通没有问题、我们可以读取显示值、但我们不知道该怎么办、我们已经走了很多路?