Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: example-battery-gauge-bq35100
bq35100.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017 u-blox 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 /** 00018 * @file bq35100.cpp 00019 * This file defines the API to the TI BQ35100 battery gauge chip. 00020 */ 00021 00022 /** Define these to print debug information. */ 00023 //#define DEBUG_BQ35100 00024 //#define DEBUG_BQ35100_BLOCK_DATA 00025 00026 #include <mbed.h> 00027 #include <battery_gauge_bq35100.h> 00028 00029 #ifdef DEBUG_BQ35100 00030 # include <stdio.h> 00031 #endif 00032 00033 // ---------------------------------------------------------------- 00034 // COMPILE-TIME MACROS 00035 // ---------------------------------------------------------------- 00036 00037 /** How long to wait for a security mode change to succeed. */ 00038 #define SET_SECURITY_MODE_RETRY_SECONDS 5 00039 00040 /** How long to wait for accumulated capacity data to be written 00041 * to data flash when gauging is disabled */ 00042 #define GAUGE_COMPLETE_WAIT_MS 10000 00043 00044 // ---------------------------------------------------------------- 00045 // GENERIC PRIVATE FUNCTIONS 00046 // ---------------------------------------------------------------- 00047 00048 // Read two bytes from an address. 00049 // Note: gpI2c should be locked before this is called. 00050 bool BatteryGaugeBq35100::getTwoBytes(uint8_t registerAddress, uint16_t *pBytes) 00051 { 00052 bool success = false; 00053 char data[3]; 00054 00055 if (gpI2c != NULL) { 00056 data[0] = registerAddress; 00057 data[1] = 0; 00058 data[2] = 0; 00059 00060 // Send a command to read from registerAddress 00061 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) && 00062 (gpI2c->read(gAddress, &(data[1]), 2) == 0)) { 00063 success = true; 00064 if (pBytes) { 00065 *pBytes = (((uint16_t) data[2]) << 8) + data[1]; 00066 } 00067 } 00068 } 00069 00070 return success; 00071 } 00072 00073 // Compute the checksum over an address plus the block of data. 00074 uint8_t BatteryGaugeBq35100::computeChecksum(const char * pData, int32_t length) 00075 { 00076 uint8_t checkSum = 0; 00077 uint8_t x = 0; 00078 00079 if (pData != NULL) { 00080 #ifdef DEBUG_BQ35100_BLOCK_DATA 00081 printf ("BatteryGaugeBq35100 (I2C 0x%02x): computing check sum on data block.\n", gAddress >> 1); 00082 printf (" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); 00083 #endif 00084 for (x = 1; x <= length; x++) { 00085 checkSum += *pData; 00086 00087 #ifdef DEBUG_BQ35100_BLOCK_DATA 00088 if (x % 16 == 8) { 00089 printf ("%02x ", *pData); 00090 } else if (x % 16 == 0) { 00091 printf ("%02x\n", *pData); 00092 } else { 00093 printf ("%02x-", *pData); 00094 } 00095 #endif 00096 pData++; 00097 } 00098 00099 checkSum = 0xff - checkSum; 00100 } 00101 00102 #ifdef DEBUG_BQ35100_BLOCK_DATA 00103 if (x % 16 != 1) { 00104 printf("\n"); 00105 } 00106 00107 printf ("BatteryGaugeBq35100 (I2C 0x%02x): check sum is 0x%02x.\n", gAddress >> 1, checkSum); 00108 #endif 00109 00110 return checkSum; 00111 } 00112 00113 // Read data of a given length from a given address. 00114 // Note: gpI2c should be locked before this is called. 00115 bool BatteryGaugeBq35100::readExtendedData(int32_t address, char * pData, int32_t length) 00116 { 00117 int32_t lengthRead; 00118 bool success = false; 00119 SecurityMode securityMode = getSecurityMode(); 00120 char block[32 + 2 + 2]; // 32 bytes of data, 2 bytes of address, 00121 // 1 byte of MACDataSum and 1 byte of MACDataLen 00122 char data[3]; 00123 00124 // Handle security mode 00125 if (setSecurityMode(SECURITY_MODE_UNSEALED)) { 00126 if ((gpI2c != NULL) && (length <= 32) && (address >= 0x4000) && (address < 0x4400) && (pData != NULL)) { 00127 #ifdef DEBUG_BQ35100 00128 printf("BatteryGaugeBq35100 (I2C 0x%02x): preparing to read %d byte(s) from address 0x%04x.\n", gAddress >> 1, (int) length, (unsigned int) address); 00129 #endif 00130 // Enable Block Data Control (0x61) 00131 data[0] = 0x61; 00132 data[1] = 0; 00133 00134 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { 00135 // Write address to ManufacturerAccessControl (0x3e) 00136 data[0] = 0x3e; 00137 data[1] = (char) address; 00138 data[2] = (char) (address >> 8); 00139 00140 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00141 // Read the address from ManufacturerAccessControl (0x3e then 0x3f), 00142 // data from MACData (0x40 to 0x5f), checksum from MACDataSum (0x60) 00143 // and length from MACDataLen (0x61) 00144 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) && 00145 (gpI2c->read(gAddress, &(block[0]), sizeof (block)) == 0)) { 00146 // Check that the address matches 00147 if ((block[0] == (char) address) && (block[1] == (char) (address >> 8))) { 00148 // Check that the checksum matches (-2 on MACDataLen as it includes MACDataSum and itself) 00149 if (block[34] == computeChecksum (&(block[0]), block[35] - 2)) { 00150 // All is good, copy the data to the user 00151 lengthRead = block[35] - 4; // -4 rather than -2 to remove the two bytes of address as well 00152 if (lengthRead > length) { 00153 lengthRead = length; 00154 } 00155 memcpy(pData, &(block[2]), lengthRead); 00156 success = true; 00157 #ifdef DEBUG_BQ35100 00158 printf("BatteryGaugeBq35100 (I2C 0x%02x): %d byte(s) read successfully.\n", gAddress >> 1, (int) lengthRead); 00159 #endif 00160 } else { 00161 #ifdef DEBUG_BQ35100 00162 printf("BatteryGaugeBq35100 (I2C 0x%02x): checksum didn't match (0x%02x expected).\n", gAddress >> 1, block[34]); 00163 #endif 00164 } 00165 } else { 00166 #ifdef DEBUG_BQ35100 00167 printf("BatteryGaugeBq35100 (I2C 0x%02x): address didn't match (expected 0x%04x, received 0x%02x%02x).\n", gAddress >> 1, (unsigned int) address, block[1], block[0]); 00168 #endif 00169 } 00170 } else { 00171 #ifdef DEBUG_BQ35100 00172 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to read %d bytes from ManufacturerAccessControl.\n", gAddress >> 1, sizeof (block)); 00173 #endif 00174 } 00175 } else { 00176 #ifdef DEBUG_BQ35100 00177 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write %d bytes to ManufacturerAccessControl.\r", gAddress >> 1, 3); 00178 #endif 00179 } 00180 } else { 00181 #ifdef DEBUG_BQ35100 00182 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set Block Data Control.\n", gAddress >> 1); 00183 #endif 00184 } 00185 } else { 00186 #ifdef DEBUG_BQ35100 00187 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set the security mode of the chip.\n", gAddress >> 1); 00188 #endif 00189 } 00190 } 00191 00192 // Put the security mode back to what it was 00193 if (!setSecurityMode(securityMode)) { 00194 success = false; 00195 } 00196 00197 return success; 00198 } 00199 00200 // Write data of a given length to a given address. 00201 // Note: gpI2c should be locked before this is called. 00202 bool BatteryGaugeBq35100::writeExtendedData(int32_t address, const char * pData, int32_t length) 00203 { 00204 bool success = false; 00205 SecurityMode securityMode = getSecurityMode(); 00206 char data[3 + 32]; 00207 uint16_t controlStatus; 00208 00209 if ((gpI2c != NULL) && (length <= 32) && (address >= 0x4000) && (address < 0x4400) && (pData != NULL)) { 00210 #ifdef DEBUG_BQ35100 00211 printf("BatteryGaugeBq35100 (I2C 0x%02x): preparing to write %d byte(s) to address 0x%04x.\n", gAddress >> 1, (int) length, (unsigned int) address); 00212 #endif 00213 // Handle security mode 00214 if (setSecurityMode(SECURITY_MODE_UNSEALED)) { 00215 // Enable Block Data Control (0x61) 00216 data[0] = 0x61; 00217 data[1] = 0; 00218 00219 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { 00220 // Start write at ManufacturerAccessControl (0x3e) 00221 data[0] = 0x3e; 00222 // Next two bytes are the address we will write to 00223 data[1] = (char) address; 00224 data[2] = (char) (address >> 8); 00225 // Remaining bytes are the data bytes we wish to write 00226 memcpy (&(data[3]), pData, length); 00227 00228 if (gpI2c->write(gAddress, &(data[0]), 3 + length) == 0) { 00229 // Compute the checksum and write it to MACDataSum (0x60) 00230 data[1] = computeChecksum (&(data[1]), length + 2); 00231 data[0] = 0x60; 00232 00233 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { 00234 // Write 4 + length to MACDataLen (0x61) 00235 data[1] = length + 4; 00236 data[0] = 0x61; 00237 00238 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { 00239 // Read the control status register to see if a bad 00240 // flash write has been detected (bit 15) 00241 data[0] = 0; 00242 if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) && 00243 getTwoBytes(0, &controlStatus) && 00244 (((controlStatus >> 15) & 0x01) != 0x01)) { 00245 success = true; 00246 } 00247 #ifdef DEBUG_BQ35100 00248 printf("BatteryGaugeBq35100 (I2C 0x%02x): write successful.\n", gAddress >> 1); 00249 #endif 00250 } else { 00251 #ifdef DEBUG_BQ35100 00252 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to read write to MACDataLen.\n", gAddress >> 1); 00253 #endif 00254 } 00255 } else { 00256 #ifdef DEBUG_BQ35100 00257 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write to MACDataSum.\n", gAddress >> 1); 00258 #endif 00259 } 00260 } else { 00261 #ifdef DEBUG_BQ35100 00262 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write %d bytes to ManufacturerAccessControl.\r", gAddress >> 1, (int) length + 2); 00263 #endif 00264 } 00265 } else { 00266 #ifdef DEBUG_BQ35100 00267 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set Block Data Control.\n", gAddress >> 1); 00268 #endif 00269 } 00270 } else { 00271 #ifdef DEBUG_BQ35100 00272 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set the security mode of the chip.\n", gAddress >> 1); 00273 #endif 00274 } 00275 } 00276 00277 // Put the security mode back to what it was 00278 if (!setSecurityMode(securityMode)) { 00279 success = false; 00280 } 00281 00282 return success; 00283 } 00284 00285 // Get the security mode of the chip. 00286 // Note: gpI2c should be locked before this is called. 00287 BatteryGaugeBq35100::SecurityMode BatteryGaugeBq35100::getSecurityMode(void) 00288 { 00289 SecurityMode securityMode = SECURITY_MODE_UNKNOWN; 00290 char data[1]; 00291 uint16_t controlStatus; 00292 00293 // Read the control status register 00294 data[0] = 0; 00295 if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) && 00296 getTwoBytes(0, &controlStatus)) { 00297 // Bits 13 and 14 of the high byte represent the security status, 00298 // 01 = full access 00299 // 10 = unsealed access 00300 // 11 = sealed access 00301 securityMode = (SecurityMode) ((controlStatus >> 13) & 0x03); 00302 #ifdef DEBUG_BQ35100 00303 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode is 0x%02x (control status 0x%04x).\r\n", gAddress >> 1, securityMode, controlStatus); 00304 #endif 00305 } 00306 00307 return securityMode; 00308 } 00309 00310 // Set the security mode of the chip. 00311 // Note: gpI2c should be locked before this is called. 00312 bool BatteryGaugeBq35100::setSecurityMode(SecurityMode securityMode) 00313 { 00314 bool success = false; 00315 char data[3]; 00316 SecurityMode currentSecurityMode = getSecurityMode(); 00317 00318 if (securityMode != SECURITY_MODE_UNKNOWN) { 00319 if (securityMode != currentSecurityMode) { 00320 // For reasons that aren't clear, the BQ35100 sometimes refuses 00321 // to change security mode if a previous security mode change 00322 // happend only a few seconds ago, hence the retry here 00323 for (int32_t x = 0; (x < SET_SECURITY_MODE_RETRY_SECONDS) && !success; x++) { 00324 data[0] = 0x3e; // Set address to ManufacturerAccessControl 00325 switch (securityMode) { 00326 case SECURITY_MODE_SEALED: 00327 // Just seal the chip 00328 data[1] = 0x20; // First byte of SEALED sub-command (0x20) 00329 data[2] = 0x00; // Second byte of SEALED sub-command (0x00) (register address will auto-increment) 00330 gpI2c->write(gAddress, &(data[0]), 3); 00331 break; 00332 case SECURITY_MODE_FULL_ACCESS: 00333 // Send the full access code with endianness conversion 00334 // in TWO writes 00335 data[2] = (char) (gFullAccessCodes >> 24); 00336 data[1] = (char) (gFullAccessCodes >> 16); 00337 gpI2c->write(gAddress, &(data[0]), 3); 00338 data[2] = (char) (gFullAccessCodes >> 8); 00339 data[1] = (char) gFullAccessCodes; 00340 gpI2c->write(gAddress, &(data[0]), 3); 00341 break; 00342 case SECURITY_MODE_UNSEALED: 00343 data[2] = (char) (gSealCodes >> 24); 00344 data[1] = (char) (gSealCodes >> 16); 00345 gpI2c->write(gAddress, &(data[0]), 3); 00346 data[2] = (char) (gSealCodes >> 8); 00347 data[1] = (char) gSealCodes; 00348 gpI2c->write(gAddress, &(data[0]), 3); 00349 break; 00350 case SECURITY_MODE_UNKNOWN: 00351 default: 00352 MBED_ASSERT(false); 00353 break; 00354 } 00355 00356 currentSecurityMode = getSecurityMode(); 00357 if (currentSecurityMode == securityMode) { 00358 success = true; 00359 #ifdef DEBUG_BQ35100 00360 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode is now 0x%02x.\n", gAddress >> 1, currentSecurityMode); 00361 #endif 00362 } else { 00363 wait_ms(1000); 00364 #ifdef DEBUG_BQ35100 00365 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode set failed (wanted 0x%02x, got 0x%02x), will retry.\n", gAddress >> 1, securityMode, currentSecurityMode); 00366 #endif 00367 } 00368 } 00369 } else { 00370 success = true; 00371 } 00372 } 00373 00374 return success; 00375 } 00376 00377 // Make sure that the device is awake and has taken a reading. 00378 bool BatteryGaugeBq35100::makeAdcReading(void) 00379 { 00380 bool success = false; 00381 00382 if (isGaugeEnabled()) { 00383 success = true; 00384 } else { 00385 if (enableGauge() && disableGauge()) { 00386 success = true; 00387 } 00388 } 00389 00390 return success; 00391 } 00392 00393 //---------------------------------------------------------------- 00394 // PUBLIC FUNCTIONS 00395 // ---------------------------------------------------------------- 00396 00397 // Constructor. 00398 BatteryGaugeBq35100::BatteryGaugeBq35100(void) 00399 { 00400 gpI2c = NULL; 00401 pGaugeEnable = NULL; 00402 gReady = false; 00403 gSealCodes = 0; 00404 gFullAccessCodes = 0; 00405 } 00406 00407 // Destructor. 00408 BatteryGaugeBq35100::~BatteryGaugeBq35100(void) 00409 { 00410 } 00411 00412 // Initialise ourselves. 00413 bool BatteryGaugeBq35100::init(I2C * pI2c, PinName gaugeEnable, uint8_t address, uint32_t sealCodes) 00414 { 00415 uint16_t answer; 00416 char data[4]; 00417 00418 gpI2c = pI2c; 00419 gAddress = address << 1; 00420 gSealCodes = sealCodes; 00421 00422 if (gaugeEnable != NC) { 00423 pGaugeEnable = new DigitalOut(gaugeEnable, 1); 00424 wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS); 00425 } 00426 00427 if (gpI2c != NULL) { 00428 gpI2c->lock(); 00429 gpI2c->frequency(I2C_CLOCK_FREQUENCY); 00430 00431 // Send a control command to read the device type 00432 data[0] = 0x3e; // Set address to ManufacturerAccessControl 00433 data[1] = 0x03; // First byte of HW_VERSION sub-command (0x03) 00434 data[2] = 0x00; // Second byte of HW_VERSION sub-command (0x00) (register address will auto-increment) 00435 00436 if ((gpI2c->write(gAddress, &(data[0]), 3) == 0) && 00437 getTwoBytes(0x40, &answer)) { // Read from MACData address 00438 if (answer == 0x00a8) { 00439 // Read the full access codes, in case we need them 00440 if (readExtendedData(0x41d0, &(data[0]), sizeof (data))) { 00441 // The four bytes are the full access codes 00442 gFullAccessCodes = ((uint32_t) data[0] << 24) + ((uint32_t) data[1] << 16) + ((uint32_t) data[2] << 8) + data[3]; 00443 #ifdef DEBUG_BQ35100 00444 printf("BatteryGaugeBq35100 (I2C 0x%02x): full access code is 0x%08x.\n", gAddress >> 1, 00445 (unsigned int) gFullAccessCodes); 00446 #endif 00447 gReady = true; 00448 } 00449 } 00450 00451 #ifdef DEBUG_BQ35100 00452 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x as HW_VERSION, expected 0x00a8.\n", gAddress >> 1, answer); 00453 #endif 00454 } 00455 00456 disableGauge(); 00457 gpI2c->unlock(); 00458 } 00459 00460 #ifdef DEBUG_BQ35100 00461 if (gReady) { 00462 printf("BatteryGaugeBq35100 (I2C 0x%02x): handler initialised.\n", gAddress >> 1); 00463 } else { 00464 printf("BatteryGaugeBq35100 (I2C 0x%02x): init NOT successful.\n", gAddress >> 1); 00465 } 00466 #endif 00467 00468 return gReady; 00469 } 00470 00471 // Switch on the battery capacity monitor. 00472 bool BatteryGaugeBq35100::enableGauge(bool nonVolatile) 00473 { 00474 bool accumulatedCapacityOn = false; 00475 bool success = false; 00476 char data[3]; 00477 char opConfig; 00478 uint16_t controlStatus; 00479 00480 if (gReady) { 00481 if (nonVolatile) { 00482 // Read the OpConfig register which is at address 0x41b1 00483 if (readExtendedData(0x41b1, &opConfig, sizeof (opConfig))) { 00484 #ifdef DEBUG_BQ35100 00485 printf("BatteryGaugeBq35100 (I2C 0x%02x): OpConfig is 0x%02x.\n", gAddress >> 1, opConfig); 00486 #endif 00487 // AccumulatedCapacity is achieved by setting GMSEL 1:0 (in bits 0 and 1) to 00 00488 if ((opConfig & 0x03) != 0) { 00489 opConfig &= ~0x03; 00490 // Write the new value back 00491 accumulatedCapacityOn = writeExtendedData(0x41b1, &opConfig, sizeof (opConfig)); 00492 #ifdef DEBUG_BQ35100 00493 if (accumulatedCapacityOn) { 00494 printf("BatteryGaugeBq35100 (I2C 0x%02x): AccumulatedCapacity enabled, OpConfig becomes 0x%02x.\r\n", gAddress >> 1, opConfig); 00495 } 00496 #endif 00497 } else { 00498 accumulatedCapacityOn = true; 00499 } 00500 } 00501 } 00502 00503 if (accumulatedCapacityOn || !nonVolatile) { 00504 if (pGaugeEnable) { 00505 *pGaugeEnable = 1; 00506 wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS); 00507 } 00508 gpI2c->lock(); 00509 data[0] = 0x3e; // Set address to ManufacturerAccessControl 00510 data[1] = 0x11; // First byte of GAUGE_START sub-command (0x11) 00511 data[2] = 0x00; // Second byte of GAUGE_START sub-command (0x00) (register address will auto-increment) 00512 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00513 // Wait for GA bit of CONTROL_STATUS (bit 0) to become 1 00514 data[0] = 0; 00515 if (gpI2c->write(gAddress, &(data[0]), 1) == 0) { 00516 for (int x = 0; (x < GAUGE_COMPLETE_WAIT_MS / 10) && !success; x++) { 00517 if (getTwoBytes(0, &controlStatus)) { 00518 if ((controlStatus & 0x01) == 0x01) { 00519 success = true; 00520 } else { 00521 wait_ms(10); 00522 } 00523 } else { 00524 wait_ms(10); 00525 } 00526 } 00527 } 00528 } 00529 gpI2c->unlock(); 00530 } 00531 } 00532 00533 return success; 00534 } 00535 00536 // Switch off the battery capacity monitor. 00537 bool BatteryGaugeBq35100::disableGauge(void) 00538 { 00539 bool accumulatedCapacityOn = false; 00540 bool success = false; 00541 char data[3]; 00542 char opConfig; 00543 uint16_t controlStatus; 00544 00545 if (gReady) { 00546 if (isGaugeEnabled()) { 00547 // Read the OpConfig register which is at address 0x41b1 00548 if (readExtendedData(0x41b1, &opConfig, sizeof (opConfig))) { 00549 #ifdef DEBUG_BQ35100 00550 printf("BatteryGaugeBq35100 (I2C 0x%02x): OpConfig is 0x%02x.\n", gAddress >> 1, opConfig); 00551 #endif 00552 // Check if AccumulatedCapacity is on 00553 if ((opConfig & 0x03) == 0) { 00554 accumulatedCapacityOn = true; 00555 } 00556 00557 // Send GAUGE_STOP 00558 gpI2c->lock(); 00559 data[0] = 0x3e; // Set address to ManufacturerAccessControl 00560 data[1] = 0x12; // First byte of GAUGE_STOP sub-command (0x12) 00561 data[2] = 0x00; // Second byte of GAUGE_STOP sub-command (0x00) (register address will auto-increment) 00562 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00563 // Wait for GA bit of CONTROL_STATUS (bit 0) to become 0 and, 00564 // if AccumulatedCapacity was on, wait for G_DONE 00565 // (bit 6 in CONTROL_STATUS) to be set 00566 data[0] = 0; 00567 if (gpI2c->write(gAddress, &(data[0]), 1) == 0) { 00568 for (int x = 0; (x < GAUGE_COMPLETE_WAIT_MS / 10) && !success; x++) { 00569 if (getTwoBytes(0, &controlStatus)) { 00570 if ((controlStatus & 0x01) == 0) { 00571 if (accumulatedCapacityOn) { 00572 if (((controlStatus >> 6) & 0x01) == 0x01) { 00573 success = true; 00574 #ifdef DEBUG_BQ35100 00575 printf("BatteryGaugeBq35100 (I2C 0x%02x): AccumulatedCapacity data written to non-volatile memory.\r\n", gAddress >> 1); 00576 #endif 00577 } else { 00578 wait_ms(10); 00579 } 00580 } else { 00581 success = true; 00582 } 00583 } else { 00584 wait_ms(10); 00585 } 00586 } else { 00587 wait_ms(10); 00588 } 00589 } 00590 } 00591 } 00592 gpI2c->unlock(); 00593 } 00594 } else { 00595 success = true; 00596 } 00597 00598 if (pGaugeEnable) { 00599 *pGaugeEnable = 0; 00600 } 00601 } 00602 00603 return success; 00604 } 00605 00606 // Determine whether battery gauging is enabled. 00607 bool BatteryGaugeBq35100::isGaugeEnabled(void) 00608 { 00609 bool gaugeEnabled = false; 00610 char data[1]; 00611 uint16_t controlStatus; 00612 00613 if (gReady) { 00614 // Check the GA bit (bit 0) in CONTROL_STATUS 00615 data[0] = 0; 00616 if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) && 00617 getTwoBytes(0, &controlStatus)) { 00618 #ifdef DEBUG_BQ35100 00619 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x as CONTROL_STATUS.\n", gAddress >> 1, controlStatus); 00620 #endif 00621 if ((controlStatus & 0x01) == 0x01) { 00622 gaugeEnabled = true; 00623 } 00624 } 00625 } 00626 00627 return gaugeEnabled; 00628 } 00629 00630 // Set the designed capacity of the cell. 00631 bool BatteryGaugeBq35100::setDesignCapacity(uint32_t capacityMAh) 00632 { 00633 bool success = false; 00634 char data[2]; 00635 00636 if (gReady) { 00637 gpI2c->lock(); 00638 00639 data[0] = capacityMAh >> 8; // Upper byte of design capacity 00640 data[1] = capacityMAh; // Lower byte of design capacity 00641 00642 // Write to the "Cell Design Capacity mAh" address in data flash 00643 if (writeExtendedData(0x41fe, &(data[0]), sizeof(data))) { 00644 success = true; 00645 00646 #ifdef DEBUG_BQ35100 00647 printf("BatteryGaugeBq35100 (I2C 0x%02x): designed cell capacity set to %d mAh.\n", gAddress >> 1, 00648 (unsigned int) capacityMAh); 00649 #endif 00650 } 00651 00652 gpI2c->unlock(); 00653 } 00654 00655 return success; 00656 } 00657 00658 // Get the designed capacity of the cell. 00659 bool BatteryGaugeBq35100::getDesignCapacity(uint32_t *pCapacityMAh) 00660 { 00661 bool success = false; 00662 uint16_t data; 00663 00664 if (gReady) { 00665 gpI2c->lock(); 00666 00667 // Read from the DesignCapacity address 00668 if (getTwoBytes (0x3c, &data)) { 00669 success = true; 00670 00671 // The answer is in mAh 00672 if (pCapacityMAh) { 00673 *pCapacityMAh = data; 00674 } 00675 00676 #ifdef DEBUG_BQ35100 00677 printf("BatteryGaugeBq35100 (I2C 0x%02x): designed cell capacity is %d mAh.\n", gAddress >> 1, data); 00678 #endif 00679 } 00680 00681 } 00682 00683 return success; 00684 } 00685 00686 // Get the temperature of the chip. 00687 bool BatteryGaugeBq35100::getTemperature(int32_t *pTemperatureC) 00688 { 00689 bool success = false; 00690 int32_t temperatureC = 0; 00691 uint16_t data; 00692 00693 if (gReady && makeAdcReading()) { 00694 gpI2c->lock(); 00695 // Read from the temperature register address 00696 if (getTwoBytes (0x06, &data)) { 00697 success = true; 00698 00699 // The answer is in units of 0.1 K, so convert to C 00700 temperatureC = ((int32_t) data / 10) - 273; 00701 00702 if (pTemperatureC) { 00703 *pTemperatureC = temperatureC; 00704 } 00705 00706 #ifdef DEBUG_BQ35100 00707 printf("BatteryGaugeBq35100 (I2C 0x%02x): chip temperature %.1f K, so %d C.\n", gAddress >> 1, ((float) data) / 10, (int) temperatureC); 00708 #endif 00709 } 00710 00711 gpI2c->unlock(); 00712 } 00713 00714 return success; 00715 } 00716 00717 // Get the voltage of the battery. 00718 bool BatteryGaugeBq35100::getVoltage(int32_t *pVoltageMV) 00719 { 00720 bool success = false; 00721 uint16_t data = 0; 00722 00723 if (gReady && makeAdcReading()) { 00724 gpI2c->lock(); 00725 // Read from the voltage register address 00726 if (getTwoBytes (0x08, &data)) { 00727 success = true; 00728 00729 // The answer is in mV 00730 if (pVoltageMV) { 00731 *pVoltageMV = (int32_t) data; 00732 } 00733 00734 #ifdef DEBUG_BQ35100 00735 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery voltage %.3f V.\n", gAddress >> 1, ((float) data) / 1000); 00736 #endif 00737 } 00738 00739 gpI2c->unlock(); 00740 } 00741 00742 return success; 00743 } 00744 00745 // Get the current flowing from the battery. 00746 bool BatteryGaugeBq35100::getCurrent(int32_t *pCurrentMA) 00747 { 00748 bool success = false; 00749 int32_t currentMA = 0; 00750 uint16_t data = 0; 00751 00752 if (gReady && makeAdcReading()) { 00753 gpI2c->lock(); 00754 // Read from the average current register address 00755 if (getTwoBytes (0x0c, &data)) { 00756 success = true; 00757 00758 if (pCurrentMA) { 00759 *pCurrentMA = currentMA; 00760 } 00761 00762 #ifdef DEBUG_BQ35100 00763 printf("BatteryGaugeBq35100 (I2C 0x%02x): current %d mA.\n", gAddress >> 1, (int) currentMA); 00764 #endif 00765 } 00766 00767 gpI2c->unlock(); 00768 } 00769 00770 return success; 00771 } 00772 00773 // Get the battery capacity used. 00774 bool BatteryGaugeBq35100::getUsedCapacity(uint32_t *pCapacityUAh) 00775 { 00776 bool success = false; 00777 char bytes[5]; 00778 uint32_t data; 00779 00780 if (gReady && makeAdcReading()) { 00781 gpI2c->lock(); 00782 // Read four bytes from the AccummulatedCapacity register address 00783 00784 // Send a command to read from registerAddress 00785 bytes[0] = 0x02; 00786 bytes[1] = 0; 00787 bytes[2] = 0; 00788 bytes[3] = 0; 00789 bytes[4] = 0; 00790 00791 if ((gpI2c->write(gAddress, &(bytes[0]), 1) == 0) && 00792 (gpI2c->read(gAddress, &(bytes[1]), 4) == 0)) { 00793 success = true; 00794 data = (((uint32_t) bytes[4]) << 24) + (((uint32_t) bytes[3]) << 16) + (((uint32_t) bytes[2]) << 8) + bytes[1]; 00795 00796 // The answer is in uAh 00797 if (pCapacityUAh) { 00798 *pCapacityUAh = data; 00799 } 00800 00801 #ifdef DEBUG_BQ35100 00802 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity used %u uAh.\n", gAddress >> 1, (unsigned int) data); 00803 #endif 00804 } 00805 00806 gpI2c->unlock(); 00807 } 00808 00809 return success; 00810 } 00811 00812 // Get the battery capacity remaining. 00813 bool BatteryGaugeBq35100::getRemainingCapacity(uint32_t *pCapacityUAh) 00814 { 00815 bool success = false; 00816 uint32_t designCapacityUAh; 00817 uint32_t usedCapacityUAh; 00818 00819 // First, get the designed capacity 00820 if (getDesignCapacity(&designCapacityUAh)) { 00821 designCapacityUAh *= 1000; 00822 // Then get the used capacity 00823 if (getUsedCapacity(&usedCapacityUAh)) { 00824 success = true; 00825 // Limit the result 00826 if (usedCapacityUAh > designCapacityUAh) { 00827 usedCapacityUAh = designCapacityUAh; 00828 } 00829 00830 // The answer is in uAh 00831 if (pCapacityUAh) { 00832 *pCapacityUAh = designCapacityUAh - usedCapacityUAh; 00833 } 00834 00835 #ifdef DEBUG_BQ35100 00836 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity remaining %u uAh (from a designed capacity of %d uAh).\n", gAddress >> 1, 00837 (unsigned int) (designCapacityUAh - usedCapacityUAh), (unsigned int) designCapacityUAh); 00838 #endif 00839 } 00840 } 00841 00842 return success; 00843 } 00844 00845 // Get the percentage capacity remaining. 00846 bool BatteryGaugeBq35100::getRemainingPercentage(int32_t *pBatteryPercentage) 00847 { 00848 bool success = false; 00849 uint32_t designCapacityUAh; 00850 uint32_t usedCapacityUAh; 00851 int32_t batteryPercentage; 00852 00853 // First, get the designed capacity (which is actually in mAh) 00854 if (getDesignCapacity(&designCapacityUAh)) { 00855 // Convert to uAh 00856 designCapacityUAh *= 1000; 00857 // Then get the used capacity 00858 if (getUsedCapacity(&usedCapacityUAh)) { 00859 success = true; 00860 // Limit the result 00861 if (usedCapacityUAh > designCapacityUAh) { 00862 usedCapacityUAh = designCapacityUAh; 00863 } 00864 batteryPercentage = (uint64_t) (designCapacityUAh - usedCapacityUAh) * 100 / designCapacityUAh; 00865 00866 if (pBatteryPercentage) { 00867 *pBatteryPercentage = batteryPercentage; 00868 } 00869 00870 #ifdef DEBUG_BQ35100 00871 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity remaining %d%%.\n", gAddress >> 1, 00872 (unsigned int) batteryPercentage); 00873 #endif 00874 } 00875 } 00876 00877 return success; 00878 } 00879 00880 // Indicate that a new battery has been inserted. 00881 bool BatteryGaugeBq35100::newBattery(uint32_t capacityMAh) 00882 { 00883 bool success = false; 00884 char data[3]; 00885 00886 if (gReady) { 00887 if (setDesignCapacity(capacityMAh)) { 00888 gpI2c->lock(); 00889 // Send a control command to indicate NEW_BATTERY 00890 data[0] = 0x3e; // Set address to ManufacturerAccessControl 00891 data[1] = 0x13; // First byte of NEW_BATTERY sub-command (0x13) 00892 data[2] = 0xA6; // Second byte of NEW_BATTERY sub-command (0xA6) (register address will auto-increment) 00893 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00894 success = true; 00895 #ifdef DEBUG_BQ35100 00896 printf("BatteryGaugeBq35100 (I2C 0x%02x): new battery set.\n", gAddress >> 1); 00897 #endif 00898 } 00899 00900 gpI2c->unlock(); 00901 } 00902 } 00903 00904 return success; 00905 } 00906 00907 // Read configuration data. 00908 bool BatteryGaugeBq35100::advancedGetConfig(int32_t address, char * pData, int32_t length) 00909 { 00910 bool success = false; 00911 00912 if (gReady) { 00913 gpI2c->lock(); 00914 00915 success = readExtendedData(address, pData, length); 00916 00917 gpI2c->unlock(); 00918 } 00919 00920 return success; 00921 } 00922 00923 // Write configuration data. 00924 bool BatteryGaugeBq35100::advancedSetConfig(int32_t address, const char * pData, int32_t length) 00925 { 00926 bool success = false; 00927 00928 if (gReady) { 00929 gpI2c->lock(); 00930 00931 success = writeExtendedData(address, pData, length); 00932 00933 gpI2c->unlock(); 00934 } 00935 00936 return success; 00937 } 00938 00939 // Send a control word. 00940 bool BatteryGaugeBq35100::advancedSendControlWord(uint16_t controlWord, uint16_t *pDataReturned) 00941 { 00942 bool success = false; 00943 char data[3]; 00944 00945 if (gReady) { 00946 gpI2c->lock(); 00947 00948 // Send the control command 00949 data[0] = 0x3e; // Set address to ManufacturerAccessControl 00950 data[1] = (char) controlWord; // First byte of controlWord 00951 data[2] = (char) (controlWord >> 8); // Second byte of controlWord 00952 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00953 // Read the two bytes returned if requested 00954 if (pDataReturned != NULL) { 00955 if (getTwoBytes(0x40, pDataReturned)) { // Read from MACData 00956 success = true; 00957 #ifdef DEBUG_BQ35100 00958 printf("BatteryGaugeBq35100 (I2C 0x%02x): sent control word 0x%04x, read back 0x%04x.\n", gAddress >> 1, controlWord, *pDataReturned); 00959 #endif 00960 } 00961 } else { 00962 success = true; 00963 #ifdef DEBUG_BQ35100 00964 printf("BatteryGaugeBq35100 (I2C 0x%02x): sent control word 0x%04x.\n", gAddress >> 1, controlWord); 00965 #endif 00966 } 00967 } 00968 00969 gpI2c->unlock(); 00970 } 00971 00972 return success; 00973 } 00974 00975 // Read two bytes starting at a given address on the chip. 00976 bool BatteryGaugeBq35100::advancedGet(uint8_t address, uint16_t *pDataReturned) 00977 { 00978 bool success = false; 00979 uint16_t value = 0; 00980 00981 if (gReady) { 00982 // Make sure there's a recent reading, as most 00983 // of these commands involve the chip having done one 00984 if (makeAdcReading()) { 00985 gpI2c->lock(); 00986 // Read the data 00987 if (getTwoBytes(address, &value)) { 00988 success = true; 00989 #ifdef DEBUG_BQ35100 00990 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x from addresses 0x%02x and 0x%02x.\n", gAddress >> 1, value, address, address + 1); 00991 #endif 00992 if (pDataReturned != NULL) { 00993 *pDataReturned = value; 00994 } 00995 } 00996 gpI2c->unlock(); 00997 } 00998 } 00999 01000 return success; 01001 } 01002 01003 // Get the security mode of the chip. 01004 BatteryGaugeBq35100::SecurityMode BatteryGaugeBq35100::advancedGetSecurityMode(void) 01005 { 01006 SecurityMode securityMode = SECURITY_MODE_UNKNOWN; 01007 01008 if (gReady) { 01009 gpI2c->lock(); 01010 01011 securityMode = getSecurityMode(); 01012 01013 gpI2c->unlock(); 01014 } 01015 01016 return securityMode; 01017 } 01018 01019 // Set the security mode of the chip. 01020 bool BatteryGaugeBq35100::advancedSetSecurityMode(SecurityMode securityMode) 01021 { 01022 bool success = false; 01023 01024 if (gReady) { 01025 gpI2c->lock(); 01026 01027 success = setSecurityMode(securityMode); 01028 01029 gpI2c->unlock(); 01030 } 01031 01032 return success; 01033 } 01034 01035 // Do a hard reset of the chip. 01036 bool BatteryGaugeBq35100::advancedReset(void) 01037 { 01038 bool success = false; 01039 SecurityMode securityMode; 01040 char data[3]; 01041 01042 if (gReady) { 01043 gpI2c->lock(); 01044 01045 securityMode = getSecurityMode(); // Must be inside lock() 01046 // Handle unsealing, as this command only works when unsealed 01047 if (setSecurityMode(SECURITY_MODE_UNSEALED)) { 01048 // Send a RESET sub-command 01049 data[0] = 0x3e; // Set address to ManufacturerAccessControl 01050 data[1] = 0x41; // First byte of RESET sub-command (0x41) 01051 data[2] = 0x00; // Second byte of RESET sub-command (0x00) (register address will auto-increment) 01052 01053 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 01054 success = true; 01055 #ifdef DEBUG_BQ35100 01056 printf("BatteryGaugeBq35100 (I2C 0x%02x): chip hard reset.\n", gAddress >> 1); 01057 #endif 01058 } 01059 01060 // Set the security mode back to what it was 01061 if (!setSecurityMode(securityMode)) { 01062 success = false; 01063 } 01064 } 01065 01066 gpI2c->unlock(); 01067 } 01068 01069 return success; 01070 } 01071 01072 /* End Of File */
Generated on Tue Jul 12 2022 19:24:03 by
1.7.2