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.