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)