After many hours of trying, I still cannot change the bz34z110 flash content .
The idea was to start with something easy like changing the serial number, as one can read it back to verify that the flash has indeed changed. I reset the hardware etc, but the flash always stays the same.
(Brand new bz34z110, never programmed before, as from the factory)
Reading subclass 48 (serial number at 15 & 16)
subclass ? 48
( 48)0x30
0164 00B0 070A F6D0 0CFE 3100 0000 0100 0000 8403 A00F 401F 70FE 085A 09CA 0D92
356 176 1802 63184 3326 12544 0 256 0 33795 40975 16415 28926 2138 2506 3474
64 01 B0 00 0A 07 D0 F6 FE 0C 00 31 00 00 00 01 00 00 03 84 0F A0 1F 40 FE 70 5A 08 CA 09 92 0D Sum32=0x08FF
SUM 32 Bytes =0x08FF
bq_read_checksum =0x0D
bq_calc_checksum =0x00 read_standard=(0D) > return 0
if I add all 32 Bytes I get 0x08FF.
If I read the checksum I get 0x0d.. I can do this for subclass 64 for instance the last byte is also the checksum read
subclass ? 64
( 64)0x40
FF61 0030 0000 0006 0014 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 4C00
65377 48 0 6 20 0 0 0 0 0 0 0 0 0 0 19456
61 FF 30 00 00 00 06 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4C Sum32=0x01F6
SUM 32 Bytes =0x01F6
bq_read_checksum =0x4C
bq_calc_checksum =0x09 read_standard=(4C) > return 0
subclass ? 104
(104)0x68
2071 945C 9808 FAC0 007B 0000 4E00 0020 0000 0000 0000 0000 0000 0000 0000 BC00
8305 37980 38920 64192 123 0 19968 32 0 0 0 0 0 0 0 48128
71 20 5C 94 08 98 C0 FA 7B 00 00 00 00 4E 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 BC Sum32=0x0580
SUM 32 Bytes =0x0580
bq_read_checksum =0xBC
bq_calc_checksum =0x7F read_standard=(BC) > return 0
My checksum function
UINT_8 bq_read_checksum (void){
//calc checksum
UINT_8 address = BQ34Z100_ADDRESS; // 0xAA
UINT_8 read_data [1];
// write checksum to the special block checksum address
read_data[0] = BQ_BLOCK_DATA_CHECKSUM; // 0x60
// send the register to the device
if (i2cwrite(address , read_data, 1, 1) == 1 ) { // no stop
if (i2cread(address , read_data, 1, 0) == 1) // stop
return read_data[0];
else
gprintf (TTL,"Err: bq_read_checksum::Read ? \n");
} else
gprintf (TTL,"Err:bq_read_checksum::Write ? \n");
return 0;
}
I calculate the checksum as follows
UINT_8 bq_calc_checksum (const bool update_flash){
//calc checksum
int i, chkSum = 0, chkSumTemp;
UINT_8 address = BQ34Z100_ADDRESS; // AA
UINT_8 write_data [2];
UINT_8 status;
// add all up
for (i = 0; i < 31; i++){
chkSum += flash_data[i];
}
chkSumTemp = chkSum / 256;
chkSum = chkSum - (chkSumTemp * 256);
chkSum = 255 - chkSum;
chkSumTemp = 0;
// add all up
for (i = 0; i < 32; i++){
chkSumTemp += flash_data[i];
}
gprintf (TTL, "Sum32=0x%04X\n", chkSumTemp);
if (update_flash == true){
//write checksum to the special block checksum address
write_data[0] = BQ_BLOCK_DATA_CHECKSUM; // 0x60
write_data[1] = (chkSum & 0x00FF);
// send the register and checksum to the device
status = i2cwrite(address , write_data, 2, 0); // issue a stop
if (status == 2 ){
return true;
}
else {
gprintf (TTL,
"ERR: could not write checksum 0x%02X Ret(%d)\n",
write_data[1], status);
return false;
}
} else{
return chkSum;
}
}
But I could not get this to change my serial number, note I have a global array (flash_data) that holds the 32 flash data bytes
New serial number always fails at bq_calc_checksum(true), or the value in flash stay unchanged, however I can use my read_standard to read the voltage currents etc, so I think I read the default serial number as one.
bool new_serial_number (const UINT_16 value)
{
UINT_8 serialH, serialL;
UINT_8 subclass = 48;
UINT_8 * ptr = NULL;
serialH = msb(value);
serialL = lsb(value);
if (readFlash(subclass, false, false, 0, ptr))
{
// Note :: The endian is different, the default serial number is at the wrong index
if (changeFlash(15,serialL,1))
{
//gprintf (TTL,"OK :changeFlash serialH\n");
if (changeFlash(16,serialH,1))
{
//gprintf (TTL,"OK :changeFlash serialL\n");
dump_flash ();
if (bq_calc_checksum(true))
{
gprintf (TTL,"OK :bq_calc_checksum 4\n");
wait_ms(200);
if (readFlash(subclass, false, false, 0, ptr))
{
gprintf (TTL, "OK :new_serial_number: Wr 0x%04X \n", value);
dump_flash ();
return true;
} else
gprintf (TTL,"ERR:new_serial_number 5\n");
} else
gprintf (TTL,"ERR:new_serial_number 4\n");
} else
gprintf (TTL,"ERR:new_serial_number 3\n");
} else
gprintf (TTL,"ERR:new_serial_number 2\n");
} else
gprintf (TTL, "ERR:new_serial_number 1\n");
return false;
}
My read flash is as follows
bool readFlash (const UINT_8 sub_class,
const bool dump,
const bool remote_control,
const UINT_32 index,
UINT_8 * answer
)
{
static UINT_8 read_data [2] = {0};
UINT_8 write_data [2], i;
UINT_8 address = BQ34Z100_ADDRESS;
// default answer
answer = NULL;
// enable flash transfer
write_data[0] = BQ_BLOCK_DATA_CONTROL ; // 0x61;
write_data[1] = 0x00; // transfer code = 0
// send the register to be read write
if (i2cwrite(address , write_data, 2, 0) == 2 ) // stop
{
// specify sub class
write_data[0] = 0x3e;
write_data[1] = sub_class;// & 0x7f;
// send the register to be read write
if (i2cwrite(address , write_data, 2, 0) == 2 ) // stop
{
// enable general purpose block
if (index < 32)
{
write_data[0] = 0x3f;
write_data[1] = 0;
} else
{
write_data[0] = 0x3f;
write_data[1] = index % 32; // modulo index 48 => 48 mod 32 = 16 (0x10)
}
// send the register to be read write
if (i2cwrite(address , write_data, 2, 0) == 2 ) // stop
{
write_data[0] = BQ_BLOCK_DATA; // 0x40
write_data[1] = 0;
// send the register to be read write
if (i2cwrite(address , write_data, 1, 0) == 1 ) // no stop
{
for (i = 0; i < 32; i++)
{
if (i2cread (address, read_data, 1, 0) == 1) // stop
{
// global
flash_data[i] = read_data[0];
}
else
{
gprintf (1,"4.Error reading flash [%d] \n", sub_class );
return false;
}
}
}
// save the global on success, only used when we dump the flash
last_read_subclass = sub_class;
} else
{
gprintf (1,"3.Error reading flash [%d] \n", sub_class );
return false;
}
}
else
{
gprintf (1,"2.Error reading flash [%d] \n", sub_class );
return false;
}
} else
{
gprintf (1,"1.Error reading flash [%d] \n", sub_class );
return false;
}
//SLUA66
//Going to Production With the bq34z1xx
//PRODUCTION STEP 3: Update any Individual Flash Locations, such as Serial Number,Lot Code, and Date.Other than
//the Voltage Divider value, there will usually be some data that is unique to each battery pack, or group
//of packs such as serial number, date of manufacture, etc. This data can be written using the technique below in
//Figure 8.
Function UpdateSerialNumber (iSerialNum As Integer) As Long
Dim lError As Long
Dim iSubClass As Integer
Dim iTransferCode As Integer
Dim yRo wData(32) As Byte
Dim iChecksum As Integer
Dim iTmp As Integer
Dim i As Integer
iSubClass = 48 '// subclass for configuration data
iTransferCode = 0
'//ENABLE FLASH TRANSFER
lError = WriteI2CByte(&H61, iTransferCode, &HAA)
'//SPECIFY SUBCLASS
lError = WriteI2CByte(&H3E, iSubClass, &HAA)
'//ENABLE GENERAL PURPOSE BLOCK
lError = WriteI2CByte(&H3F, iTransferCode, &HAA)
'//
READ 32 BYTE BLOCK
lError = ReadI2CByteArray(&H40, yRowData, 32, &HAA)
'// REPLACE SERIAL NUMBER RAM. ROW OFFSETS ARE FOUND IN THE DATASHEET
yRowData(15) = (iSerialNum\256) '//MSByte
yRowData(16) = iSerialNum -(yRowData(0) * 256) '//LSByte
'//CALCULATE THE CHECKSUM BYTE AND INVERT IT
For i = 0 To 31
iChecksum = iChecksum + yRowData(i)
Next i
iTmp = iChecksum\256 '//Integer divide
iChecksum = iChecksum -(iTmp * 256)
iChecksum = 255 - iChecksum
'// MOVE THE SERIAL NUMBER INTO THE FUEL GAUGE BUFFER
lError = WriteI2CByte(&H40 + 15, CInt(yRowData(15)), &HAA)
lError = WriteI2CByte(&H40 + 16, CInt(yRowData(16)), &HAA)
'// TRANSFER TO FLASH USING THE CHECKSUM
lError = WriteI2CByte(&H60, iChecksum, &HAA)
DoDelay 0.2 '// Wait 0.2 second
En Function