One of the reasons I wanted to reverse engineer rather than replace the microcontroller on the module BMS board is that Tesla have carefully selected voltage levels for under/over voltage thresholds and balancing levels. So it's a bit of a bummer to find that the modules themselves don't seem to have these values built in, it's handled higher up the control chain.
But the BQ76 does have a hardware over and under voltage threshold, as well as over temperature built in, which pulls a shared fault line low.
There are also some other configuration values worth reading out, and since I do have a bunch of boards which have had power applied since the last time they were used, since they have this huge battery backup - the hundreds of 18650 cells - to keep the RAM powered!
So how do we read it out? need to find the address first, using my python script we can iterate through the possible addresses with something like
for address in range(0x3E):
sendData(Read,[address, 0x00, 0x4C])
And eventually, at address=0x0F I get the result:
TX: 0x1e, 0x0, 0x4c,
RX: 0x1e, 0x00, 0x4c, 0x81, 0x2a, 0x25, 0x25, 0xa5, 0x25, 0xab, 0x25, 0xae, 0x25, 0xad, 0x25, 0xac, 0x25, 0xaa, 0x0a, 0x99, 0x0a, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x31, 0x81, 0x08, 0x81, 0x66, 0xff, 0x15, 0x00, 0x00, 0x00, 0xad,
Labeling each register:
0: 81 #status register 1: 2a 25 #GPAI measurement data 3: 25 a5 #cell 1 voltage data 5: 25 ab #cell 2 voltage data 7: 25 ae #cell 3 voltage data 9 25 ad #cell 4 voltage data b: 25 ac #cell 5 voltage data d: 25 aa #cell 6 voltage data f: a 99 #TS1 voltage data 11: a 93 #TS2 voltage data 13-1f rsvd 20: 0 #alert status 21: 0 #fault status 22: 0 #OV fault state 23: 0 #UV fault state 24: 0 #parity result A 25: 0 #parity result B 26-2f rsvd 30: 3d #ADC measurement control 31: 3 #I/O pin control 32: 0 #cell balancing control 33: 0 #cell balancing max on time 34: 0 #ADC conversion start 35-39: rsvd 3a: 0 #group 3 registers write access control 3b: 8f #Address register 3c: 0 #reset control 3d: 0 #test mode selection 3e: rsvd 3f: 0 #EPROM programming enable 40: 10 #Function configuration 41: 80 #IO configuration 42: 31 #OV setpoint 43: 81 #OV time delay 44: 8 #UV setpoint 45: 81 #UV time delay 46: 66 #over temperature set point 47: ff #over temperature time delay 48: 15 #user data 1 49: 0 #user data 2 4a: 0 #user data 3 4b: 0 #user data 4
So the values after 0x3F are identical to those read from the EPROM on a restart, they set to OV/UV/OT and time delays.
OV setpoint = 0x31, datasheet says 2V + 50mV * 49 = 4.45V
UV setpoint = 0x08. datasheet says 0.7V + 100mV * 8 = 1.50V
OT setpoint = 0x66. Table 2 says this corresponds to 1.578V, which is 65C for a 10k NTC such as ERT-J1VG103FA
Interesting values, the cells will basically be on fire if they reach these voltages.. The temperature value is much more reasonable.
Since we can't guarantee the register content, best practice is to just reset the BQ76 chips with a broadcast reset, then set it up from scratch. EPROM values will be loaded automatically but there are a few registers that require setup after a reset, Address control, ADC control, IO control and the fault and alert registers.
### ~~ Startup Code ~~ ###
#A5 is the magic value to reset the chips
sendData( Write, [broadcast, RESET_CONTROL, 0xA5])
#set address
sendData( Write, [0x00, ADDRESS_CONTROL, address|0x80]) #do this for each BMS on the daisychain
#configure ADC
sendData( Write, [address, ADC_CONTROL, 0x3D])
#configure IO
sendData( Write, [address, IO_CONRTOL, 0x03])
#clear faults, need to write a 1 to the fault bit to be cleared, then a zero
sendData( Write, [address, ALERT_STATUS, 0x80])
sendData( Write, [address, ALERT_STATUS, 0x00])
sendData( Write, [address, FAULT_STATUS, 0x08])
sendData( Write, [address, FAULT_STATUS, 0x00])
I've put a new version of the python script in the files section which also reads out and converts the ADC values to voltages.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
Excellent progress--thanks for the update report.
Was this the same board that you were testing previously, or was this a different board--possibly from BMB15 on the daisy-chain? i found serial number data embedded in the flash code, still looking for where the device ID is stored.
The bq76 has the capability to use shadow data to override the stored eprom values--look at sending the access code to the shadow_control register 3A. That way you can adjust the OV, UV, OT values to more useful values that might actually protect the cells.
cheers,
Are you sure? yes | no
This board has BMB-16 printed on it's J1 connector, the last board from which I read the firmware had BMB-11 on the sticker. The number appears to correspond to the stored device address. Not that it really matters as you can easily reset and reassign the addresses.
The 'shadow data' is the EPROM data, which yes is programmable although it requires a 7V programming voltage. But the values in there kinda make sense:
The secondary protector (UV/OV/OT fault line) as the name implies, is secondary. Primary protection is done by reading out values and processing them in an external microcontroller. It therefore makes sense for the secondary protector values to have wider margins than you would expect for proper a BMS. Under normal use it should never trigger a fault
Are you sure? yes | no