Driver for Texas Instruments' battery state-of-charge estimator.

Dependents:   BQ34Z100G1-Utils BQ34Z100G1-ChemIDMeasurer

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.

Committer:
Jamie Smith
Date:
Sun Feb 07 20:36:23 2021 -0800
Revision:
1:6483d36150c3
Parent:
0:6d09d3ad58aa
Fix some inaccurate comments

Who changed what in which revision?

UserRevisionLine numberNew 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 }