Jamie Smith
/
BQ34Z100G1-Utils
Utility library for testing and calibrating the BQ34Z100-G1 fuel gauge IC.
Embed:
(wiki syntax)
Show/hide line numbers
BQ34Z100G1-Utils.cpp
00001 /* 00002 USC RPL HAMSTER v2.3 BQ34Z100 Test Suite 00003 Contributors: Arpad Kovesdy 00004 */ 00005 #include "BQ34Z100G1-Utils.h" 00006 00007 #include <cinttypes> 00008 00009 namespace mbed 00010 { 00011 FileHandle *mbed_override_console(int) 00012 { 00013 static BufferedSerial serial(USBTX, USBRX, 115200); 00014 return &serial; 00015 } 00016 } 00017 00018 // helper function to print a bitfield prettily. 00019 void printBitfield(uint16_t value, const char* name, const char** bitDescriptions) 00020 { 00021 printf("\n"); 00022 printf("%s: 0x%" PRIx16 " (0b", name, value); 00023 for (int i = 15; i >= 0; i--) 00024 { 00025 printf("%i", (value >> i) & 1); 00026 } 00027 printf(")\n"); 00028 00029 const size_t maxBit = sizeof(value) * 8 - 1; 00030 for (int i = maxBit; i>=0; i--) 00031 { 00032 // Description array is in reverse order numerically 00033 char const * description = bitDescriptions[maxBit - i]; 00034 00035 uint8_t bitValue = (value >> i) & 1; 00036 if(description != nullptr) 00037 { 00038 printf("- %s: %" PRIu8 "\n", description, bitValue); 00039 } 00040 } 00041 } 00042 00043 void BQ34Utils::outputStatus() 00044 { 00045 uint16_t status_code = soc.getStatus(); 00046 00047 // Descriptions for each bit of the status bytes 00048 const char* statusBitDescs[] = { 00049 nullptr, 00050 "Full Access Sealed (FAS)", 00051 "Sealed (SS)", 00052 "Calibration Enabled (CALEN)", 00053 "Coulomb Counter Calibrating (CCA)", 00054 "Board Calibration Active (BCA)", 00055 "Valid Data Flash Checksum (CSV)", 00056 nullptr, 00057 nullptr, 00058 nullptr, 00059 "Full Sleep Mode (FULLSLEEP)", 00060 "Sleep Mode (SLEEP)", 00061 "Impedance Track using Constant Power (LDMD)", 00062 "Ra Updates Disabled (RUP_DIS)", 00063 "Voltage OK for Qmax Updates (VOK)", 00064 "Qmax Updates Enabled (QEN)" 00065 }; 00066 00067 printBitfield(status_code, "Control Status", statusBitDescs); 00068 00069 // Descriptions for each bit of the flags bytes 00070 const char* flagsBitDescs[] = { 00071 "Overtemperature in Charge (OTC)", 00072 "Overtemperature in Discharge (OTD)", 00073 "High Battery Voltage (BATHI)", 00074 "Low Battery Voltage (BATLOW)", 00075 "Charge Inhibited (CHG_INH)", 00076 "Charging Not Allowed (XCHG)", 00077 "Full Charge (FC)", 00078 "Charge Allowed (CHG)", 00079 "Open Circuit Voltage Measurement Performed (OCVTAKEN)", 00080 nullptr, 00081 nullptr, 00082 "Update Cycle Needed (CF)", 00083 nullptr, 00084 "SoC Threshold 1 Reached (SOC1)", 00085 "SoC Threshold Final Reached (SOCF)", 00086 "Discharge Detected (DSG)" 00087 }; 00088 const char* flagsBBitDescs[] = { 00089 "State of Health Calc Active (SOH)", 00090 "LiFePO4 Relax Enabled (LIFE)", 00091 "Waiting for Depth of Discharge Measurement (FIRSTDOD)", 00092 nullptr, 00093 nullptr, 00094 "Depth of Discharge at End of Charge Updated (DODEOC)", 00095 "Remaining Capacity Changed (DTRC)", 00096 nullptr, 00097 nullptr, 00098 nullptr, 00099 nullptr, 00100 nullptr, 00101 nullptr, 00102 nullptr, 00103 nullptr, 00104 nullptr 00105 }; 00106 00107 std::pair<uint16_t, uint16_t> flags = soc.getFlags(); 00108 printBitfield(flags.first, "Flags", flagsBitDescs); 00109 printBitfield(flags.second, "FlagsB", flagsBBitDescs); 00110 00111 00112 uint8_t updateStatus = soc.getUpdateStatus(); 00113 printf("Update status: 0x%" PRIx8 "\n", updateStatus); 00114 } 00115 00116 void BQ34Utils::sensorReset() 00117 { 00118 printf("Resetting BQ34Z100 Sensor.\r\n"); 00119 soc.reset(); 00120 00121 uint16_t deviceType = soc.readDeviceType(); 00122 if(deviceType == 0x100) 00123 { 00124 printf("BQ34Z100 detected\r\n"); 00125 } 00126 else 00127 { 00128 printf("Error communicating with BQ34Z100. Expected DEVICE_TYPE = 0x100, got 0x%" PRIx16 "\n", deviceType); 00129 return; 00130 } 00131 00132 printf("Chip reads as FW_VERSION 0x%" PRIx16 ", HW version 0x%" PRIx16 "\r\n", soc.readFWVersion(), soc.readHWVersion()); 00133 } 00134 00135 00136 void BQ34Utils::displayData() 00137 { 00138 ThisThread::sleep_for(10ms); //Let the device catch up 00139 printf("SOC: %d%%\r\n", soc.getSOC()); 00140 printf("Voltage: %d mV\r\n", soc.getVoltage()); 00141 printf("Current: %d mA\r\n", soc.getCurrent()); 00142 printf("Remaining: %d mAh\r\n", soc.getRemaining()); 00143 printf("Temperature: %.1f C\r\n", soc.getTemperature()); 00144 printf("Max Error: %d%%\r\n", soc.getError()); 00145 printf("Serial No: %d\r\n", soc.getSerial()); 00146 printf("CHEM ID: %" PRIx16 "\r\n", soc.getChemID()); 00147 } 00148 00149 void BQ34Utils::testICConnection() 00150 { 00151 printf("Testing Electrical Connection\r\n"); 00152 int status = soc.getStatus(); 00153 printf("Status: %d\r\n\r\n", status); 00154 } 00155 00156 void BQ34Utils::startCal() 00157 { 00158 printf("Starting calibration mode\r\n"); 00159 soc.enableCal(); 00160 soc.enterCal(); 00161 } 00162 00163 void BQ34Utils::stopCal() 00164 { 00165 printf("Stopping calibration mode\r\n"); 00166 soc.exitCal(); 00167 } 00168 00169 void BQ34Utils::startIt() 00170 { 00171 printf("Enabling Impedance Tracking\r\n"); 00172 soc.ITEnable(); 00173 } 00174 00175 //Outputs an integer of the length provided starting from the given index in flashBytes 00176 //Provide pointer to first element (array pointer to flashbytes) 00177 void BQ34Utils::outputFlashInt(uint8_t* flash, int index, int len) 00178 { 00179 if (index > 31) index = index % 32; 00180 unsigned int result = 0; 00181 for (int i = 0; i<len; i++) 00182 { 00183 //result = result | ((uint32_t)flash[index+i] << 8*len); 00184 result |= ((uint32_t)flash[index+i] << 8*(len-i-1)); 00185 } 00186 printf("%d", result); 00187 } 00188 00189 void BQ34Utils::writeSettings() 00190 { 00191 if(soc.getVoltage() <= FLASH_UPDATE_OK_VOLT * CELLCOUNT) 00192 { 00193 printf("WARNING: Measured voltage is below FLASH_UPDATE_OK_VOLT, flash memory writes may not go through. However this is expected if voltage has not been calibrated yet."); 00194 } 00195 00196 soc.unseal(); 00197 printf("Starting overwrite of sensor settings\r\n"); 00198 uint8_t* flashStore = soc.getFlashBytes(); //Get address of array for later 00199 00200 //Page 48 00201 soc.changePage(48, 0); //calls ChangePage from BQ34Z100 editing page 48 from datasheet 00202 soc.readFlash(); 00203 00204 //declares old subclass properties as per BQ34Z100 function commands 00205 printf("Old design capacity:"); 00206 outputFlashInt(flashStore, 11, 2); 00207 printf("\r\n"); 00208 printf("Old design energy:"); 00209 outputFlashInt(flashStore, 13, 2); 00210 printf("\r\n"); 00211 00212 //replaces the old subclass properties with new ones as per BQ34Z100 function commands 00213 soc.changePage48(); 00214 printf("New design capacity:"); 00215 outputFlashInt(flashStore, 11, 2); 00216 printf("\r\n"); 00217 printf("New design energy:"); 00218 outputFlashInt(flashStore, 13, 2); 00219 printf("\r\n"); 00220 00221 //Page 64 00222 soc.changePage(64, 0); //calls ChangePage from BQ34Z100 editing page 48 from datasheet 00223 soc.readFlash(); 00224 00225 //declares old subclass properties as per BQ34Z100 function commands 00226 printf("Old Pack Configuration:"); 00227 outputFlashInt(flashStore, 0, 2); 00228 printf("\r\n"); 00229 printf("Old LED Config:"); 00230 outputFlashInt(flashStore, 4, 1); 00231 printf("\r\n"); 00232 printf("Old Cell Count:"); 00233 outputFlashInt(flashStore, 7, 1); 00234 printf("\r\n"); 00235 00236 //replaces the old subclass properties with new ones as per BQ34Z100 function commands 00237 soc.changePage64(); 00238 printf("New Pack Configuration:"); 00239 outputFlashInt(flashStore, 0, 2); 00240 printf("\r\n"); 00241 printf("New LED Config:"); 00242 outputFlashInt(flashStore, 4, 1); 00243 printf("\r\n"); 00244 printf("New Cell Count:"); 00245 outputFlashInt(flashStore, 7, 1); 00246 printf("\r\n"); 00247 00248 //Page 80 00249 00250 soc.changePage(80, 0); //calls ChangePage from BQ34Z100 editing page 48 from datasheet 00251 soc.readFlash(); 00252 //declares old subclass properties as per BQ34Z100 function commands 00253 printf("Old Load Select:"); 00254 outputFlashInt(flashStore, 0, 1); 00255 printf("\r\n"); 00256 printf("Old Load Mode:"); 00257 outputFlashInt(flashStore, 1, 1); 00258 printf("\r\n"); 00259 00260 soc.changePage(80, 53); 00261 soc.readFlash(); 00262 printf("Old Cell Terminate Voltage:"); 00263 outputFlashInt(flashStore, 53, 2); 00264 printf("\r\n"); 00265 00266 //replaces the old subclass properties with new ones as per BQ34Z100 function commands 00267 soc.changePage80(); 00268 soc.changePage(80, 0); 00269 soc.readFlash(); 00270 printf("New Load Select:"); 00271 outputFlashInt(flashStore, 0, 1); 00272 printf("\r\n"); 00273 printf("New Load Mode:"); 00274 outputFlashInt(flashStore, 1, 1); 00275 printf("\r\n"); 00276 printf("Res Current:"); 00277 outputFlashInt(flashStore, 10, 2); 00278 printf("\r\n"); 00279 soc.changePage(80, 53); 00280 soc.readFlash(); 00281 printf("New Cell Terminate Voltage:"); 00282 outputFlashInt(flashStore, 53, 2); 00283 printf("\r\n"); 00284 00285 //Page 82 00286 soc.changePage(82, 0); //calls ChangePage from BQ34Z100 editing page 48 from datasheet 00287 soc.readFlash(); 00288 00289 //declares old subclass properties as per BQ34Z100 function commands 00290 printf("Old QMax0:"); 00291 outputFlashInt(flashStore, 0, 2); 00292 printf("\r\n"); 00293 00294 //replaces the old subclass properties with new ones as per BQ34Z100 function commands 00295 soc.changePage82(); 00296 printf("New QMax0:"); 00297 outputFlashInt(flashStore, 0, 2); 00298 printf("\r\n"); 00299 00300 //Print the updatestatus 00301 //0x02 = Qmax and Ra data are learned, but Impedance Track is not enabled. 00302 //This should be the standard setting for a Golden Image File 00303 //0x04 = Impedance Track is enabled but Qmax and Ra data are not yet learned. 00304 //0x05 = Impedance Track is enabled and only Qmax has been updated during a learning cycle. 00305 //0x06 = Impedance Track is enabled. Qmax and Ra data are learned after a successful learning 00306 //cycle. This should be the operation setting for end equipment. 00307 printf("UPDATE STATUS:"); 00308 outputFlashInt(flashStore, 4, 1); 00309 printf("\r\n"); 00310 } 00311 00312 void BQ34Utils::calibrateVoltage () 00313 { 00314 00315 printf("Enter voltage across the pack: "); 00316 float batVoltage=-1; 00317 scanf("%f", &batVoltage); 00318 printf("Hand measured voltage: %f\r\n\n", batVoltage); 00319 //printf("Enter ACTUAL battery voltage in volts\r\n"); 00320 //pc.scanf("%f", &batVoltage); 00321 uint16_t batVoltage_mv = (uint16_t)(batVoltage*1000.0f); 00322 printf("\r\nCurrent Monitor Bus Voltage Battery Voltage (V): %f\r\n", batVoltage); 00323 00324 printf("New Flash Voltage: %d\r\n", soc.calibrateVoltage(batVoltage_mv)); 00325 } 00326 00327 //Input current in A 00328 void BQ34Utils::calibrateCurrent() 00329 { 00330 // first reset back to theoretical value 00331 soc.setSenseResistor(); 00332 00333 // reset sensor so it picks up new settings 00334 soc.reset(); 00335 ThisThread::sleep_for(200ms); 00336 00337 // Now calibrate more exactly using hand-measured value 00338 printf("Enter current through the sense resistor in A: "); 00339 float current=-1; 00340 scanf("%f", ¤t); 00341 printf("Hand measured current%f:\r\n\n", current); 00342 00343 printf("Calibrating current shunt\r\n\r\n"); 00344 int16_t current_int = (int16_t)(current*1000.0f); 00345 soc.calibrateShunt(current_int); 00346 } 00347 00348 00349 void BQ34Utils::readVoltageCurrent() 00350 { 00351 Timer chargeTimer; 00352 chargeTimer.start(); 00353 00354 printf("Time (s),\tVoltage (V),\tCurrent (mA)\r\n"); 00355 00356 while (true) { 00357 int voltage = soc.getVoltage(); 00358 int current = soc.getCurrent(); 00359 printf("%f,\t%d,\t%d\r\n", std::chrono::duration_cast<std::chrono::duration<float>>(chargeTimer.elapsed_time()).count(), voltage, current); 00360 ThisThread::sleep_for(100ms); 00361 } 00362 } 00363 00364 void BQ34Utils::resetVoltageCalibration() 00365 { 00366 soc.setVoltageDivider(RESETVOLTAGE); 00367 printf("\r\n\nVoltage divider calibration reset.\r\n"); 00368 } 00369 00370 void BQ34Utils::testFloatConversion() 00371 { 00372 // test data from https://e2e.ti.com/support/power-management/f/196/p/551252/2020286?tisearch=e2e-quicksearch&keymatch=xemics#2020286 00373 float valueFloat = .8335f; 00374 uint32_t valueXemics = 0x80555E9E; 00375 00376 // try converting float to xemics 00377 uint32_t convertedValue = BQ34Z100::floatToXemics(valueFloat); 00378 printf("Converted value: 0x%" PRIx32 "\n", convertedValue); 00379 00380 // try converting xemics to float 00381 float convertedFloat = BQ34Z100::xemicsToFloat(valueXemics); 00382 printf("Converted float: %f\n", convertedFloat); 00383 00384 printf("Expected default CC Gain: 0x%" PRIx32 "\n", BQ34Z100::floatToXemics(0.4768)); 00385 printf("Expected default CC Delta: 0x%" PRIx32 "\n", BQ34Z100::floatToXemics(567744.56)); 00386 00387 } 00388 00389 00390 int main() 00391 { 00392 //declare the test harness 00393 BQ34Utils harness; 00394 00395 while(1){ 00396 int test=-1; 00397 printf("\r\n\nBattery State of Charge Sensor Test Suite:\r\n"); 00398 00399 //Menu for each test item 00400 printf("Select a test: \n\r"); 00401 printf("1. Reset Sensor (Restart)\r\n"); 00402 printf("2. Write Settings to Flash\r\n"); 00403 printf("3. Calibrate Voltage\r\n"); 00404 printf("4. Calibrate Current\r\n"); 00405 printf("5. Enable Calibration Mode\r\n"); 00406 printf("6. Disable Calibration Mode\r\n"); 00407 printf("7. Enable Impedance Tracking\r\n"); 00408 printf("8. Output Status\r\n"); 00409 printf("9. Display Data\r\n"); 00410 printf("10. Test Connection to Sensor\r\n"); 00411 printf("11. Reset Voltage Divider Calibration\r\n"); 00412 printf("12. Test Float Conversion\r\n"); 00413 printf("13. Read Voltage and Current Forever\r\n"); 00414 00415 scanf("%d", &test); 00416 printf("Running test %d:\r\n\n", test); 00417 00418 //SWITCH. ADD A CASE FOR EACH TEST. 00419 switch(test) { 00420 case 1: harness.sensorReset(); break; 00421 case 2: harness.writeSettings(); break; 00422 case 3: harness.calibrateVoltage(); break; 00423 case 4: harness.calibrateCurrent(); break; 00424 case 5: harness.startCal(); break; 00425 case 6: harness.stopCal(); break; 00426 case 7: harness.startIt(); break; 00427 case 8: harness.outputStatus(); break; 00428 case 9: harness.displayData(); break; 00429 case 10: harness.testICConnection(); break; 00430 case 11: harness.resetVoltageCalibration(); break; 00431 case 12: harness.testFloatConversion(); break; 00432 case 13: harness.readVoltageCurrent(); break; 00433 default: printf("Invalid test number.\r\n"); break; 00434 } 00435 00436 printf("done.\r\n"); 00437 } 00438 return 0; 00439 }
Generated on Sun Jul 17 2022 10:02:44 by 1.7.2