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
Revision 0:fcd2c91c4626, committed 2021-02-07
- Comitter:
- MultipleMonomials
- Date:
- Sun Feb 07 14:21:20 2021 -0800
- Commit message:
- Import test suite from RPL repository
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sun Feb 07 14:21:20 2021 -0800 @@ -0,0 +1,4 @@ +^BUILD$ +^.mbed$ +^mbed-os$ +^BQ34Z100G1$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BQ34Z100G1-Utils.cpp Sun Feb 07 14:21:20 2021 -0800 @@ -0,0 +1,439 @@ +/* + 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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BQ34Z100G1-Utils.h Sun Feb 07 14:21:20 2021 -0800 @@ -0,0 +1,31 @@ +/* + USC RPL HAMSTER v2.3 BQ34Z100 Test Suite + Contributors: Arpad Kovesdy +*/ + +#pragma once + +#include "BQ34Z100.h" +#include "mbed.h" + +BQ34Z100 soc(I2C_SDA, I2C_SCL, 10000); + +class BQ34Utils { +public: + void outputStatus(); + void sensorReset(); + void displayData(); + void testICConnection(); + void startCal(); + void stopCal(); + void startIt(); + void writeSettings(); + void calibrateVoltage(); + void calibrateCurrent(); + void resetVoltageCalibration(); + void testFloatConversion(); + void readVoltageCurrent(); + +private: + void outputFlashInt(uint8_t* flash, int index, int len); +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BQ34Z100G1.lib Sun Feb 07 14:21:20 2021 -0800 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/MultipleMonomials/code/BQ34Z100G1/#6d09d3ad58aada9b6ebefd70e21e7757befbe66b \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Sun Feb 07 14:21:20 2021 -0800 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os#0c6753bb821612eb72b5f682aed7ffcc98e80a1f \ No newline at end of file