SLUAA11B February 2020 – August 2021 BQ769142 , BQ76922 , BQ76942 , BQ76952
The following example code is written in Python and designed to communicate to the BQ769x2 device from a PC through an EV2400 module or through the USB connector on the BQ76942 or BQ76952 Evaluation Module. The code shows the creation of simple I2C Read and Write functions, a DataRAM_Read function, (which can also be used to execute subcommands since these follow the same format), and a DataRAM_Write function that shows the calculation of checksum and length. The main section of the code goes through all of the examples covered in the first three sections of this document.
This simple code example is intended to illustrate the basic command structure for I2C commands. Microcontroller code examples are also available for I2C and SPI. The link to the microcontroller code is provided in Section 7.
'''
/* BQ769x2 example Program demonstrates examples for direct commands, subcommands, and writing / reading from device RAM.
'''
import pywinusb
import bqcomm
import sys
import time
from time import sleep
import sets
I2C_ADDR = 0x10 # BQ769x2 slave address
numCells = 10 # Set to 10 for BQ76942
####################################################
## Check to see if EV2400 is connected
####################################################
try:
a = bqcomm.Adapter() # This will use the first found Aardvark or EV2400
except:
print "No EV2400 Available"
sys.exit(1)
######################################################
## Define some command functions
######################################################
def I2C_Read(device_addr, reg_addr, length):
'''
Uses global I2C address and returns value read
'''
try:
value = a.i2c_read_block(device_addr, reg_addr, length)
except:
print "Nack received"
return
return value
def I2C_Write(device_addr, reg_addr, block):
'''
Uses global I2C address
'''
try:
a.i2c_write_block(device_addr, reg_addr, block)
except:
print "Nack received"
return
def DataRAM_Read(addr, length):
'''
Write address location to 0x3E and read back from 0x40
Used to read configuration registers and for subcommands
'''
addressBlock = [(addr%256), (addr/256)]
I2C_Write(I2C_ADDR, 0x3E, addressBlock)
value = I2C_Read(I2C_ADDR, 0x40,length)
return value
def DataRAM_Write(addr, block):
'''
Write address location to 0x3E and Checksum,length to 0x60
Used to write configuration registers
'''
addressBlock = [(addr%256), (addr/256)]
wholeBlock = addressBlock + block
I2C_Write(I2C_ADDR, 0x3E, wholeBlock) # Write Data Block
# Write Data Checksum and length to 0x60, required for RAM writes
I2C_Write(I2C_ADDR, 0x60, [~sum(wholeBlock) & 0xff, len(wholeBlock)+2])
return
def crc8(b,key):
crc = 0
ptr = 0
for j in range(len(b),0,-1):
for k in range(8):
i = 128 / (2**k)
if ((crc & 0x80) != 0):
crc = crc * 2
crc = crc ^ key
else:
crc = crc * 2
if ((b[ptr] & i) != 0):
crc = crc ^ key
ptr = ptr + 1
return crc
##########################################
# Start of Main Script
##########################################
################ Direct Command Examples ################
#Write Alarm Enable to 0xF082
I2C_Write(I2C_ADDR, 0x66, [0x82, 0xF0])
#Read Voltage on Cell #1
result = I2C_Read(I2C_ADDR, 0x14, 2)
print "Cell 1 = ", (result[1]*256 + result[0]), " mV"
#Read Internal Temperature
result = I2C_Read(I2C_ADDR, 0x68, 2)
print "Internal Temp = ", ((result[1]*256 + result[0])/10 - 273.15), "degrees C"
#Read CC2 Current Measurement
result = I2C_Read(I2C_ADDR, 0x3A, 2)
print "CC2 = ", (result[1]*256 + result[0]), " mA"
################ Subcommand Examples ################
#Read Device Number
b = DataRAM_Read(0x0001,6)
print "Device_Number = " '{0:04X}'.format(b[1]*256+b[0])
#Read Manufacturing Status
b = DataRAM_Read(0x0057,2)
print "Manufacturing Status = " '{0:04X}'.format(b[0]+256*b[1])
## Command-only Subcomands ##
#FET_ENABLE
I2C_Write(I2C_ADDR, 0x3E, [0x22, 0x00])
#RESET - returns device to default settings
I2C_Write(I2C_ADDR, 0x3E, [0x12, 0x00])
sleep(1)
############ Reading and Writing to RAM Registers ##########
# Read 'Enabled Protections A' RAM register 0x9261
b = DataRAM_Read(0x9261,1)
print "Enabled Protections A = 0x" '{0:02X}'.format(b[0])
#Set CONFIG_UPDATE Mode (RAM registers should be written while in
#CONFIG_UPDATE mode and will take effect after exiting CONFIG_UPDATE mode
I2C_Write(I2C_ADDR, 0x3E, [0x90, 0x00])
#Write to 'Enabled Protections A' RAM register to enable CUV protection
DataRAM_Write(0x9261, [0x8C])
#Write to 'VCell Mode' RAM register to configure for a 9-cell battery
DataRAM_Write(0x9304, [0x03, 0x7f])
#Exit CONFIG_UPDATE Mode
I2C_Write(I2C_ADDR, 0x3E, [0x92, 0x00])
# CRC8 Example Calculation
TestValue = [0x10, 0x14, 0x11, 0x68]
crcKey = 0x107
check = 0xff & crc8(TestValue,crcKey)
print "crc8 check = 0x" '{0:02X}'.format(check)
The output from running the example Python script on a BQ76942 Evaluation Module follows.
Cell 1 = 3700 mV
Internal Temp = 25.05 degrees C
CC2 = 7 mA
Device_Number = 7694
Manufacturing Status = 0040
Enabled Protections A = 0x88
crc8 check = 0x33