Utility library for testing and calibrating the BQ34Z100-G1 fuel gauge IC.

Dependencies:   BQ34Z100G1

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BQ34Z100G1-Utils.cpp Source File

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", &current);
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 }