This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

BQ34Z100-G1: configuration issues + lack of understanding regarding some parameters

Part Number: BQ34Z100-G1
Other Parts Discussed in Thread: EV2400, BQSTUDIO, BQ34Z100

Hello,

we are using BQ34Z100-G1 as the gauging solution for the lead acid batteries in our robots. The lead acid batteries (each 12V 17Ah) are connected in series. Following are the configuration parameters we use

no of Cells =12 //(each battery 6 cells)

nominal Cell Voltage = 2100 mV

design Capacity = 17000 mAh

design Energy = nominal Cell Voltage * design Capacity = 35700 mWh

charge cutoff Voltage = 2160 mV

ok Cell Volt = 1000 mV

T1-T2 = 2000 mV

T2-T3 = 2330 mV

T3-T4 = 2110 mV

CCGain = 5 (5 milliOhm resistor)

CCDelta = 5 (5 milliOhm sense resistor)

chemID = 808

We do not have access to bqstudio or EV2400, hence most of our configurations have been a process of trial and error. The test value for voltage divider is 26080 which reports a good enough voltage estimate.

However the current estimates are always very bad and vary alot.

This is the code for calibrating the sense resistor. All the values listed above are updated to the gauge before performing this step. 

void BQ34Z100::calibrateSenseR(float currentApplied)
  {
    if(currentApplied > -200.0f && currentApplied < 200.0f)
      return;
 
    auto currentMeasured = getCurrent();
    /*if(currentMeasured < 0)
      currentMeasured -= currentMeasured;*/
    if(currentMeasured == 0)
      currentMeasured = 20;
    hw::Timer.udelay(190);
    
    readDataFlashBlock(0x68,0x00,16); //read calibration subclass 104


    //The data gets stored in local buffer flashData according to the index
    uint32_t oldCurrentGain = ((uint32_t)flashData[0]) << 24 | (uint32_t)(flashData[1]) << 16 | (uint32_t)(flashData[2]) << 8 | (uint32_t)(flashData[3]);
    float currentGainR = 4.768f/xemicsToFloat(oldCurrentGain);
    
    float newCurrentGain = (static_cast<float>(currentMeasured)/currentApplied) * currentGainR;
    
    uint32_t xemicCCGain = floatToXemics(4.768/newCurrentGain);
    uint32_t xemicCCDelta = floatToXemics(5677445/newCurrentGain);
    flashData[0] = static_cast<uint8_t>(xemicCCGain >> 24);
    flashData[1] = static_cast<uint8_t>(xemicCCGain >> 16);
    flashData[2] = static_cast<uint8_t>(xemicCCGain >> 8);
    flashData[3] = static_cast<uint8_t>(xemicCCGain);
    flashData[4] = static_cast<uint8_t>(xemicCCDelta >> 24);
    flashData[5] = static_cast<uint8_t>(xemicCCDelta >> 16);
    flashData[6] = static_cast<uint8_t>(xemicCCDelta >> 8);
    flashData[7] = static_cast<uint8_t>(xemicCCDelta);
    writeDataFlashBlock(0x68,0,16);
    hw::Timer.udelay(190);
    writeCheckSum();
  }

the applied current is -1.00 A and usually the value reported by the gauge is either too high or zero. Is this the proper way of calibrating the gauge? are the configuration parameters correct for a leac acid battery pack?

  • Edit:

    When CCGain and CCDelta are set to 5mOhm. The measured current is 20230 mA; applied current is -1.00A. The DF value for 5mOhm is "2155093793". After estimating the new CCGain and CCDelta using the formula below:

    float newCurrentGain = (static_cast<float>(currentMeasured)/currentApplied) * currentGainR; //currentGainR = 5.0 mOhm
    uint32_t xemicCCGain = floatToXemics(4.768/newCurrentGain);

    the newCurrentGain is "-96.4885559" when converted to DF "2103784394".

    And the measured current after that is 2304 mA which is still not right.

    Following is the code for floatToXemics:

    uint32_t BQ34Z100::floatToXemics(float value)	{
    	int iByte1,iByte2,iByte3,iByte4,iExp;
    	bool bNegative = false;
    	float fMantissa;
    
    	//Dont blow up with logs of zero
    	if(value ==0)
    			value = 0.00001F;
    	if(value < 0)
    	{
    		bNegative = true;
    		value =- value;
    	}
    
    	iExp = static_cast<int>((std::log(value)/std::log(2)) + 1);	//remember - log of any base is ln(x)/ln(base)
    	//MSB is the exponent + 0x80
    	iByte1 = iExp + 128;
    
    	//Divide input by the exponent to get mantissa;
    	fMantissa = value /(std::pow(2,iExp));
    
    	//scale it up
    	fMantissa = fMantissa / (std::pow(2,-24));
    	//split the mantissa into 3 bytes
    	iByte2 = static_cast<int>(fMantissa/std::pow(2,16));
    
    	iByte3 = static_cast<int>((fMantissa - (iByte2*std::pow(2,16)))/std::pow(2,8));
    
    	iByte4 = static_cast<int>((fMantissa - (iByte2*std::pow(2,16)))- (iByte3*std::pow(2,8)));
    
    	//subtract the sign bit if the number is positive
    	if(bNegative == false)
    			iByte2 = iByte2 & 0x7F;
    
    	return  static_cast<uint32_t> (iByte1<<24) | static_cast<uint32_t> (iByte2<<16) |
    						static_cast<uint32_t> (iByte3<<8) | static_cast<uint32_t> (iByte4);
    
    }
    

    Please do let me know if the above impl of floatToXemics is correct

  • Hi, Mohammed

        Can you further provide the code of xemicsToFloat, writeDataFlashBlock, readDataFlashBlock, and the read back data and actual calculated result in flashData array. the measured current with calibration before and after calibration?

  • xemicsToFloat Code:

    float BQ34Z100::xemicsToFloat(uint32_t value)	{
    	bool bIsPositive=false;
    	float fExponent,fResult;
    
    	uint8_t vMSByte,vMidHiByte,vMidLoByte,vLSByte;
    
    	vMSByte = static_cast<uint8_t>(value >> 24);
    	vMidHiByte = static_cast<uint8_t>(value >> 16);
    	vMidLoByte = static_cast<uint8_t>(value >> 8);
    	vLSByte = static_cast<uint8_t>(value);
    	//Get the sign its in the 0x00 80 00 00 bit
    	if((vMidHiByte & 128) == 0)
    		bIsPositive = true;
    
    	//Get the Exponent its 2^(vMSByte-128)
    	fExponent = std::pow(2,vMSByte-128);
    	// or in 0x80 to the vMidhiByte
    	vMidHiByte = (vMidHiByte | 128);
    	// get value of the vMidHiByte
    	fResult = vMidHiByte*65536;
    	//add in vMidLoByte
    	fResult += vMidLoByte*256;
    	//add in vLSByte
    	fResult = fResult + vLSByte;
    	//multiply by 2^(-24) to get the actual fraction
    	fResult = fResult * std::pow(2,-24);
    	//multiply the fraction by the exponent part
    	fResult *= fExponent;
    
    
    	if(bIsPositive)
    		return fResult;
    	else
    		return -fResult;
    }

    writeDataFlashBlock and readDataFlashBlock:

    void BQ34Z100::writeDataFlashBlock(uint8_t subclass,uint8_t index,uint8_t blockSize)	{
    	blockDataControl();
    	hw::Timer.udelay(190);
    	dataFlashClass(subclass);
    	hw::Timer.udelay(190); 
    	dataFlashBlock(index);
    	hw::Timer.udelay(1000);
    	writeBlock(0x40,&flashData[index],blockSize);
    }
    
    void BQ34Z100::readDataFlashBlock(uint8_t subclass,uint8_t index,uint8_t blockSize) {
    	blockDataControl();
    	hw::Timer.udelay(190); //Break Time
    	dataFlashClass(subclass);
    	hw::Timer.udelay(190); //Break Time
    	dataFlashBlock(index);
    	hw::Timer.udelay(190);	
    
    	readBlock(0x40,&flashData[index],blockSize);
    	hw::Timer.udelay(190);
    	readCheckSum();
    	oldMSB = flashData[index];
    	lastreadBlocksize = blockSize;
    	lastreadIndex = index;
    }

    This is the uint8_t flashData[32] array after reading the 104 subclass:

    gdb Output:

    {0xff, 0xff, 0xff, 0xf3, 0xe1, 0x41, 0x0 <repeats 26 times>}

    the above value represents DF CCGain "4294967283"

    after modifying the CC Delta and CCGain

    new CCGain "2130706432"

    gdb Output:

    {0x7f, 0x0, 0x0, 0x0, 0x7f, 0x0 <repeats 27 times>}

    Current before calibration:

    384 mA

    current After Calibration:

    5376 mA

    P.S now my voltage values are swinging wildly as well after each power cycle.

    the voltageDivider value i applied is 26080 for a 24V battery.

  • mohammed

       I just check something, the current gain is not in xemics float format, it is just IEEE754 format float data, so you do not need to transfer the data to xemics float, just try standard IEEE754 float data format

  • This post says that the floating point of many TI gauges is not the same as IEEE floating point

  • Hi, Mohammed

        There is a detailed description in sluub65a.pdf, page 106, the exp part is stored in an 4byte array at position byte[0], which indicates the lowest byte in the array, but in your floatToXemics function, if this program runs on PC, then exp part should be the bytes with the highest address in your 4 byte array, have you checked the byte sequence with a debugging tool for memory view