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.

[参考译文] BQ27441-G1:电池电量管理 IC 设置容量

Guru**** 2493545 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/power-management-group/power-management/f/power-management-forum/1487756/bq27441-g1-battery-fuel-management-ic-set-capacity

器件型号:BQ27441-G1

工具与软件:

您好!

我一直在使用 BQ27441来开发嵌入式项目。 我已经把它做得很好的工作,但我不会写新的能力。 我已经测试过芯片、读取的电压、温度、电流都正确、这是预期结果。 我在 Python 中编写此代码、但当我读取容量时、它仍读取为默认值。  

当我设置电池容量时、我执行以下操作:

解封

进入扩展模式  

写入寄存器以获取电池容量

退出扩展模式

密封  

这不会产生任何错误、器件可以工作并向我提供读数、但容量尚未更新。 我随附了此示例的完整代码、以防将来有人在 Raspberry PI 或其他 Linux 发行版的入门方面需要任何帮助。

import smbus2
import time

# I2C address of BQ27441
BQ27441_I2C_ADDR = 0x55  

# Register addresses
CONTROL_REG = 0x00       # Control register
EXTENDED_DATA_CTRL = 0x3E  # Extended Data Control register
DESIGN_CAP_REG = 0x4B    # Design Capacity register
EXIT_CFGUPDATE_REG = 0x44  # Exit Config Mode
SOC_REG = 0x1C           # State of Charge register
VOLTAGE_REG = 0x04       # Battery Voltage register
CURRENT_REG = 0x10       # Average Current register
TEMP_REG = 0x02          # Battery Temperature register
REMAINING_CAP_REG = 0x0A  # Remaining Capacity register
SOH_Reg = 0x20 #State of health 

# Control Subcommands
UNSEAL_KEY_1 = 0x8000
SEAL_COMMAND = 0x0020
ENTER_CFGUPDATE = 0x0013

# Battery capacity to set (mAh)
BATTERY_CAPACITY = 4500  

# Initialize I2C bus
bus = smbus2.SMBus(1)

def write_register(reg, value):
    """Writes a 16-bit value to the specified BQ27441 register."""
    data = [value & 0xFF, (value >> 8) & 0xFF]  # Low byte first
    bus.write_i2c_block_data(BQ27441_I2C_ADDR, reg, data)

def read_register(reg):
    """Reads a 16-bit value from the specified BQ27441 register."""
    data = bus.read_i2c_block_data(BQ27441_I2C_ADDR, reg, 2)
    return data[0] | (data[1] << 8)

def unseal_battery():
    """Unseals the BQ27441 to allow writing to protected registers."""
    write_register(CONTROL_REG, UNSEAL_KEY_1)
    time.sleep(0.1)

def seal_battery():
    """Seals the BQ27441 to protect configuration settings."""
    write_register(CONTROL_REG, SEAL_COMMAND)
    time.sleep(0.1)

def enter_extended_mode():
    """Enables Extended Mode for configuration changes."""
    write_register(CONTROL_REG, ENTER_CFGUPDATE)  # Enter Config Mode
    time.sleep(0.1)

def exit_extended_mode():
    """Exits Extended Mode and applies changes."""
    write_register(EXIT_CFGUPDATE_REG, 0x00)  # Exit Extended Mode
    time.sleep(0.1)

def set_battery_capacity(capacity):
    """Sets the battery capacity in Extended Mode."""
    unseal_battery()  # Unseal before modifying protected settings
    enter_extended_mode()
    
    # Access Design Capacity Block
    write_register(EXTENDED_DATA_CTRL, 0x13)
    time.sleep(0.1)

    # Write new battery capacity
    write_register(DESIGN_CAP_REG, capacity)
    time.sleep(0.1)

    exit_extended_mode()
    seal_battery()  # Reseal after configuration
    return read_register(DESIGN_CAP_REG) == capacity

def get_battery_percentage():
    """Reads the battery's state of charge (SOC) in percentage."""
    return read_register(SOC_REG)

def get_battery_voltage():
    """Reads the battery voltage in millivolts (mV)."""
    return read_register(VOLTAGE_REG)

def get_current_draw():
    """Reads the battery current draw in mA (negative = discharge, positive = charge)."""
    raw_current = read_register(CURRENT_REG)
    if raw_current > 32767:  # Convert two's complement for negative values
        raw_current -= 65536
    return raw_current

def get_battery_temperature():
    """Reads the battery temperature in Celsius."""
    raw_temp = read_register(TEMP_REG)  # Temperature in 0.1 Kelvin
    temp_celsius = (raw_temp / 10.0) - 273.15  # Convert to Celsius
    return round(temp_celsius, 2)

def get_remaining_capacity():
    """Reads the remaining battery capacity in mAh."""
    return read_register(REMAINING_CAP_REG)

def get_state_of_health():
    """Reads state of battery"""
    soh_data = read_register(SOH_Reg)
    return soh_data & 0xFF

# Main execution
if __name__ == "__main__":
    print("Initializing BQ27441...")

    if set_battery_capacity(BATTERY_CAPACITY):
        print(f"Battery capacity set to {BATTERY_CAPACITY} mAh")
    else:
        print("Failed to set battery capacity!")

    while True:
        battery_percentage = get_battery_percentage()
        battery_voltage = get_battery_voltage()
        current_draw = get_current_draw()
        battery_temperature = get_battery_temperature()
        remaining_capacity = get_remaining_capacity()
        state_of_health = get_state_of_health()

        print(f"Battery Percentage: {battery_percentage}%")
        print(f"Battery Voltage: {battery_voltage} mV")
        print(f"Current Draw: {current_draw} mA")
        print(f"Battery Temperature: {battery_temperature}°C")
        print(f"Remaining Capacity: {remaining_capacity} mAh")
        print(f"State of Health: {state_of_health}")
        print("-" * 40)

        time.sleep(2)  # Delay before next reading

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    当您说到扩展模式时、您是指配置更新模式吗?

    此致、

    Adrian

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Adrian、您好 、感谢您观看我的问题。  要回答您的问题、请是、它会进入配置更新模式下的器件以发送新数据。 我查看了 TRM 并更新了代码、但我仍然无法更新容量。 如果查看 Update Capacity I、Write the unseal 命令两次、输入 ConfigUpdate、等待直到 Flags 寄存器中的位4设置、启用块 RAM 更新、更新 Capacity 寄存器、校验和更新、我检查校验和、然后执行软复位、但当我查看剩余容量时、我仍然看到1232 (mAh)、表示初始值仍然设置。  

     

    import time
    from smbus2 import SMBus
    
    # Define I2C address and registers
    BQ27441_I2C_ADDR = 0x55  # Default I2C address
    CONTROL_REG = 0x00
    FLAGS_REG = 0x06
    BLOCK_DATA_CONTROL = 0x61
    DATA_BLOCK_CLASS = 0x3E
    DATA_BLOCK_OFFSET = 0x3F
    CHECKSUM_REG = 0x60
    SOFT_RESET = 0x0042
    
    # Battery information registers
    DESIGN_CAPACITY_REG = 0x4A  # Accessed via RAM update (Subclass 82)
    REMAINING_CAPACITY_REG = 0x0A
    STATE_OF_CHARGE_REG = 0x1C
    VOLTAGE_REG = 0x04
    TEMPERATURE_REG = 0x02  # Needs conversion to Celsius
    
    # Unseal and sealing keys
    UNSEAL_KEY = [0x80, 0x00, 0x80, 0x00]
    SEAL_KEY = [0x20, 0x00]
    
    # Subclass ID for Design Capacity
    DESIGN_CAPACITY_CLASS = 0x52  # Subclass 82
    
    # I2C bus number (modify as needed)
    I2C_BUS = 1
    
    def write_word(bus, reg, value):
        """Write a word (2 bytes) to a register."""
        bus.write_word_data(BQ27441_I2C_ADDR, reg, value)
    
    def write_bytes(bus, reg, values):
        """Write multiple bytes to a register."""
        bus.write_i2c_block_data(BQ27441_I2C_ADDR, reg, values)
    
    def read_word(bus, reg):
        """Read a word (2 bytes) from a register."""
        return bus.read_word_data(BQ27441_I2C_ADDR, reg)
    
    def read_bytes(bus, reg, length):
        """Read multiple bytes from a register."""
        return bus.read_i2c_block_data(BQ27441_I2C_ADDR, reg, length)
    
    def calculate_checksum(data):
        """Calculate checksum according to BQ27441 TRM."""
        checksum = 255 - (sum(data) % 256)
        return checksum & 0xFF
    
    def read_battery_info():
        """Read and print battery parameters."""
        with SMBus(I2C_BUS) as bus:
            capacity = read_word(bus, DESIGN_CAPACITY_REG)
            remaining_capacity = read_word(bus, REMAINING_CAPACITY_REG)
            soc = read_word(bus, STATE_OF_CHARGE_REG) & 0xFF  # SOC is a percentage
            voltage = read_word(bus, VOLTAGE_REG)
            temperature = read_word(bus, TEMPERATURE_REG)  # Needs conversion
    
            # Convert temperature (reported in 0.1 Kelvin) to Celsius
            temperature_c = (temperature * 0.1) - 273.15
    
            print("\nBattery Information:")
            print(f"- Design Capacity: {capacity} mAh")
            print(f"- Remaining Capacity: {remaining_capacity} mAh")
            print(f"- Battery Percentage: {soc}%")
            print(f"- Voltage: {voltage} mV")
            print(f"- Temperature: {temperature_c:.2f} °C\n")
    
    def update_capacity(new_capacity):
        """Update the fuel gauge capacity and read battery info."""
        with SMBus(I2C_BUS) as bus:
            print("Unsealing device...")
            write_bytes(bus, CONTROL_REG, UNSEAL_KEY[:2])
            time.sleep(0.5)
            write_bytes(bus, CONTROL_REG, UNSEAL_KEY[2:])
            time.sleep(0.5)
    
            print("Entering config update mode...")
            write_bytes(bus, CONTROL_REG, [0x13, 0x00])
            time.sleep(0.5)
    
            # Wait until bit 4 is set in FLAGS_REG
            while not (read_word(bus, FLAGS_REG) & 0x0010):
                time.sleep(0.5)
    
            print("Enabling block RAM update...")
            write_bytes(bus, BLOCK_DATA_CONTROL, [0x00])
    
            print("Selecting Design Capacity subclass...")
            write_bytes(bus, DATA_BLOCK_CLASS, [DESIGN_CAPACITY_CLASS])
    
            print("Selecting first 32-byte block...")
            write_bytes(bus, DATA_BLOCK_OFFSET, [0x00])
    
            print("Reading initial checksum...")
            old_checksum = read_bytes(bus, CHECKSUM_REG, 1)[0]
    
            print("Reading current settings...")
            block_data = read_bytes(bus, 0x40, 32)
    
            # Update design capacity (assume it's stored at offset 10-11)
            block_data[10] = new_capacity & 0xFF
            block_data[11] = (new_capacity >> 8) & 0xFF
    
            print("Writing new values...")
            for i in range(len(block_data)):
                write_bytes(bus, 0x4C + i, [block_data[i]])
                time.sleep(0.01)  # Small delay for stability
    
            print("Calculating new checksum...")
            new_checksum = calculate_checksum(block_data)
            write_bytes(bus, CHECKSUM_REG, [new_checksum])
    
            time.sleep(2)  # Wait 2s
    
            print("Verifying new checksum...")
            updated_checksum = read_bytes(bus, CHECKSUM_REG, 1)[0]
            print("Updated Checksum  "+str(updated_checksum))
            print("New Checksum " + str(new_checksum))
            if new_checksum == updated_checksum:
                print("Checksum matches. Applying soft reset...")
                write_bytes(bus, CONTROL_REG, [SOFT_RESET & 0xFF, (SOFT_RESET >> 8) & 0xFF])
            else:
                print("Checksum mismatch! Update failed.")
                return
    
            time.sleep(0.5)
    
            print("Sealing the device...")
            write_bytes(bus, CONTROL_REG, SEAL_KEY)
    
            print("Update complete!")
    
        # After updating, print battery information
        read_battery_info()
    
    # Example usage: Set new capacity to 3000mAh
    update_capacity(3000)