![](/media/cache/profiles/TAG-avatar.png.50x50_q85.png)
Utility library for testing and calibrating the BQ34Z100-G1 fuel gauge IC.
Utils library for our BQ34Z100G1 driver. See https://os.mbed.com/users/MultipleMonomials/code/BQ34Z100G1/wiki/Setup-and-Calibration-Guide
New releases of this code have moved to GitHub: https://github.com/USCRPL/BQ34Z100G1-Utils
BQ34Z100G1-Utils.cpp
- Committer:
- MultipleMonomials
- Date:
- 2021-02-07
- Revision:
- 0:fcd2c91c4626
File content as of revision 0:fcd2c91c4626:
/* USC RPL HAMSTER v2.3 BQ34Z100 Test Suite Contributors: Arpad Kovesdy */ #include "BQ34Z100G1-Utils.h" #include <cinttypes> namespace mbed { FileHandle *mbed_override_console(int) { static BufferedSerial serial(USBTX, USBRX, 115200); return &serial; } } // helper function to print a bitfield prettily. void printBitfield(uint16_t value, const char* name, const char** bitDescriptions) { printf("\n"); printf("%s: 0x%" PRIx16 " (0b", name, value); for (int i = 15; i >= 0; i--) { printf("%i", (value >> i) & 1); } printf(")\n"); const size_t maxBit = sizeof(value) * 8 - 1; for (int i = maxBit; i>=0; i--) { // Description array is in reverse order numerically char const * description = bitDescriptions[maxBit - i]; uint8_t bitValue = (value >> i) & 1; if(description != nullptr) { printf("- %s: %" PRIu8 "\n", description, bitValue); } } } void BQ34Utils::outputStatus() { uint16_t status_code = soc.getStatus(); // Descriptions for each bit of the status bytes const char* statusBitDescs[] = { nullptr, "Full Access Sealed (FAS)", "Sealed (SS)", "Calibration Enabled (CALEN)", "Coulomb Counter Calibrating (CCA)", "Board Calibration Active (BCA)", "Valid Data Flash Checksum (CSV)", nullptr, nullptr, nullptr, "Full Sleep Mode (FULLSLEEP)", "Sleep Mode (SLEEP)", "Impedance Track using Constant Power (LDMD)", "Ra Updates Disabled (RUP_DIS)", "Voltage OK for Qmax Updates (VOK)", "Qmax Updates Enabled (QEN)" }; printBitfield(status_code, "Control Status", statusBitDescs); // Descriptions for each bit of the flags bytes const char* flagsBitDescs[] = { "Overtemperature in Charge (OTC)", "Overtemperature in Discharge (OTD)", "High Battery Voltage (BATHI)", "Low Battery Voltage (BATLOW)", "Charge Inhibited (CHG_INH)", "Charging Not Allowed (XCHG)", "Full Charge (FC)", "Charge Allowed (CHG)", "Open Circuit Voltage Measurement Performed (OCVTAKEN)", nullptr, nullptr, "Update Cycle Needed (CF)", nullptr, "SoC Threshold 1 Reached (SOC1)", "SoC Threshold Final Reached (SOCF)", "Discharge Detected (DSG)" }; const char* flagsBBitDescs[] = { "State of Health Calc Active (SOH)", "LiFePO4 Relax Enabled (LIFE)", "Waiting for Depth of Discharge Measurement (FIRSTDOD)", nullptr, nullptr, "Depth of Discharge at End of Charge Updated (DODEOC)", "Remaining Capacity Changed (DTRC)", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; std::pair<uint16_t, uint16_t> flags = soc.getFlags(); printBitfield(flags.first, "Flags", flagsBitDescs); printBitfield(flags.second, "FlagsB", flagsBBitDescs); uint8_t updateStatus = soc.getUpdateStatus(); printf("Update status: 0x%" PRIx8 "\n", updateStatus); } void BQ34Utils::sensorReset() { printf("Resetting BQ34Z100 Sensor.\r\n"); soc.reset(); uint16_t deviceType = soc.readDeviceType(); if(deviceType == 0x100) { printf("BQ34Z100 detected\r\n"); } else { printf("Error communicating with BQ34Z100. Expected DEVICE_TYPE = 0x100, got 0x%" PRIx16 "\n", deviceType); return; } printf("Chip reads as FW_VERSION 0x%" PRIx16 ", HW version 0x%" PRIx16 "\r\n", soc.readFWVersion(), soc.readHWVersion()); } void BQ34Utils::displayData() { ThisThread::sleep_for(10ms); //Let the device catch up printf("SOC: %d%%\r\n", soc.getSOC()); printf("Voltage: %d mV\r\n", soc.getVoltage()); printf("Current: %d mA\r\n", soc.getCurrent()); printf("Remaining: %d mAh\r\n", soc.getRemaining()); printf("Temperature: %.1f C\r\n", soc.getTemperature()); printf("Max Error: %d%%\r\n", soc.getError()); printf("Serial No: %d\r\n", soc.getSerial()); printf("CHEM ID: %" PRIx16 "\r\n", soc.getChemID()); } void BQ34Utils::testICConnection() { printf("Testing Electrical Connection\r\n"); int status = soc.getStatus(); printf("Status: %d\r\n\r\n", status); } void BQ34Utils::startCal() { printf("Starting calibration mode\r\n"); soc.enableCal(); soc.enterCal(); } void BQ34Utils::stopCal() { printf("Stopping calibration mode\r\n"); soc.exitCal(); } void BQ34Utils::startIt() { printf("Enabling Impedance Tracking\r\n"); soc.ITEnable(); } //Outputs an integer of the length provided starting from the given index in flashBytes //Provide pointer to first element (array pointer to flashbytes) void BQ34Utils::outputFlashInt(uint8_t* flash, int index, int len) { if (index > 31) index = index % 32; unsigned int result = 0; for (int i = 0; i<len; i++) { //result = result | ((uint32_t)flash[index+i] << 8*len); result |= ((uint32_t)flash[index+i] << 8*(len-i-1)); } printf("%d", result); } void BQ34Utils::writeSettings() { if(soc.getVoltage() <= FLASH_UPDATE_OK_VOLT * CELLCOUNT) { 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."); } soc.unseal(); printf("Starting overwrite of sensor settings\r\n"); uint8_t* flashStore = soc.getFlashBytes(); //Get address of array for later //Page 48 soc.changePage(48, 0); //calls ChangePage from BQ34Z100 editing page 48 from datasheet soc.readFlash(); //declares old subclass properties as per BQ34Z100 function commands printf("Old design capacity:"); outputFlashInt(flashStore, 11, 2); printf("\r\n"); printf("Old design energy:"); outputFlashInt(flashStore, 13, 2); printf("\r\n"); //replaces the old subclass properties with new ones as per BQ34Z100 function commands soc.changePage48(); printf("New design capacity:"); outputFlashInt(flashStore, 11, 2); printf("\r\n"); printf("New design energy:"); outputFlashInt(flashStore, 13, 2); printf("\r\n"); //Page 64 soc.changePage(64, 0); //calls ChangePage from BQ34Z100 editing page 48 from datasheet soc.readFlash(); //declares old subclass properties as per BQ34Z100 function commands printf("Old Pack Configuration:"); outputFlashInt(flashStore, 0, 2); printf("\r\n"); printf("Old LED Config:"); outputFlashInt(flashStore, 4, 1); printf("\r\n"); printf("Old Cell Count:"); outputFlashInt(flashStore, 7, 1); printf("\r\n"); //replaces the old subclass properties with new ones as per BQ34Z100 function commands soc.changePage64(); printf("New Pack Configuration:"); outputFlashInt(flashStore, 0, 2); printf("\r\n"); printf("New LED Config:"); outputFlashInt(flashStore, 4, 1); printf("\r\n"); printf("New Cell Count:"); outputFlashInt(flashStore, 7, 1); printf("\r\n"); //Page 80 soc.changePage(80, 0); //calls ChangePage from BQ34Z100 editing page 48 from datasheet soc.readFlash(); //declares old subclass properties as per BQ34Z100 function commands printf("Old Load Select:"); outputFlashInt(flashStore, 0, 1); printf("\r\n"); printf("Old Load Mode:"); outputFlashInt(flashStore, 1, 1); printf("\r\n"); soc.changePage(80, 53); soc.readFlash(); printf("Old Cell Terminate Voltage:"); outputFlashInt(flashStore, 53, 2); printf("\r\n"); //replaces the old subclass properties with new ones as per BQ34Z100 function commands soc.changePage80(); soc.changePage(80, 0); soc.readFlash(); printf("New Load Select:"); outputFlashInt(flashStore, 0, 1); printf("\r\n"); printf("New Load Mode:"); outputFlashInt(flashStore, 1, 1); printf("\r\n"); printf("Res Current:"); outputFlashInt(flashStore, 10, 2); printf("\r\n"); soc.changePage(80, 53); soc.readFlash(); printf("New Cell Terminate Voltage:"); outputFlashInt(flashStore, 53, 2); printf("\r\n"); //Page 82 soc.changePage(82, 0); //calls ChangePage from BQ34Z100 editing page 48 from datasheet soc.readFlash(); //declares old subclass properties as per BQ34Z100 function commands printf("Old QMax0:"); outputFlashInt(flashStore, 0, 2); printf("\r\n"); //replaces the old subclass properties with new ones as per BQ34Z100 function commands soc.changePage82(); printf("New QMax0:"); outputFlashInt(flashStore, 0, 2); printf("\r\n"); //Print the updatestatus //0x02 = Qmax and Ra data are learned, but Impedance Track is not enabled. //This should be the standard setting for a Golden Image File //0x04 = Impedance Track is enabled but Qmax and Ra data are not yet learned. //0x05 = Impedance Track is enabled and only Qmax has been updated during a learning cycle. //0x06 = Impedance Track is enabled. Qmax and Ra data are learned after a successful learning //cycle. This should be the operation setting for end equipment. printf("UPDATE STATUS:"); outputFlashInt(flashStore, 4, 1); printf("\r\n"); } void BQ34Utils::calibrateVoltage () { printf("Enter voltage across the pack: "); float batVoltage=-1; scanf("%f", &batVoltage); printf("Hand measured voltage: %f\r\n\n", batVoltage); //printf("Enter ACTUAL battery voltage in volts\r\n"); //pc.scanf("%f", &batVoltage); uint16_t batVoltage_mv = (uint16_t)(batVoltage*1000.0f); printf("\r\nCurrent Monitor Bus Voltage Battery Voltage (V): %f\r\n", batVoltage); printf("New Flash Voltage: %d\r\n", soc.calibrateVoltage(batVoltage_mv)); } //Input current in A void BQ34Utils::calibrateCurrent() { // first reset back to theoretical value soc.setSenseResistor(); // reset sensor so it picks up new settings soc.reset(); ThisThread::sleep_for(200ms); // Now calibrate more exactly using hand-measured value printf("Enter current through the sense resistor in A: "); float current=-1; scanf("%f", ¤t); printf("Hand measured current%f:\r\n\n", current); printf("Calibrating current shunt\r\n\r\n"); int16_t current_int = (int16_t)(current*1000.0f); soc.calibrateShunt(current_int); } void BQ34Utils::readVoltageCurrent() { Timer chargeTimer; chargeTimer.start(); printf("Time (s),\tVoltage (V),\tCurrent (mA)\r\n"); while (true) { int voltage = soc.getVoltage(); int current = soc.getCurrent(); printf("%f,\t%d,\t%d\r\n", std::chrono::duration_cast<std::chrono::duration<float>>(chargeTimer.elapsed_time()).count(), voltage, current); ThisThread::sleep_for(100ms); } } void BQ34Utils::resetVoltageCalibration() { soc.setVoltageDivider(RESETVOLTAGE); printf("\r\n\nVoltage divider calibration reset.\r\n"); } void BQ34Utils::testFloatConversion() { // test data from https://e2e.ti.com/support/power-management/f/196/p/551252/2020286?tisearch=e2e-quicksearch&keymatch=xemics#2020286 float valueFloat = .8335f; uint32_t valueXemics = 0x80555E9E; // try converting float to xemics uint32_t convertedValue = BQ34Z100::floatToXemics(valueFloat); printf("Converted value: 0x%" PRIx32 "\n", convertedValue); // try converting xemics to float float convertedFloat = BQ34Z100::xemicsToFloat(valueXemics); printf("Converted float: %f\n", convertedFloat); printf("Expected default CC Gain: 0x%" PRIx32 "\n", BQ34Z100::floatToXemics(0.4768)); printf("Expected default CC Delta: 0x%" PRIx32 "\n", BQ34Z100::floatToXemics(567744.56)); } int main() { //declare the test harness BQ34Utils harness; while(1){ int test=-1; printf("\r\n\nBattery State of Charge Sensor Test Suite:\r\n"); //Menu for each test item printf("Select a test: \n\r"); printf("1. Reset Sensor (Restart)\r\n"); printf("2. Write Settings to Flash\r\n"); printf("3. Calibrate Voltage\r\n"); printf("4. Calibrate Current\r\n"); printf("5. Enable Calibration Mode\r\n"); printf("6. Disable Calibration Mode\r\n"); printf("7. Enable Impedance Tracking\r\n"); printf("8. Output Status\r\n"); printf("9. Display Data\r\n"); printf("10. Test Connection to Sensor\r\n"); printf("11. Reset Voltage Divider Calibration\r\n"); printf("12. Test Float Conversion\r\n"); printf("13. Read Voltage and Current Forever\r\n"); scanf("%d", &test); printf("Running test %d:\r\n\n", test); //SWITCH. ADD A CASE FOR EACH TEST. switch(test) { case 1: harness.sensorReset(); break; case 2: harness.writeSettings(); break; case 3: harness.calibrateVoltage(); break; case 4: harness.calibrateCurrent(); break; case 5: harness.startCal(); break; case 6: harness.stopCal(); break; case 7: harness.startIt(); break; case 8: harness.outputStatus(); break; case 9: harness.displayData(); break; case 10: harness.testICConnection(); break; case 11: harness.resetVoltageCalibration(); break; case 12: harness.testFloatConversion(); break; case 13: harness.readVoltageCurrent(); break; default: printf("Invalid test number.\r\n"); break; } printf("done.\r\n"); } return 0; }