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: Writing new Capacity Value DIfficulties

Part Number: BQ27441-G1

Tool/software:

Hello,

We are developing a portable product and plan on using the BQ27441 as a fuel gauge for the battery health.

We do not have a EV2300/2400 and are prototyping the system with a Raspberry PI since it's easy to communicate over i2c with it. I am using the SMBUS to send signals.

I can read Voltage, Temperature, and current draw and it is accurate, and changes based on the environment.

I believe I am following the TRM correct about updating the new capacity. I have the prototype code below incase anyone needs a quick start reference for the code, as well as make it easier for someone who knows more then me to offer any input. Any input and feedback is greatly appreciated. Thanks so much.

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)