Driver for Texas Instruments' battery state-of-charge estimator.
Dependents: BQ34Z100G1-Utils BQ34Z100G1-ChemIDMeasurer
BQ34Z100G1 Driver
Newer releases of this driver have moved to GitHub: https://github.com/USCRPL/BQ34Z100G1-Driver
By USC Rocket Propulsion Lab / Arpad Kovesdy, Kyle Marino, Jamie Smith
After lots of development, testing, debugging, dead ends, backtracking, and retracing our steps, we at RPL are proud to present a complete driver for Texas Instruments' BQ34Z100G1 state-of-charge estimator. This handy chip handles all the complexities of monitoring a battery's charging and discharging cycle, and is one of the only real ways to have a real estimate of how much usable energy is left in a standard lithium-ion battery.
However, in order to perform this function, the IC needs a lot of information, including both the on-paper specifications of your battery system and the results of several different calibration runs of your real battery system. With one exception*, this driver can handle all the needed configuration, taking you from unconfigured to calibrated in as little time as possible.
Note: To initially program the Chem ID information into each chip to configure it for your battery, you will need an EV2300 or EV2400 programmer box from TI, as well as a header to plug it in on your board.
Calibrating the Chip
See here.
Credits
The initial version of this driver was taken from Ralim on GitHub here.
However, we have made a huge number of changes and additions since then, including porting the Arduino library to Mbed, cleaning up the code to use enums, breaking out the configuration to external constants, and fixing looots of bugs.
BQ34Z100.cpp@0:6d09d3ad58aa, 2021-02-07 (annotated)
- Committer:
- Jamie Smith
- Date:
- Sun Feb 07 01:17:28 2021 -0800
- Revision:
- 0:6d09d3ad58aa
Import from RPL internal repository
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Jamie Smith |
0:6d09d3ad58aa | 1 | #include "BQ34Z100.h" |
Jamie Smith |
0:6d09d3ad58aa | 2 | |
Jamie Smith |
0:6d09d3ad58aa | 3 | #include <cinttypes> |
Jamie Smith |
0:6d09d3ad58aa | 4 | |
Jamie Smith |
0:6d09d3ad58aa | 5 | BQ34Z100::BQ34Z100(PinName sda, PinName scl, int hz) : _i2c(sda,scl) |
Jamie Smith |
0:6d09d3ad58aa | 6 | { |
Jamie Smith |
0:6d09d3ad58aa | 7 | //Set the I2C bus frequency |
Jamie Smith |
0:6d09d3ad58aa | 8 | _i2c.frequency(hz); |
Jamie Smith |
0:6d09d3ad58aa | 9 | } |
Jamie Smith |
0:6d09d3ad58aa | 10 | |
Jamie Smith |
0:6d09d3ad58aa | 11 | //For example, sending Control(0x0414) |
Jamie Smith |
0:6d09d3ad58aa | 12 | //Translates into WRITE 0x00 0x14 0x04 |
Jamie Smith |
0:6d09d3ad58aa | 13 | //Command1 = 0x04 and Command2 = 0x14 in this case |
Jamie Smith |
0:6d09d3ad58aa | 14 | void BQ34Z100::sendControlCommand(Control control) |
Jamie Smith |
0:6d09d3ad58aa | 15 | { |
Jamie Smith |
0:6d09d3ad58aa | 16 | //First write two bytes, LSB first |
Jamie Smith |
0:6d09d3ad58aa | 17 | uint16_t controlBytes = static_cast<uint16_t>(control); |
Jamie Smith |
0:6d09d3ad58aa | 18 | write(Command::Control, controlBytes & 0xFF, (controlBytes >> 8) & 0xFF); |
Jamie Smith |
0:6d09d3ad58aa | 19 | } |
Jamie Smith |
0:6d09d3ad58aa | 20 | |
Jamie Smith |
0:6d09d3ad58aa | 21 | //For example, sending Control(0x0414) |
Jamie Smith |
0:6d09d3ad58aa | 22 | //Translates into WRITE 0x00 0x14 0x04 |
Jamie Smith |
0:6d09d3ad58aa | 23 | //Command1 = 0x04 and Command2 = 0x14 in this case |
Jamie Smith |
0:6d09d3ad58aa | 24 | uint16_t BQ34Z100::readControlCommand(Control control) |
Jamie Smith |
0:6d09d3ad58aa | 25 | { |
Jamie Smith |
0:6d09d3ad58aa | 26 | //First write two bytes, LSB first |
Jamie Smith |
0:6d09d3ad58aa | 27 | uint16_t controlBytes = static_cast<uint16_t>(control); |
Jamie Smith |
0:6d09d3ad58aa | 28 | write(Command::Control, controlBytes & 0xFF, (controlBytes >> 8) & 0xFF); |
Jamie Smith |
0:6d09d3ad58aa | 29 | //Read two bytes from the register 0x00 |
Jamie Smith |
0:6d09d3ad58aa | 30 | return read(Command::Control, 2); |
Jamie Smith |
0:6d09d3ad58aa | 31 | } |
Jamie Smith |
0:6d09d3ad58aa | 32 | |
Jamie Smith |
0:6d09d3ad58aa | 33 | //Writes over I2c to the device |
Jamie Smith |
0:6d09d3ad58aa | 34 | //For example the start subcommand WRITE 01 00 to Register 00 requires |
Jamie Smith |
0:6d09d3ad58aa | 35 | //write(0x00, 0x01, 0x00) |
Jamie Smith |
0:6d09d3ad58aa | 36 | void BQ34Z100::write(Command command, const uint8_t cmd1, const uint8_t cmd2) |
Jamie Smith |
0:6d09d3ad58aa | 37 | { |
Jamie Smith |
0:6d09d3ad58aa | 38 | //TODO, add i2c error checking like in read() |
Jamie Smith |
0:6d09d3ad58aa | 39 | _i2c.start(); |
Jamie Smith |
0:6d09d3ad58aa | 40 | _i2c.write(GAUGE_ADDRESS | 0x0); |
Jamie Smith |
0:6d09d3ad58aa | 41 | _i2c.write(static_cast<uint8_t>(command)); |
Jamie Smith |
0:6d09d3ad58aa | 42 | _i2c.write(cmd1); |
Jamie Smith |
0:6d09d3ad58aa | 43 | _i2c.write(cmd2); |
Jamie Smith |
0:6d09d3ad58aa | 44 | _i2c.stop(); |
Jamie Smith |
0:6d09d3ad58aa | 45 | } |
Jamie Smith |
0:6d09d3ad58aa | 46 | |
Jamie Smith |
0:6d09d3ad58aa | 47 | //Similar to the previous function but only writes 1 byte |
Jamie Smith |
0:6d09d3ad58aa | 48 | void BQ34Z100::write(Command command, const uint8_t cmd) |
Jamie Smith |
0:6d09d3ad58aa | 49 | { |
Jamie Smith |
0:6d09d3ad58aa | 50 | _i2c.start(); |
Jamie Smith |
0:6d09d3ad58aa | 51 | _i2c.write(GAUGE_ADDRESS | 0x0); |
Jamie Smith |
0:6d09d3ad58aa | 52 | _i2c.write(static_cast<uint8_t>(command)); |
Jamie Smith |
0:6d09d3ad58aa | 53 | _i2c.write(cmd); |
Jamie Smith |
0:6d09d3ad58aa | 54 | _i2c.stop(); |
Jamie Smith |
0:6d09d3ad58aa | 55 | } |
Jamie Smith |
0:6d09d3ad58aa | 56 | |
Jamie Smith |
0:6d09d3ad58aa | 57 | //Reads over i2c to the device |
Jamie Smith |
0:6d09d3ad58aa | 58 | //For example, to finish the subcommand sequence (step 2), READ 2 bytes from register 00 |
Jamie Smith |
0:6d09d3ad58aa | 59 | //read(0x00, 2) |
Jamie Smith |
0:6d09d3ad58aa | 60 | uint32_t BQ34Z100::read(Command command, const uint8_t length) |
Jamie Smith |
0:6d09d3ad58aa | 61 | { |
Jamie Smith |
0:6d09d3ad58aa | 62 | uint32_t val = 0; //Contains next byte of data that will be read |
Jamie Smith |
0:6d09d3ad58aa | 63 | |
Jamie Smith |
0:6d09d3ad58aa | 64 | for (int i = 0; i < length; i++) |
Jamie Smith |
0:6d09d3ad58aa | 65 | { |
Jamie Smith |
0:6d09d3ad58aa | 66 | _i2c.start(); |
Jamie Smith |
0:6d09d3ad58aa | 67 | |
Jamie Smith |
0:6d09d3ad58aa | 68 | int writeResult = _i2c.write(GAUGE_ADDRESS | 0x0); |
Jamie Smith |
0:6d09d3ad58aa | 69 | |
Jamie Smith |
0:6d09d3ad58aa | 70 | if(writeResult != 1) |
Jamie Smith |
0:6d09d3ad58aa | 71 | { |
Jamie Smith |
0:6d09d3ad58aa | 72 | printf("A write error has occurred when transmitting address.\r\n"); |
Jamie Smith |
0:6d09d3ad58aa | 73 | return 0; |
Jamie Smith |
0:6d09d3ad58aa | 74 | } |
Jamie Smith |
0:6d09d3ad58aa | 75 | |
Jamie Smith |
0:6d09d3ad58aa | 76 | _i2c.write(static_cast<uint8_t>(command) + i); |
Jamie Smith |
0:6d09d3ad58aa | 77 | _i2c.stop(); |
Jamie Smith |
0:6d09d3ad58aa | 78 | |
Jamie Smith |
0:6d09d3ad58aa | 79 | _i2c.start(); |
Jamie Smith |
0:6d09d3ad58aa | 80 | _i2c.write(GAUGE_ADDRESS | 0x1); |
Jamie Smith |
0:6d09d3ad58aa | 81 | |
Jamie Smith |
0:6d09d3ad58aa | 82 | //Swap bytes around (convert to Little Endian) |
Jamie Smith |
0:6d09d3ad58aa | 83 | val |= (_i2c.read(false) << (8 * i)); |
Jamie Smith |
0:6d09d3ad58aa | 84 | |
Jamie Smith |
0:6d09d3ad58aa | 85 | _i2c.stop(); |
Jamie Smith |
0:6d09d3ad58aa | 86 | |
Jamie Smith |
0:6d09d3ad58aa | 87 | } |
Jamie Smith |
0:6d09d3ad58aa | 88 | |
Jamie Smith |
0:6d09d3ad58aa | 89 | return val; |
Jamie Smith |
0:6d09d3ad58aa | 90 | } |
Jamie Smith |
0:6d09d3ad58aa | 91 | |
Jamie Smith |
0:6d09d3ad58aa | 92 | void BQ34Z100::enableCal() |
Jamie Smith |
0:6d09d3ad58aa | 93 | { |
Jamie Smith |
0:6d09d3ad58aa | 94 | sendControlCommand(Control::CAL_ENABLE); |
Jamie Smith |
0:6d09d3ad58aa | 95 | } |
Jamie Smith |
0:6d09d3ad58aa | 96 | |
Jamie Smith |
0:6d09d3ad58aa | 97 | void BQ34Z100::enterCal() |
Jamie Smith |
0:6d09d3ad58aa | 98 | { |
Jamie Smith |
0:6d09d3ad58aa | 99 | sendControlCommand(Control::ENTER_CAL); |
Jamie Smith |
0:6d09d3ad58aa | 100 | } |
Jamie Smith |
0:6d09d3ad58aa | 101 | |
Jamie Smith |
0:6d09d3ad58aa | 102 | void BQ34Z100::exitCal() |
Jamie Smith |
0:6d09d3ad58aa | 103 | { |
Jamie Smith |
0:6d09d3ad58aa | 104 | sendControlCommand(Control::EXIT_CAL); |
Jamie Smith |
0:6d09d3ad58aa | 105 | } |
Jamie Smith |
0:6d09d3ad58aa | 106 | |
Jamie Smith |
0:6d09d3ad58aa | 107 | //Warning: Enabling IT should only be done when configuration is complete |
Jamie Smith |
0:6d09d3ad58aa | 108 | void BQ34Z100::ITEnable() |
Jamie Smith |
0:6d09d3ad58aa | 109 | { |
Jamie Smith |
0:6d09d3ad58aa | 110 | sendControlCommand(Control::IT_ENABLE); |
Jamie Smith |
0:6d09d3ad58aa | 111 | } |
Jamie Smith |
0:6d09d3ad58aa | 112 | |
Jamie Smith |
0:6d09d3ad58aa | 113 | uint16_t BQ34Z100::getStatus() |
Jamie Smith |
0:6d09d3ad58aa | 114 | { |
Jamie Smith |
0:6d09d3ad58aa | 115 | return readControlCommand(Control::CONTROL_STATUS); |
Jamie Smith |
0:6d09d3ad58aa | 116 | } |
Jamie Smith |
0:6d09d3ad58aa | 117 | |
Jamie Smith |
0:6d09d3ad58aa | 118 | uint16_t BQ34Z100::getChemID() |
Jamie Smith |
0:6d09d3ad58aa | 119 | { |
Jamie Smith |
0:6d09d3ad58aa | 120 | return readControlCommand(Control::CHEM_ID); |
Jamie Smith |
0:6d09d3ad58aa | 121 | } |
Jamie Smith |
0:6d09d3ad58aa | 122 | |
Jamie Smith |
0:6d09d3ad58aa | 123 | uint16_t BQ34Z100::getStateOfHealth() |
Jamie Smith |
0:6d09d3ad58aa | 124 | { |
Jamie Smith |
0:6d09d3ad58aa | 125 | return read(Command::StateOfHealth, 2); |
Jamie Smith |
0:6d09d3ad58aa | 126 | } |
Jamie Smith |
0:6d09d3ad58aa | 127 | |
Jamie Smith |
0:6d09d3ad58aa | 128 | uint8_t BQ34Z100::getSOC() |
Jamie Smith |
0:6d09d3ad58aa | 129 | { |
Jamie Smith |
0:6d09d3ad58aa | 130 | return read(Command::StateOfCharge, 1); |
Jamie Smith |
0:6d09d3ad58aa | 131 | } |
Jamie Smith |
0:6d09d3ad58aa | 132 | |
Jamie Smith |
0:6d09d3ad58aa | 133 | uint16_t BQ34Z100::getError() |
Jamie Smith |
0:6d09d3ad58aa | 134 | { |
Jamie Smith |
0:6d09d3ad58aa | 135 | return read(Command::MaxError, 1); |
Jamie Smith |
0:6d09d3ad58aa | 136 | } |
Jamie Smith |
0:6d09d3ad58aa | 137 | |
Jamie Smith |
0:6d09d3ad58aa | 138 | uint16_t BQ34Z100::getRemaining() |
Jamie Smith |
0:6d09d3ad58aa | 139 | { |
Jamie Smith |
0:6d09d3ad58aa | 140 | return read(Command::RemainingCapacity, 2); |
Jamie Smith |
0:6d09d3ad58aa | 141 | } |
Jamie Smith |
0:6d09d3ad58aa | 142 | |
Jamie Smith |
0:6d09d3ad58aa | 143 | uint16_t BQ34Z100::getVoltage() |
Jamie Smith |
0:6d09d3ad58aa | 144 | { |
Jamie Smith |
0:6d09d3ad58aa | 145 | return read(Command::Voltage, 2); |
Jamie Smith |
0:6d09d3ad58aa | 146 | } |
Jamie Smith |
0:6d09d3ad58aa | 147 | |
Jamie Smith |
0:6d09d3ad58aa | 148 | int16_t BQ34Z100::getCurrent() |
Jamie Smith |
0:6d09d3ad58aa | 149 | { |
Jamie Smith |
0:6d09d3ad58aa | 150 | int16_t result = read(Command::Current, 2); |
Jamie Smith |
0:6d09d3ad58aa | 151 | if (result < 0) result = -result; |
Jamie Smith |
0:6d09d3ad58aa | 152 | return result; |
Jamie Smith |
0:6d09d3ad58aa | 153 | } |
Jamie Smith |
0:6d09d3ad58aa | 154 | |
Jamie Smith |
0:6d09d3ad58aa | 155 | double BQ34Z100::getTemperature() |
Jamie Smith |
0:6d09d3ad58aa | 156 | { |
Jamie Smith |
0:6d09d3ad58aa | 157 | //The device returns an internal temperature in units of 0.1K |
Jamie Smith |
0:6d09d3ad58aa | 158 | //Convert to celsius by subtracting dividing by 10 then subtracting 273.15K |
Jamie Smith |
0:6d09d3ad58aa | 159 | return (read(Command::Temperature, 2)/10.0) - 273.15; |
Jamie Smith |
0:6d09d3ad58aa | 160 | } |
Jamie Smith |
0:6d09d3ad58aa | 161 | |
Jamie Smith |
0:6d09d3ad58aa | 162 | int BQ34Z100::getSerial() |
Jamie Smith |
0:6d09d3ad58aa | 163 | { |
Jamie Smith |
0:6d09d3ad58aa | 164 | return read(Command::SerialNumber, 2); |
Jamie Smith |
0:6d09d3ad58aa | 165 | } |
Jamie Smith |
0:6d09d3ad58aa | 166 | |
Jamie Smith |
0:6d09d3ad58aa | 167 | void BQ34Z100::reset() |
Jamie Smith |
0:6d09d3ad58aa | 168 | { |
Jamie Smith |
0:6d09d3ad58aa | 169 | sendControlCommand(Control::RESET); |
Jamie Smith |
0:6d09d3ad58aa | 170 | ThisThread::sleep_for(175ms); // experimentally determined boot time |
Jamie Smith |
0:6d09d3ad58aa | 171 | } |
Jamie Smith |
0:6d09d3ad58aa | 172 | |
Jamie Smith |
0:6d09d3ad58aa | 173 | void BQ34Z100::unseal() |
Jamie Smith |
0:6d09d3ad58aa | 174 | { |
Jamie Smith |
0:6d09d3ad58aa | 175 | //Follows the UNSEAL commands listed on page 21 of the datasheet |
Jamie Smith |
0:6d09d3ad58aa | 176 | //First sequence required to read DATA FLASH |
Jamie Smith |
0:6d09d3ad58aa | 177 | sendControlCommand(Control::UNSEAL_KEY1); |
Jamie Smith |
0:6d09d3ad58aa | 178 | sendControlCommand(Control::UNSEAL_KEY2); |
Jamie Smith |
0:6d09d3ad58aa | 179 | } |
Jamie Smith |
0:6d09d3ad58aa | 180 | |
Jamie Smith |
0:6d09d3ad58aa | 181 | void BQ34Z100::seal() |
Jamie Smith |
0:6d09d3ad58aa | 182 | { |
Jamie Smith |
0:6d09d3ad58aa | 183 | //Reseals the sensor, blocking access to certain flash registers |
Jamie Smith |
0:6d09d3ad58aa | 184 | //Would not recommend using this |
Jamie Smith |
0:6d09d3ad58aa | 185 | //See page 22 of the datasheet |
Jamie Smith |
0:6d09d3ad58aa | 186 | sendControlCommand(Control::SEALED); |
Jamie Smith |
0:6d09d3ad58aa | 187 | } |
Jamie Smith |
0:6d09d3ad58aa | 188 | |
Jamie Smith |
0:6d09d3ad58aa | 189 | //TODO: see if we can get away with taking the ThisThread::sleep_for away |
Jamie Smith |
0:6d09d3ad58aa | 190 | //as they will slow down the main Hamster loop |
Jamie Smith |
0:6d09d3ad58aa | 191 | void BQ34Z100::changePage(char subclass, uint16_t offset) |
Jamie Smith |
0:6d09d3ad58aa | 192 | { |
Jamie Smith |
0:6d09d3ad58aa | 193 | ThisThread::sleep_for(10ms); |
Jamie Smith |
0:6d09d3ad58aa | 194 | //Enable block data flash control (single byte write) |
Jamie Smith |
0:6d09d3ad58aa | 195 | write(Command::BlockDataControl, 0x00); |
Jamie Smith |
0:6d09d3ad58aa | 196 | ThisThread::sleep_for(10ms); |
Jamie Smith |
0:6d09d3ad58aa | 197 | |
Jamie Smith |
0:6d09d3ad58aa | 198 | //Use DataFlashClass() command to access the subclass |
Jamie Smith |
0:6d09d3ad58aa | 199 | write(Command::DataFlashClass, subclass); |
Jamie Smith |
0:6d09d3ad58aa | 200 | currFlashPage = subclass; |
Jamie Smith |
0:6d09d3ad58aa | 201 | ThisThread::sleep_for(10ms); |
Jamie Smith |
0:6d09d3ad58aa | 202 | |
Jamie Smith |
0:6d09d3ad58aa | 203 | //Select the block offset location |
Jamie Smith |
0:6d09d3ad58aa | 204 | //Blocks are 32 in size, so the offset is which block the data sits in |
Jamie Smith |
0:6d09d3ad58aa | 205 | //Ex: 16 is block 0x00, 52 is block 0x01 (called "index" variable) |
Jamie Smith |
0:6d09d3ad58aa | 206 | currFlashBlockIndex =(uint8_t)(offset/32); |
Jamie Smith |
0:6d09d3ad58aa | 207 | write(Command::DataFlashBlock, currFlashBlockIndex); |
Jamie Smith |
0:6d09d3ad58aa | 208 | ThisThread::sleep_for(20ms); |
Jamie Smith |
0:6d09d3ad58aa | 209 | } |
Jamie Smith |
0:6d09d3ad58aa | 210 | |
Jamie Smith |
0:6d09d3ad58aa | 211 | void BQ34Z100::updateChecksum() |
Jamie Smith |
0:6d09d3ad58aa | 212 | { |
Jamie Smith |
0:6d09d3ad58aa | 213 | |
Jamie Smith |
0:6d09d3ad58aa | 214 | uint8_t newChecksum = calcChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 215 | |
Jamie Smith |
0:6d09d3ad58aa | 216 | //Send new checksum thru I2C |
Jamie Smith |
0:6d09d3ad58aa | 217 | write(Command::BlockDataCheckSum, newChecksum); |
Jamie Smith |
0:6d09d3ad58aa | 218 | printf("Writing new checksum for page %" PRIu8 " block %" PRIu8 ": 0x%" PRIx8 "\r\n", currFlashPage, currFlashBlockIndex, newChecksum); |
Jamie Smith |
0:6d09d3ad58aa | 219 | |
Jamie Smith |
0:6d09d3ad58aa | 220 | ThisThread::sleep_for(50ms); //Wait for BQ34Z100 to process, may be totally overkill |
Jamie Smith |
0:6d09d3ad58aa | 221 | } |
Jamie Smith |
0:6d09d3ad58aa | 222 | |
Jamie Smith |
0:6d09d3ad58aa | 223 | |
Jamie Smith |
0:6d09d3ad58aa | 224 | //Warning: change page first before reading data |
Jamie Smith |
0:6d09d3ad58aa | 225 | //Copies a page in flash into the "flashbytes" array |
Jamie Smith |
0:6d09d3ad58aa | 226 | void BQ34Z100::readFlash() |
Jamie Smith |
0:6d09d3ad58aa | 227 | { |
Jamie Smith |
0:6d09d3ad58aa | 228 | //Request read flash |
Jamie Smith |
0:6d09d3ad58aa | 229 | _i2c.write(GAUGE_ADDRESS | 0); |
Jamie Smith |
0:6d09d3ad58aa | 230 | _i2c.write(static_cast<uint8_t>(Command::BlockData)); //Command to read Data Flash |
Jamie Smith |
0:6d09d3ad58aa | 231 | _i2c.stop(); |
Jamie Smith |
0:6d09d3ad58aa | 232 | |
Jamie Smith |
0:6d09d3ad58aa | 233 | _i2c.start(); |
Jamie Smith |
0:6d09d3ad58aa | 234 | _i2c.write(GAUGE_ADDRESS | 1); |
Jamie Smith |
0:6d09d3ad58aa | 235 | //Read all bytes from page (which is 32 bytes long) |
Jamie Smith |
0:6d09d3ad58aa | 236 | //_i2c.read(GAUGE_ADDRESS, reinterpret_cast<char*>(flashbytes), 32); |
Jamie Smith |
0:6d09d3ad58aa | 237 | for (int i = 0; i<32; i++) |
Jamie Smith |
0:6d09d3ad58aa | 238 | { |
Jamie Smith |
0:6d09d3ad58aa | 239 | //Store in flashbytes (memory) |
Jamie Smith |
0:6d09d3ad58aa | 240 | flashbytes[i] = _i2c.read(i < 31); |
Jamie Smith |
0:6d09d3ad58aa | 241 | } |
Jamie Smith |
0:6d09d3ad58aa | 242 | |
Jamie Smith |
0:6d09d3ad58aa | 243 | _i2c.stop(); |
Jamie Smith |
0:6d09d3ad58aa | 244 | |
Jamie Smith |
0:6d09d3ad58aa | 245 | uint8_t expectedChecksum = read(Command::BlockDataCheckSum, 1); |
Jamie Smith |
0:6d09d3ad58aa | 246 | |
Jamie Smith |
0:6d09d3ad58aa | 247 | if(expectedChecksum != calcChecksum()) |
Jamie Smith |
0:6d09d3ad58aa | 248 | { |
Jamie Smith |
0:6d09d3ad58aa | 249 | printf("ERROR: Checksum of flash memory block does not match. I2C read was likely corrupted."); |
Jamie Smith |
0:6d09d3ad58aa | 250 | } |
Jamie Smith |
0:6d09d3ad58aa | 251 | |
Jamie Smith |
0:6d09d3ad58aa | 252 | printf("Page %" PRIu8 " block %" PRIu8 " contents:", currFlashPage, currFlashBlockIndex); |
Jamie Smith |
0:6d09d3ad58aa | 253 | for(size_t byteIndex = 0; byteIndex < 32; ++byteIndex) |
Jamie Smith |
0:6d09d3ad58aa | 254 | { |
Jamie Smith |
0:6d09d3ad58aa | 255 | printf(" %" PRIx8, flashbytes[byteIndex]); |
Jamie Smith |
0:6d09d3ad58aa | 256 | } |
Jamie Smith |
0:6d09d3ad58aa | 257 | printf("\r\n"); |
Jamie Smith |
0:6d09d3ad58aa | 258 | printf("Checksum: 0x%" PRIx8 "\r\n", expectedChecksum); |
Jamie Smith |
0:6d09d3ad58aa | 259 | |
Jamie Smith |
0:6d09d3ad58aa | 260 | |
Jamie Smith |
0:6d09d3ad58aa | 261 | ThisThread::sleep_for(10ms); //Is this necessary? |
Jamie Smith |
0:6d09d3ad58aa | 262 | } |
Jamie Smith |
0:6d09d3ad58aa | 263 | |
Jamie Smith |
0:6d09d3ad58aa | 264 | //Writes new data, first to flashbytes array, then updates on the sensor as well |
Jamie Smith |
0:6d09d3ad58aa | 265 | //Note: Requires update of the checksum after changes are made |
Jamie Smith |
0:6d09d3ad58aa | 266 | //See pg. 25 of datasheet for reference |
Jamie Smith |
0:6d09d3ad58aa | 267 | //Input: subclass ID (index) |
Jamie Smith |
0:6d09d3ad58aa | 268 | //Input: offset |
Jamie Smith |
0:6d09d3ad58aa | 269 | //Input: length of write |
Jamie Smith |
0:6d09d3ad58aa | 270 | void BQ34Z100::writeFlash(uint8_t index, uint32_t value, int len) |
Jamie Smith |
0:6d09d3ad58aa | 271 | { |
Jamie Smith |
0:6d09d3ad58aa | 272 | //Has to be a number between 0 to 31 |
Jamie Smith |
0:6d09d3ad58aa | 273 | //Use changePage to set the offset correctly beforehand |
Jamie Smith |
0:6d09d3ad58aa | 274 | if (index > 31) index = index % 32; |
Jamie Smith |
0:6d09d3ad58aa | 275 | |
Jamie Smith |
0:6d09d3ad58aa | 276 | //Write to I2C bus and change flashbytes at the same time |
Jamie Smith |
0:6d09d3ad58aa | 277 | //Necessary for checksum calculation at the end |
Jamie Smith |
0:6d09d3ad58aa | 278 | if (len == 1) |
Jamie Smith |
0:6d09d3ad58aa | 279 | { |
Jamie Smith |
0:6d09d3ad58aa | 280 | flashbytes[index] = value; |
Jamie Smith |
0:6d09d3ad58aa | 281 | write(static_cast<Command>(static_cast<uint8_t>(Command::BlockData) + index), (unsigned char)value); |
Jamie Smith |
0:6d09d3ad58aa | 282 | printf("Flash[%d] <- 0x%" PRIx8 "\n", index, flashbytes[index]); |
Jamie Smith |
0:6d09d3ad58aa | 283 | |
Jamie Smith |
0:6d09d3ad58aa | 284 | } else if (len > 1) |
Jamie Smith |
0:6d09d3ad58aa | 285 | { |
Jamie Smith |
0:6d09d3ad58aa | 286 | //Process every byte except the last |
Jamie Smith |
0:6d09d3ad58aa | 287 | for (int i = 0; i<len-1; i++) |
Jamie Smith |
0:6d09d3ad58aa | 288 | { |
Jamie Smith |
0:6d09d3ad58aa | 289 | flashbytes[index+i] = value >> 8*((len-1)-i); |
Jamie Smith |
0:6d09d3ad58aa | 290 | printf("Flash[%d] <- 0x%" PRIx8 "\n", index + i, flashbytes[index+i]); |
Jamie Smith |
0:6d09d3ad58aa | 291 | write(static_cast<Command>(static_cast<uint8_t>(Command::BlockData) + index + i), flashbytes[index+i]); |
Jamie Smith |
0:6d09d3ad58aa | 292 | } |
Jamie Smith |
0:6d09d3ad58aa | 293 | |
Jamie Smith |
0:6d09d3ad58aa | 294 | //Last byte (lower byte) |
Jamie Smith |
0:6d09d3ad58aa | 295 | flashbytes[index+len-1] = value & 0xFF; |
Jamie Smith |
0:6d09d3ad58aa | 296 | printf("Flash[%d] <- 0x%" PRIx8 "\n", index + (len - 1), flashbytes[index+len-1]); |
Jamie Smith |
0:6d09d3ad58aa | 297 | write(static_cast<Command>(static_cast<uint8_t>(Command::BlockData) + index + len - 1), value & 0xFF); |
Jamie Smith |
0:6d09d3ad58aa | 298 | } |
Jamie Smith |
0:6d09d3ad58aa | 299 | } |
Jamie Smith |
0:6d09d3ad58aa | 300 | |
Jamie Smith |
0:6d09d3ad58aa | 301 | uint8_t* BQ34Z100::getFlashBytes() |
Jamie Smith |
0:6d09d3ad58aa | 302 | { |
Jamie Smith |
0:6d09d3ad58aa | 303 | return flashbytes; |
Jamie Smith |
0:6d09d3ad58aa | 304 | } |
Jamie Smith |
0:6d09d3ad58aa | 305 | |
Jamie Smith |
0:6d09d3ad58aa | 306 | //Edits the design capacity and design energy of the battery |
Jamie Smith |
0:6d09d3ad58aa | 307 | void BQ34Z100::changePage48() |
Jamie Smith |
0:6d09d3ad58aa | 308 | { |
Jamie Smith |
0:6d09d3ad58aa | 309 | changePage(48, 0); //Block 48, offset 0 |
Jamie Smith |
0:6d09d3ad58aa | 310 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 311 | writeFlash(11, DESIGNCAP, 2); |
Jamie Smith |
0:6d09d3ad58aa | 312 | writeFlash(13, DESIGNENERGY, 2); |
Jamie Smith |
0:6d09d3ad58aa | 313 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 314 | ThisThread::sleep_for(300ms); |
Jamie Smith |
0:6d09d3ad58aa | 315 | } |
Jamie Smith |
0:6d09d3ad58aa | 316 | |
Jamie Smith |
0:6d09d3ad58aa | 317 | //This function sets certain settings, such as enabling the external voltage divider, |
Jamie Smith |
0:6d09d3ad58aa | 318 | //enablibg calibration, enabling internal temp sensor, and setting the number of cells in the bat. |
Jamie Smith |
0:6d09d3ad58aa | 319 | //and selecting the correct LED config mode |
Jamie Smith |
0:6d09d3ad58aa | 320 | void BQ34Z100::changePage64() |
Jamie Smith |
0:6d09d3ad58aa | 321 | { |
Jamie Smith |
0:6d09d3ad58aa | 322 | changePage(64, 0); //Block 64, offset 0 |
Jamie Smith |
0:6d09d3ad58aa | 323 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 324 | |
Jamie Smith |
0:6d09d3ad58aa | 325 | //Edit pack configuration register (has an upper and lower byte) |
Jamie Smith |
0:6d09d3ad58aa | 326 | //Enables external voltage divider use |
Jamie Smith |
0:6d09d3ad58aa | 327 | uint8_t packConfig_high = flashbytes[0]; |
Jamie Smith |
0:6d09d3ad58aa | 328 | uint8_t packConfig_low = flashbytes[1]; |
Jamie Smith |
0:6d09d3ad58aa | 329 | if (VOLTSEL) |
Jamie Smith |
0:6d09d3ad58aa | 330 | { |
Jamie Smith |
0:6d09d3ad58aa | 331 | packConfig_high |= 0x08; //00001000 |
Jamie Smith |
0:6d09d3ad58aa | 332 | } |
Jamie Smith |
0:6d09d3ad58aa | 333 | |
Jamie Smith |
0:6d09d3ad58aa | 334 | //Also allow calibration by switching the CAL_EN bit to 1 |
Jamie Smith |
0:6d09d3ad58aa | 335 | packConfig_high |= 0x40; //01000000 |
Jamie Smith |
0:6d09d3ad58aa | 336 | |
Jamie Smith |
0:6d09d3ad58aa | 337 | //Set temps bit. |
Jamie Smith |
0:6d09d3ad58aa | 338 | packConfig_low &= ~(1); |
Jamie Smith |
0:6d09d3ad58aa | 339 | packConfig_low |= USE_EXTERNAL_THERMISTOR; |
Jamie Smith |
0:6d09d3ad58aa | 340 | |
Jamie Smith |
0:6d09d3ad58aa | 341 | writeFlash(0, packConfig_high, 1); |
Jamie Smith |
0:6d09d3ad58aa | 342 | writeFlash(1, packConfig_low, 1); |
Jamie Smith |
0:6d09d3ad58aa | 343 | |
Jamie Smith |
0:6d09d3ad58aa | 344 | // Disable fast convergence as recommended in the calibration procedure |
Jamie Smith |
0:6d09d3ad58aa | 345 | uint8_t packConfigB = flashbytes[2]; |
Jamie Smith |
0:6d09d3ad58aa | 346 | packConfigB &= ~1; |
Jamie Smith |
0:6d09d3ad58aa | 347 | writeFlash(2, packConfigB, 1); |
Jamie Smith |
0:6d09d3ad58aa | 348 | |
Jamie Smith |
0:6d09d3ad58aa | 349 | //Update LED config and number of cells in battery |
Jamie Smith |
0:6d09d3ad58aa | 350 | writeFlash(4, LEDCONFIG, 1); |
Jamie Smith |
0:6d09d3ad58aa | 351 | writeFlash(7, 0x04, 1); |
Jamie Smith |
0:6d09d3ad58aa | 352 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 353 | ThisThread::sleep_for(300ms); |
Jamie Smith |
0:6d09d3ad58aa | 354 | } |
Jamie Smith |
0:6d09d3ad58aa | 355 | |
Jamie Smith |
0:6d09d3ad58aa | 356 | void BQ34Z100::changePage80() |
Jamie Smith |
0:6d09d3ad58aa | 357 | { |
Jamie Smith |
0:6d09d3ad58aa | 358 | changePage(80, 0); |
Jamie Smith |
0:6d09d3ad58aa | 359 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 360 | |
Jamie Smith |
0:6d09d3ad58aa | 361 | writeFlash(0, LOADSELECT, 1); |
Jamie Smith |
0:6d09d3ad58aa | 362 | writeFlash(1, LOADMODE, 1); |
Jamie Smith |
0:6d09d3ad58aa | 363 | writeFlash(10, 10, 2); |
Jamie Smith |
0:6d09d3ad58aa | 364 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 365 | ThisThread::sleep_for(300ms); |
Jamie Smith |
0:6d09d3ad58aa | 366 | |
Jamie Smith |
0:6d09d3ad58aa | 367 | changePage(80, 53); |
Jamie Smith |
0:6d09d3ad58aa | 368 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 369 | //Update cell terminate voltage |
Jamie Smith |
0:6d09d3ad58aa | 370 | writeFlash(53, ZEROCHARGEVOLT, 2); |
Jamie Smith |
0:6d09d3ad58aa | 371 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 372 | ThisThread::sleep_for(300ms); |
Jamie Smith |
0:6d09d3ad58aa | 373 | } |
Jamie Smith |
0:6d09d3ad58aa | 374 | |
Jamie Smith |
0:6d09d3ad58aa | 375 | void BQ34Z100::changePage82() |
Jamie Smith |
0:6d09d3ad58aa | 376 | { |
Jamie Smith |
0:6d09d3ad58aa | 377 | changePage(82, 0); |
Jamie Smith |
0:6d09d3ad58aa | 378 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 379 | //Update QMax cell 0 |
Jamie Smith |
0:6d09d3ad58aa | 380 | writeFlash(0, QMAX0, 2); |
Jamie Smith |
0:6d09d3ad58aa | 381 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 382 | ThisThread::sleep_for(300ms); |
Jamie Smith |
0:6d09d3ad58aa | 383 | } |
Jamie Smith |
0:6d09d3ad58aa | 384 | |
Jamie Smith |
0:6d09d3ad58aa | 385 | //Input: The actual battery voltage, measure with multimeter (mV) |
Jamie Smith |
0:6d09d3ad58aa | 386 | //Output: The new voltage divider ratio written |
Jamie Smith |
0:6d09d3ad58aa | 387 | uint16_t BQ34Z100::calibrateVoltage(uint16_t currentVoltage) |
Jamie Smith |
0:6d09d3ad58aa | 388 | { |
Jamie Smith |
0:6d09d3ad58aa | 389 | changePage(104, 0); |
Jamie Smith |
0:6d09d3ad58aa | 390 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 391 | //Gets the voltage divider value stored in flash |
Jamie Smith |
0:6d09d3ad58aa | 392 | uint16_t flashVoltage = (uint16_t)(flashbytes[14] << 8); |
Jamie Smith |
0:6d09d3ad58aa | 393 | flashVoltage |= (uint16_t)(flashbytes[15]); |
Jamie Smith |
0:6d09d3ad58aa | 394 | |
Jamie Smith |
0:6d09d3ad58aa | 395 | float readVoltage = (float)getVoltage(); |
Jamie Smith |
0:6d09d3ad58aa | 396 | float newSetting = ((float)(currentVoltage)/readVoltage)*(float)(flashVoltage); |
Jamie Smith |
0:6d09d3ad58aa | 397 | uint16_t writeSetting; //This 2 byte integer will be written to chip |
Jamie Smith |
0:6d09d3ad58aa | 398 | if (newSetting>65535.0f) writeSetting=65535; |
Jamie Smith |
0:6d09d3ad58aa | 399 | else if (newSetting < 0.0f) writeSetting=0; |
Jamie Smith |
0:6d09d3ad58aa | 400 | else writeSetting=(uint16_t)(newSetting); |
Jamie Smith |
0:6d09d3ad58aa | 401 | writeFlash(14, writeSetting, 2); |
Jamie Smith |
0:6d09d3ad58aa | 402 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 403 | ThisThread::sleep_for(10ms); |
Jamie Smith |
0:6d09d3ad58aa | 404 | |
Jamie Smith |
0:6d09d3ad58aa | 405 | // also change the "Flash Update OK Cell Volt" as the datasheet says to: |
Jamie Smith |
0:6d09d3ad58aa | 406 | changePage(68, 0); |
Jamie Smith |
0:6d09d3ad58aa | 407 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 408 | |
Jamie Smith |
0:6d09d3ad58aa | 409 | int16_t oldUpdateOK = 0; |
Jamie Smith |
0:6d09d3ad58aa | 410 | oldUpdateOK |= (static_cast<uint16_t>(flashbytes[0]) << 8); |
Jamie Smith |
0:6d09d3ad58aa | 411 | oldUpdateOK |= flashbytes[1]; |
Jamie Smith |
0:6d09d3ad58aa | 412 | |
Jamie Smith |
0:6d09d3ad58aa | 413 | int16_t newUpdateOK = static_cast<int16_t>(round(FLASH_UPDATE_OK_VOLT * CELLCOUNT * (5000.0f/writeSetting))); |
Jamie Smith |
0:6d09d3ad58aa | 414 | printf("Changing Flash Update OK Voltage from %" PRIi16 " to %" PRIi16 "\r\n", oldUpdateOK, newUpdateOK); |
Jamie Smith |
0:6d09d3ad58aa | 415 | |
Jamie Smith |
0:6d09d3ad58aa | 416 | writeFlash(0, newUpdateOK, 2); |
Jamie Smith |
0:6d09d3ad58aa | 417 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 418 | |
Jamie Smith |
0:6d09d3ad58aa | 419 | //Test output |
Jamie Smith |
0:6d09d3ad58aa | 420 | printf("Register (voltage divider): %d\r\n", flashVoltage); |
Jamie Smith |
0:6d09d3ad58aa | 421 | printf("New Ratio: %f\r\n", ((float)(currentVoltage)/readVoltage)); |
Jamie Smith |
0:6d09d3ad58aa | 422 | printf("READ VOLTAGE (mv): %f\r\n", readVoltage); |
Jamie Smith |
0:6d09d3ad58aa | 423 | return (uint16_t)newSetting; |
Jamie Smith |
0:6d09d3ad58aa | 424 | } |
Jamie Smith |
0:6d09d3ad58aa | 425 | |
Jamie Smith |
0:6d09d3ad58aa | 426 | //If too much calibration is done, you may want to reset the Voltage divider |
Jamie Smith |
0:6d09d3ad58aa | 427 | //Sets voltage divider register to custom value (in mV) |
Jamie Smith |
0:6d09d3ad58aa | 428 | //Recommended: 1.5x the current battery voltage |
Jamie Smith |
0:6d09d3ad58aa | 429 | void BQ34Z100::setVoltageDivider(uint16_t newVoltage) |
Jamie Smith |
0:6d09d3ad58aa | 430 | { |
Jamie Smith |
0:6d09d3ad58aa | 431 | changePage(104, 0); |
Jamie Smith |
0:6d09d3ad58aa | 432 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 433 | writeFlash(14, newVoltage, 2); |
Jamie Smith |
0:6d09d3ad58aa | 434 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 435 | ThisThread::sleep_for(300ms); |
Jamie Smith |
0:6d09d3ad58aa | 436 | } |
Jamie Smith |
0:6d09d3ad58aa | 437 | |
Jamie Smith |
0:6d09d3ad58aa | 438 | //Calibrates the current output to match the calibration current input (calCurrent) |
Jamie Smith |
0:6d09d3ad58aa | 439 | void BQ34Z100::calibrateShunt(int16_t calCurrent) |
Jamie Smith |
0:6d09d3ad58aa | 440 | { |
Jamie Smith |
0:6d09d3ad58aa | 441 | if (calCurrent < 0) calCurrent = -calCurrent; |
Jamie Smith |
0:6d09d3ad58aa | 442 | |
Jamie Smith |
0:6d09d3ad58aa | 443 | int16_t currentReading = getCurrent(); |
Jamie Smith |
0:6d09d3ad58aa | 444 | if (currentReading < 0) currentReading = -currentReading; |
Jamie Smith |
0:6d09d3ad58aa | 445 | |
Jamie Smith |
0:6d09d3ad58aa | 446 | changePage(104, 0); |
Jamie Smith |
0:6d09d3ad58aa | 447 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 448 | ThisThread::sleep_for(30ms); |
Jamie Smith |
0:6d09d3ad58aa | 449 | |
Jamie Smith |
0:6d09d3ad58aa | 450 | // read and convert CC Gain |
Jamie Smith |
0:6d09d3ad58aa | 451 | uint32_t currentGainDF = ((uint32_t)flashbytes[0]) << 24 | ((uint32_t)flashbytes[1]) << 16 | ((uint32_t)flashbytes[2]) << 8 | (uint32_t)flashbytes[3]; |
Jamie Smith |
0:6d09d3ad58aa | 452 | float currentGainResistance = (4.768f/xemicsToFloat(currentGainDF)); |
Jamie Smith |
0:6d09d3ad58aa | 453 | |
Jamie Smith |
0:6d09d3ad58aa | 454 | uint32_t currentDeltaDF = ((uint32_t)flashbytes[4]) << 24 | ((uint32_t)flashbytes[5]) << 16 | ((uint32_t)flashbytes[6]) << 8 | (uint32_t)flashbytes[7]; |
Jamie Smith |
0:6d09d3ad58aa | 455 | float currentDeltaResistance = (5677445/xemicsToFloat(currentGainDF)); |
Jamie Smith |
0:6d09d3ad58aa | 456 | |
Jamie Smith |
0:6d09d3ad58aa | 457 | float newGain = (((float)currentReading)/((float)calCurrent)) * currentGainResistance; |
Jamie Smith |
0:6d09d3ad58aa | 458 | |
Jamie Smith |
0:6d09d3ad58aa | 459 | uint32_t newGainDF = floatToXemics(4.768 / newGain); |
Jamie Smith |
0:6d09d3ad58aa | 460 | float DeltaDF = floatToXemics(5677445/newGain); |
Jamie Smith |
0:6d09d3ad58aa | 461 | |
Jamie Smith |
0:6d09d3ad58aa | 462 | printf("currentGainDF = 0x%" PRIx32 ", currentGainResistance = %f, currentDeltaDF = %" PRIx32 ", currentDeltaResistance = %f, newGain = %f, newGainDF = 0x%" PRIx32 "\n", |
Jamie Smith |
0:6d09d3ad58aa | 463 | currentGainDF, currentGainResistance, currentDeltaDF, currentDeltaResistance, newGain, newGainDF); |
Jamie Smith |
0:6d09d3ad58aa | 464 | |
Jamie Smith |
0:6d09d3ad58aa | 465 | writeFlash(0, newGainDF, 4); |
Jamie Smith |
0:6d09d3ad58aa | 466 | writeFlash(4, DeltaDF, 4); |
Jamie Smith |
0:6d09d3ad58aa | 467 | |
Jamie Smith |
0:6d09d3ad58aa | 468 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 469 | ThisThread::sleep_for(300ms); |
Jamie Smith |
0:6d09d3ad58aa | 470 | } |
Jamie Smith |
0:6d09d3ad58aa | 471 | |
Jamie Smith |
0:6d09d3ad58aa | 472 | void BQ34Z100::setSenseResistor() { |
Jamie Smith |
0:6d09d3ad58aa | 473 | changePage(104, 0); |
Jamie Smith |
0:6d09d3ad58aa | 474 | ThisThread::sleep_for(30ms); |
Jamie Smith |
0:6d09d3ad58aa | 475 | |
Jamie Smith |
0:6d09d3ad58aa | 476 | //Constants use to convert mOhm to the BQ34Z100 data flash units |
Jamie Smith |
0:6d09d3ad58aa | 477 | uint32_t GainDF = floatToXemics(/*4.768/SENSE_RES*/0.4768); |
Jamie Smith |
0:6d09d3ad58aa | 478 | uint32_t DeltaDF = floatToXemics(5677445/SENSE_RES); |
Jamie Smith |
0:6d09d3ad58aa | 479 | writeFlash(0, GainDF, 4); |
Jamie Smith |
0:6d09d3ad58aa | 480 | writeFlash(4, DeltaDF, 4); |
Jamie Smith |
0:6d09d3ad58aa | 481 | |
Jamie Smith |
0:6d09d3ad58aa | 482 | printf("newGain = %f, GainDF = 0x%" PRIx32 "\n", |
Jamie Smith |
0:6d09d3ad58aa | 483 | SENSE_RES, GainDF); |
Jamie Smith |
0:6d09d3ad58aa | 484 | |
Jamie Smith |
0:6d09d3ad58aa | 485 | updateChecksum(); |
Jamie Smith |
0:6d09d3ad58aa | 486 | ThisThread::sleep_for(300ms); |
Jamie Smith |
0:6d09d3ad58aa | 487 | } |
Jamie Smith |
0:6d09d3ad58aa | 488 | |
Jamie Smith |
0:6d09d3ad58aa | 489 | uint16_t BQ34Z100::readDeviceType() |
Jamie Smith |
0:6d09d3ad58aa | 490 | { |
Jamie Smith |
0:6d09d3ad58aa | 491 | return readControlCommand(Control::DEVICE_TYPE); |
Jamie Smith |
0:6d09d3ad58aa | 492 | } |
Jamie Smith |
0:6d09d3ad58aa | 493 | |
Jamie Smith |
0:6d09d3ad58aa | 494 | uint16_t BQ34Z100::readFWVersion() { |
Jamie Smith |
0:6d09d3ad58aa | 495 | return readControlCommand(Control::FW_VERSION); |
Jamie Smith |
0:6d09d3ad58aa | 496 | } |
Jamie Smith |
0:6d09d3ad58aa | 497 | |
Jamie Smith |
0:6d09d3ad58aa | 498 | uint16_t BQ34Z100::readHWVersion() { |
Jamie Smith |
0:6d09d3ad58aa | 499 | return readControlCommand(Control::HW_VERSION); |
Jamie Smith |
0:6d09d3ad58aa | 500 | } |
Jamie Smith |
0:6d09d3ad58aa | 501 | |
Jamie Smith |
0:6d09d3ad58aa | 502 | uint8_t BQ34Z100::calcChecksum() { |
Jamie Smith |
0:6d09d3ad58aa | 503 | uint8_t chkSum = 0; |
Jamie Smith |
0:6d09d3ad58aa | 504 | //Perform 8 bit summation of the entire BlockData() on byte-per-byte |
Jamie Smith |
0:6d09d3ad58aa | 505 | //basis. Checksum = (255-sum) |
Jamie Smith |
0:6d09d3ad58aa | 506 | //For every byte in flashbytes, add to sum |
Jamie Smith |
0:6d09d3ad58aa | 507 | for (int i = 0; i<32; i++) |
Jamie Smith |
0:6d09d3ad58aa | 508 | { |
Jamie Smith |
0:6d09d3ad58aa | 509 | chkSum += flashbytes[i]; |
Jamie Smith |
0:6d09d3ad58aa | 510 | } |
Jamie Smith |
0:6d09d3ad58aa | 511 | |
Jamie Smith |
0:6d09d3ad58aa | 512 | chkSum = 255 - chkSum; |
Jamie Smith |
0:6d09d3ad58aa | 513 | |
Jamie Smith |
0:6d09d3ad58aa | 514 | return chkSum; |
Jamie Smith |
0:6d09d3ad58aa | 515 | } |
Jamie Smith |
0:6d09d3ad58aa | 516 | |
Jamie Smith |
0:6d09d3ad58aa | 517 | uint32_t BQ34Z100::floatToXemics(float value) { |
Jamie Smith |
0:6d09d3ad58aa | 518 | int iByte1, iByte2, iByte3, iByte4, iExp; |
Jamie Smith |
0:6d09d3ad58aa | 519 | bool bNegative = false; |
Jamie Smith |
0:6d09d3ad58aa | 520 | float fMantissa; |
Jamie Smith |
0:6d09d3ad58aa | 521 | // Don't blow up with logs of zero |
Jamie Smith |
0:6d09d3ad58aa | 522 | if (value == 0) value = 0.00001F; |
Jamie Smith |
0:6d09d3ad58aa | 523 | if (value < 0) |
Jamie Smith |
0:6d09d3ad58aa | 524 | { |
Jamie Smith |
0:6d09d3ad58aa | 525 | bNegative = true; |
Jamie Smith |
0:6d09d3ad58aa | 526 | value = -value; |
Jamie Smith |
0:6d09d3ad58aa | 527 | } |
Jamie Smith |
0:6d09d3ad58aa | 528 | // find the correct exponent |
Jamie Smith |
0:6d09d3ad58aa | 529 | iExp = (int)((log(value) / log(2)) + 1);// remember - log of any base is ln(x)/ln(base) |
Jamie Smith |
0:6d09d3ad58aa | 530 | |
Jamie Smith |
0:6d09d3ad58aa | 531 | // MS byte is the exponent + 0x80 |
Jamie Smith |
0:6d09d3ad58aa | 532 | iByte1 = iExp + 128; |
Jamie Smith |
0:6d09d3ad58aa | 533 | |
Jamie Smith |
0:6d09d3ad58aa | 534 | // Divide input by this exponent to get mantissa |
Jamie Smith |
0:6d09d3ad58aa | 535 | fMantissa = value / (pow(2, iExp)); |
Jamie Smith |
0:6d09d3ad58aa | 536 | |
Jamie Smith |
0:6d09d3ad58aa | 537 | // Scale it up |
Jamie Smith |
0:6d09d3ad58aa | 538 | fMantissa = fMantissa / (pow(2, -24)); |
Jamie Smith |
0:6d09d3ad58aa | 539 | |
Jamie Smith |
0:6d09d3ad58aa | 540 | // Split the mantissa into 3 bytes |
Jamie Smith |
0:6d09d3ad58aa | 541 | iByte2 = (int)(fMantissa / (pow(2, 16))); |
Jamie Smith |
0:6d09d3ad58aa | 542 | |
Jamie Smith |
0:6d09d3ad58aa | 543 | iByte3 = (int)((fMantissa - (iByte2 * (pow(2, 16)))) / (pow(2, 8))); |
Jamie Smith |
0:6d09d3ad58aa | 544 | |
Jamie Smith |
0:6d09d3ad58aa | 545 | iByte4 = (int)(fMantissa - (iByte2 * (pow(2, 16))) - (iByte3 * (pow(2, 8)))); |
Jamie Smith |
0:6d09d3ad58aa | 546 | |
Jamie Smith |
0:6d09d3ad58aa | 547 | // subtract the sign bit if number is positive |
Jamie Smith |
0:6d09d3ad58aa | 548 | if (bNegative == false) |
Jamie Smith |
0:6d09d3ad58aa | 549 | { |
Jamie Smith |
0:6d09d3ad58aa | 550 | iByte2 = iByte2 & 0x7F; |
Jamie Smith |
0:6d09d3ad58aa | 551 | } |
Jamie Smith |
0:6d09d3ad58aa | 552 | return (uint32_t)((uint32_t)iByte1 << 24 | (uint32_t)iByte2 << 16 | (uint32_t)iByte3 << 8 | (uint32_t)iByte4); |
Jamie Smith |
0:6d09d3ad58aa | 553 | } |
Jamie Smith |
0:6d09d3ad58aa | 554 | |
Jamie Smith |
0:6d09d3ad58aa | 555 | float BQ34Z100::xemicsToFloat(uint32_t xemics) |
Jamie Smith |
0:6d09d3ad58aa | 556 | { |
Jamie Smith |
0:6d09d3ad58aa | 557 | bool bIsPositive = false; |
Jamie Smith |
0:6d09d3ad58aa | 558 | float fExponent, fResult; |
Jamie Smith |
0:6d09d3ad58aa | 559 | uint8_t vMSByte = (uint8_t)(xemics >> 24); |
Jamie Smith |
0:6d09d3ad58aa | 560 | uint8_t vMidHiByte = (uint8_t)(xemics >> 16); |
Jamie Smith |
0:6d09d3ad58aa | 561 | uint8_t vMidLoByte = (uint8_t)(xemics >> 8); |
Jamie Smith |
0:6d09d3ad58aa | 562 | uint8_t vLSByte = (uint8_t)xemics; |
Jamie Smith |
0:6d09d3ad58aa | 563 | // Get the sign, its in the 0x00 80 00 00 bit |
Jamie Smith |
0:6d09d3ad58aa | 564 | if ((vMidHiByte & 128) == 0) |
Jamie Smith |
0:6d09d3ad58aa | 565 | { bIsPositive = true; } |
Jamie Smith |
0:6d09d3ad58aa | 566 | |
Jamie Smith |
0:6d09d3ad58aa | 567 | // Get the exponent, it's 2^(MSbyte - 0x80) |
Jamie Smith |
0:6d09d3ad58aa | 568 | fExponent = pow(2, (vMSByte - 128)); |
Jamie Smith |
0:6d09d3ad58aa | 569 | // Or in 0x80 to the MidHiByte |
Jamie Smith |
0:6d09d3ad58aa | 570 | vMidHiByte = (uint8_t)(vMidHiByte | 128); |
Jamie Smith |
0:6d09d3ad58aa | 571 | // get value out of midhi byte |
Jamie Smith |
0:6d09d3ad58aa | 572 | fResult = (vMidHiByte) * 65536; |
Jamie Smith |
0:6d09d3ad58aa | 573 | // add in midlow byte |
Jamie Smith |
0:6d09d3ad58aa | 574 | fResult = fResult + (vMidLoByte * 256); |
Jamie Smith |
0:6d09d3ad58aa | 575 | // add in LS byte |
Jamie Smith |
0:6d09d3ad58aa | 576 | fResult = fResult + vLSByte; |
Jamie Smith |
0:6d09d3ad58aa | 577 | // multiply by 2^-24 to get the actual fraction |
Jamie Smith |
0:6d09d3ad58aa | 578 | fResult = fResult * pow(2, -24); |
Jamie Smith |
0:6d09d3ad58aa | 579 | // multiply fraction by the ‘exponent’ part |
Jamie Smith |
0:6d09d3ad58aa | 580 | fResult = fResult * fExponent; |
Jamie Smith |
0:6d09d3ad58aa | 581 | // Make negative if necessary |
Jamie Smith |
0:6d09d3ad58aa | 582 | if (bIsPositive) |
Jamie Smith |
0:6d09d3ad58aa | 583 | return fResult; |
Jamie Smith |
0:6d09d3ad58aa | 584 | else |
Jamie Smith |
0:6d09d3ad58aa | 585 | return -fResult; |
Jamie Smith |
0:6d09d3ad58aa | 586 | } |
Jamie Smith |
0:6d09d3ad58aa | 587 | |
Jamie Smith |
0:6d09d3ad58aa | 588 | uint8_t BQ34Z100::getUpdateStatus() { |
Jamie Smith |
0:6d09d3ad58aa | 589 | changePage(82, 0); |
Jamie Smith |
0:6d09d3ad58aa | 590 | readFlash(); |
Jamie Smith |
0:6d09d3ad58aa | 591 | return flashbytes[4]; |
Jamie Smith |
0:6d09d3ad58aa | 592 | } |
Jamie Smith |
0:6d09d3ad58aa | 593 | |
Jamie Smith |
0:6d09d3ad58aa | 594 | std::pair<uint16_t, uint16_t> BQ34Z100::getFlags() { |
Jamie Smith |
0:6d09d3ad58aa | 595 | uint16_t flags = read(Command::Flags, 2); |
Jamie Smith |
0:6d09d3ad58aa | 596 | uint16_t flagsB = read(Command::FlagsB, 2); |
Jamie Smith |
0:6d09d3ad58aa | 597 | return std::make_pair(flags, flagsB); |
Jamie Smith |
0:6d09d3ad58aa | 598 | } |