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.
Fork of battery-gauge-bq27441 by
bq27441.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 bq27441.cpp 00019 * This file defines the API to the TI BQ27441 battery gauge chip. 00020 */ 00021 00022 /** Define these to print debug information. */ 00023 //#define DEBUG_BQ27441 00024 //#define DEBUG_BQ27441_BLOCK_DATA 00025 00026 #include <mbed.h> 00027 #include <battery_gauge_bq27441.h> 00028 00029 #ifdef DEBUG_BQ27441 00030 # include <stdio.h> 00031 #endif 00032 00033 // ---------------------------------------------------------------- 00034 // COMPILE-TIME MACROS 00035 // ---------------------------------------------------------------- 00036 00037 /** How many loops to wait for a configuration update to be permitted. 00038 * Experience suggests that the limit really does need to be this large. */ 00039 #define CONFIG_UPDATE_LOOPS 200 00040 00041 /** How long to delay when running around the config update loop. */ 00042 #define CONFIG_UPDATE_LOOP_DELAY_MS 100 00043 00044 /** How long to wait for all the ADC readings to be performed. */ 00045 #define ADC_READ_WAIT_MS 1000 00046 00047 /** Delay after the last config update before we can unseal the 00048 * chip again (see section 6.4.5.1.1 of the BQ27441 technical 00049 * reference manual). */ 00050 #define UNSEAL_DELAY_MS 4000 00051 00052 // ---------------------------------------------------------------- 00053 // PRIVATE VARIABLES 00054 // ---------------------------------------------------------------- 00055 00056 // ---------------------------------------------------------------- 00057 // GENERIC PRIVATE FUNCTIONS 00058 // ---------------------------------------------------------------- 00059 00060 // Read two bytes from an address. 00061 // Note: gpI2c should be locked before this is called. 00062 bool BatteryGaugeBq27441::getTwoBytes (uint8_t registerAddress, uint16_t *pBytes) 00063 { 00064 bool success = false; 00065 char data[3]; 00066 00067 if (gpI2c != NULL) { 00068 // Send a command to read from registerAddress 00069 data[0] = registerAddress; 00070 data[1] = 0; 00071 data[2] = 0; 00072 00073 if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) && 00074 (gpI2c->read(gAddress, &(data[1]), 2) == 0)) { 00075 success = true; 00076 if (pBytes) { 00077 *pBytes = (((uint16_t) data[2]) << 8) + data[1]; 00078 } 00079 } 00080 } 00081 00082 return success; 00083 } 00084 00085 bool BatteryGaugeBq27441::getTwoBytesSigned (uint8_t registerAddress, int16_t *pBytes) 00086 { 00087 bool success = false; 00088 char data[3]; 00089 00090 if (gpI2c != NULL) { 00091 // Send a command to read from registerAddress 00092 data[0] = registerAddress; 00093 data[1] = 0; 00094 data[2] = 0; 00095 00096 if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) && 00097 (gpI2c->read(gAddress, &(data[1]), 2) == 0)) { 00098 success = true; 00099 if (pBytes) { 00100 *pBytes = (((int16_t) data[2]) << 8) + data[1]; 00101 } 00102 } 00103 } 00104 00105 return success; 00106 } 00107 00108 // Compute the checksum over a block of data. 00109 uint8_t BatteryGaugeBq27441::computeChecksum(const char * pData) 00110 { 00111 uint8_t checkSum = 0; 00112 uint8_t x; 00113 00114 if (pData != NULL) { 00115 #ifdef DEBUG_BQ27441_BLOCK_DATA 00116 printf ("BatteryGaugeBq27441 (I2C 0x%02x): computing check sum on data block.\n", gAddress >> 1); 00117 printf (" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); 00118 #endif 00119 for (x = 1; x <= 32; x++) { 00120 checkSum += *pData; 00121 00122 #ifdef DEBUG_BQ27441_BLOCK_DATA 00123 if (x % 16 == 8) { 00124 printf ("%02x ", *pData); 00125 } else if (x % 16 == 0) { 00126 printf ("%02x\n", *pData); 00127 } else { 00128 printf ("%02x-", *pData); 00129 } 00130 #endif 00131 pData++; 00132 } 00133 00134 checkSum = 0xff - checkSum; 00135 } 00136 00137 #ifdef DEBUG_BQ27441_BLOCK_DATA 00138 if (x % 16 != 1) { 00139 printf("\n"); 00140 } 00141 00142 printf ("BatteryGaugeBq27441 (I2C 0x%02x): check sum is 0x%02x.\n", gAddress >> 1, checkSum); 00143 #endif 00144 00145 return checkSum; 00146 } 00147 00148 // Read data of a given length and class ID. 00149 // Note: gpI2c should be locked before this is called. 00150 bool BatteryGaugeBq27441::readExtendedData(uint8_t subClassId, int32_t offset, int32_t length, char * pData) 00151 { 00152 bool success = false; 00153 bool wasSealed = false; 00154 char block[32]; 00155 char data[3]; 00156 00157 if ((gpI2c != NULL) && (length <= 32) && (pData != NULL)) { 00158 00159 // The offset + length combination must not cross a 32-byte boundary 00160 if (offset / 32 == (offset + length - 1) / 32) { 00161 00162 #ifdef DEBUG_BQ27441 00163 printf("BatteryGaugeBq27441 (I2C 0x%02x): preparing to read %d byte(s) from offset %d of sub-class %d.\n", gAddress >> 1, (int) length, (int) offset, subClassId); 00164 #endif 00165 // Handle unsealing 00166 wasSealed = isSealed(); 00167 if (!wasSealed || unseal(gSealCode)) { 00168 00169 // Enable Block Data Control (0x61) 00170 data[0] = 0x61; 00171 data[1] = 0; 00172 00173 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { 00174 // Write sub-class ID using Data Block Class (0x3e) 00175 data[0] = 0x3e; 00176 data[1] = subClassId; 00177 00178 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { 00179 // Write offset using Block Offset (0x3f) and then 00180 // read the data block 00181 data[0] = 0x3f; 00182 data[1] = offset / 32; 00183 00184 if ((gpI2c->write(gAddress, &(data[0]), 2, true) == 0) && 00185 (gpI2c->read(gAddress, &(block[0]), 32) == 0)) { 00186 // Compute the block checksum and then read it 00187 data[2] = computeChecksum(&(block[0])); 00188 data[0] = 0x60; 00189 data[1] = 0; 00190 00191 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) && 00192 (gpI2c->read(gAddress, &(data[1]), 1) == 0)) { 00193 00194 // Does the checksum match? 00195 if (data[1] == data[2]) { 00196 // If so read the new data from the block data area at 0x40 plus 00197 // the offset (plus the Block Offset already written) 00198 data[0] = 0x40 + (offset % 32); 00199 00200 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) && 00201 (gpI2c->read(gAddress, pData, length) == 0)) { 00202 success = true; 00203 #ifdef DEBUG_BQ27441 00204 printf("BatteryGaugeBq27441 (I2C 0x%02x): read successful.\n", gAddress >> 1); 00205 #endif 00206 } else { 00207 #ifdef DEBUG_BQ27441 00208 printf("BatteryGaugeBq27441 (I2C 0x%02x): couldn't read all %d bytes of config.\r", gAddress >> 1, (int) length); 00209 #endif 00210 } 00211 } else { 00212 #ifdef DEBUG_BQ27441 00213 printf("BatteryGaugeBq27441 (I2C 0x%02x): checksum on data block incorrect (expected 0x%02x, received 0x%02x).\n", gAddress >> 1, data[2], data[1]); 00214 #endif 00215 } 00216 } else { 00217 #ifdef DEBUG_BQ27441 00218 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to read Block Data Checksum for config.\n", gAddress >> 1); 00219 #endif 00220 } 00221 } else { 00222 #ifdef DEBUG_BQ27441 00223 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write Block Offset (%d), or maybe read the data block, for config.\n", gAddress >> 1, data[1]); 00224 #endif 00225 } 00226 } else { 00227 #ifdef DEBUG_BQ27441 00228 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable set sub-class ID (0x%02x) for config.\n", gAddress >> 1, subClassId); 00229 #endif 00230 } 00231 } else { 00232 #ifdef DEBUG_BQ27441 00233 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to set Block Data Control for config.\n", gAddress >> 1); 00234 #endif 00235 } 00236 } else { 00237 #ifdef DEBUG_BQ27441 00238 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to unseal chip.\n", gAddress >> 1); 00239 #endif 00240 } 00241 } else { 00242 #ifdef DEBUG_BQ27441 00243 printf("BatteryGaugeBq27441 (I2C 0x%02x): offset (%d) is in different 32 byte block to offset + length (%d) [length is %d].\n", gAddress >> 1, (int) offset, (int) (offset + length), (int) length); 00244 #endif 00245 } 00246 } 00247 00248 // Reseal if required, and fail if it fails 00249 if (wasSealed) { 00250 if (!seal()) { 00251 success = false; 00252 } 00253 } 00254 00255 return success; 00256 } 00257 00258 // Write data of a given length and class ID to a given offset. This code taken from 00259 // section 3.1 of the SLUUAC9A application technical reference manual with hints from: 00260 // https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library/blob/master/src/SparkFunBQ27441.cpp. 00261 // Note: gpI2c should be locked before this is called. 00262 bool BatteryGaugeBq27441::writeExtendedData(uint8_t subClassId, int32_t offset, int32_t length, const char * pData) 00263 { 00264 bool success = false; 00265 bool wasSealed = false; 00266 char data[3 + 32]; 00267 char block[32]; 00268 uint16_t answer; 00269 uint32_t count = 0; 00270 00271 if ((gpI2c != NULL) && (length <= 32) && (pData != NULL)) { 00272 00273 // The offset + length combination must not cross a 32-byte boundary 00274 if (offset / 32 == (offset + length - 1) / 32) { 00275 #ifdef DEBUG_BQ27441 00276 printf("BatteryGaugeBq27441 (I2C 0x%02x): preparing to write %d byte(s) to offset %d of sub-class %d.\n", gAddress >> 1, (int) length, (int) offset, subClassId); 00277 #endif 00278 // Handle unsealing 00279 wasSealed = isSealed(); 00280 if (!wasSealed || unseal(gSealCode)) { 00281 00282 // Send Config Update (command 0x13) 00283 data[0] = 0; 00284 data[1] = 0x13; 00285 data[2] = 0; 00286 00287 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00288 // Wait for CONFIGUPDATE to be set in Flags register (bit 4) 00289 count = 0; 00290 do { 00291 answer = 0; 00292 getTwoBytes(0x06, &answer); 00293 count++; 00294 wait_ms(CONFIG_UPDATE_LOOP_DELAY_MS); 00295 } while (((answer & (1 << 4)) == 0) && (count < CONFIG_UPDATE_LOOPS)); 00296 00297 if ((answer & (1 << 4)) != 0) { 00298 // Enable Block Data Control (0x61) 00299 data[0] = 0x61; 00300 data[1] = 0; 00301 00302 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { 00303 // Write sub-class ID using Data Block Class (0x3e) 00304 data[0] = 0x3e; 00305 data[1] = subClassId; 00306 00307 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { 00308 // Write offset using Block Offset (0x3f) and then 00309 // read the data block 00310 data[0] = 0x3f; 00311 data[1] = offset / 32; 00312 00313 if ((gpI2c->write(gAddress, &(data[0]), 2, true) == 0) && 00314 (gpI2c->read(gAddress, &(block[0]), 32) == 0)) { 00315 // Compute the existing block checksum and then read it 00316 data[2] = computeChecksum(&(block[0])); 00317 data[0] = 0x60; 00318 data[1] = 0; 00319 00320 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) && 00321 (gpI2c->read(gAddress, &(data[1]), 1) == 0)) { 00322 00323 // Does the checksum match? 00324 if (data[1] == data[2]) { 00325 // If so write the new data to the block data area at 0x40 plus the offset (plus the Block Offset already written) 00326 // NOTE: I tried doing this as two separate writes, one of the offset and then another of the 00327 // data block (so that I could use pData directly rather than having to extend the local 00328 // data array by 32) but the chip didn't like that, hence we have to copy pData into the 00329 // local array and do a single contiguous write. 00330 data[0] = 0x40 + (offset % 32); 00331 memcpy (&(data[1]), pData, length); 00332 00333 if (gpI2c->write(gAddress, &(data[0]), length + 1) == 0) { 00334 // Also write the data into our local block variable 00335 // on top of the previously read data and use 00336 // that to compute the new block checksum, then write it 00337 memcpy (&(block[offset % 32]), pData, length); 00338 data[0] = 0x60; 00339 data[1] = computeChecksum(&(block[0])); 00340 00341 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { 00342 // Exit config mode with SOFT_RESET command 0x42 00343 data[0] = 0; 00344 data[1] = 0x42; 00345 data[2] = 0; 00346 00347 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00348 // Finally, wait for CONFIGUPDATE to be unset in Flags register (bit 4) 00349 count = 0; 00350 do { 00351 answer = 0xFFFF; 00352 getTwoBytes(0x06, &answer); 00353 count++; 00354 wait_ms(CONFIG_UPDATE_LOOP_DELAY_MS); 00355 } while (((answer & (1 << 4)) != 0) && (count < CONFIG_UPDATE_LOOPS)); 00356 00357 if ((answer & (1 << 4)) == 0) { 00358 success = true; 00359 // Wait around for 4 seconds if there has been a config update 00360 // and there is a danger that we might have to unseal the device 00361 // Note: would be nice if we could note the time and do other 00362 // things but the timer is restarted when certain commands are sent, 00363 // so it is better to be dumb 00364 if (wasSealed) { 00365 wait_ms(UNSEAL_DELAY_MS); 00366 } 00367 #ifdef DEBUG_BQ27441 00368 printf("BatteryGaugeBq27441 (I2C 0x%02x): write successful.\n", gAddress >> 1); 00369 #endif 00370 } else { 00371 #ifdef DEBUG_BQ27441 00372 printf("BatteryGaugeBq27441 (I2C 0x%02x): Flags register didn't show config update flag unset in time (0x%04x).\n", gAddress >> 1, answer); 00373 #endif 00374 } 00375 } else { 00376 #ifdef DEBUG_BQ27441 00377 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write config update exit after update.\n", gAddress >> 1); 00378 #endif 00379 } 00380 } else { 00381 #ifdef DEBUG_BQ27441 00382 printf("BatteryGaugeBq27441 (I2C 0x%02x): checksum on modified data block incorrect (0x%02x) during config update.\n", gAddress >> 1, data[1]); 00383 #endif 00384 } 00385 } else { 00386 #ifdef DEBUG_BQ27441 00387 printf("BatteryGaugeBq27441 (I2C 0x%02x): couldn't write all %d bytes during config update.\n", gAddress >> 1, (int) length); 00388 #endif 00389 } 00390 } else { 00391 #ifdef DEBUG_BQ27441 00392 printf("BatteryGaugeBq27441 (I2C 0x%02x): checksum on read data block incorrect (expected 0x%02x, received 0x%02x).\n", gAddress >> 1, data[2], data[1]); 00393 #endif 00394 } 00395 } else { 00396 #ifdef DEBUG_BQ27441 00397 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to read Block Data Checksum for config update.\n", gAddress >> 1); 00398 #endif 00399 } 00400 } else { 00401 #ifdef DEBUG_BQ27441 00402 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write Block Offset (%d), or possibly read the data block, for config update.\n", gAddress >> 1, data[1]); 00403 #endif 00404 } 00405 } else { 00406 #ifdef DEBUG_BQ27441 00407 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to set sub-class ID (0x%02x) for config update.\r", gAddress >> 1, subClassId); 00408 #endif 00409 } 00410 } else { 00411 #ifdef DEBUG_BQ27441 00412 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to set Block Data Control for config update.\n", gAddress >> 1); 00413 #endif 00414 } 00415 } else { 00416 #ifdef DEBUG_BQ27441 00417 printf("BatteryGaugeBq27441 (I2C 0x%02x): Flags register didn't show config update flag set in time (0x%04x).\n", gAddress >> 1, answer); 00418 #endif 00419 } 00420 } else { 00421 #ifdef DEBUG_BQ27441 00422 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write to control register for config update.\n", gAddress >> 1); 00423 #endif 00424 } 00425 } else { 00426 #ifdef DEBUG_BQ27441 00427 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to unseal chip.\n", gAddress >> 1); 00428 #endif 00429 } 00430 } else { 00431 #ifdef DEBUG_BQ27441 00432 printf("BatteryGaugeBq27441 (I2C 0x%02x): offset (%d) is in different 32 byte block to offset + length (%d) [length is %d].\n", gAddress >> 1, (int) offset, (int) (offset + length), (int) length); 00433 #endif 00434 } 00435 } 00436 00437 // If the write succeeded the exit from config update state will 00438 // re-seal things. If it failed, we need to re-seal the device 00439 // manually if it was previously sealed. 00440 if (!success && wasSealed) { 00441 if (!seal()) { 00442 success = false; 00443 } 00444 } 00445 00446 return success; 00447 } 00448 00449 00450 // Check if the chip is SEALED or UNSEALED. 00451 // Note: gpI2c should be locked before this is called. 00452 bool BatteryGaugeBq27441::isSealed(void) 00453 { 00454 bool sealed = false; 00455 char data[3]; 00456 uint16_t controlStatus; 00457 00458 // Send a control command to read the control status register 00459 data[0] = 0x00; // Set address to first register for control 00460 data[1] = 0x00; // First byte of CONTROL_STATUS sub-command (0x00) 00461 data[2] = 0x00; // Second byte of CONTROL_STATUS sub-command (0x00) (register address will auto-increment) 00462 00463 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00464 if (getTwoBytes (0, &controlStatus)) { 00465 // Bit 5 of the high byte is set to 1 if the device is sealed 00466 if (controlStatus & (1 << 13)) { 00467 sealed = true; 00468 #ifdef DEBUG_BQ27441 00469 printf("BatteryGaugeBq27441 (I2C 0x%02x): is sealed (control status 0x%04x).\r\n", gAddress >> 1, controlStatus); 00470 } else { 00471 printf("BatteryGaugeBq27441 (I2C 0x%02x): is unsealed (control status 0x%04x).\r\n", gAddress >> 1, controlStatus); 00472 #endif 00473 } 00474 } 00475 } 00476 00477 return sealed; 00478 } 00479 00480 // Put the chip into SEALED mode. 00481 // Note: gpI2c should be locked before this is called. 00482 bool BatteryGaugeBq27441::seal(void) 00483 { 00484 bool success = false; 00485 char data[3]; 00486 uint16_t controlStatus; 00487 00488 // Send a SEALED sub-command 00489 data[0] = 0x00; // Set address to first register for control 00490 data[1] = 0x20; // First byte of SEALED sub-command (0x20) 00491 data[2] = 0x00; // Second byte of SEALED sub-command (0x00) (register address will auto-increment) 00492 00493 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00494 // Check for success by reading the control status register 00495 data[0] = 0x00; // Set address to first register for control 00496 data[1] = 0x00; // First byte of CONTROL_STATUS sub-command (0x00) 00497 data[2] = 0x00; // Second byte of CONTROL_STATUS sub-command (0x00) (register address will auto-increment) 00498 00499 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00500 if (getTwoBytes (0, &controlStatus)) { 00501 // Bit 5 of the high byte is set to 1 if the device is sealed 00502 if (controlStatus & (1 << 13)) { 00503 success = true; 00504 #ifdef DEBUG_BQ27441 00505 printf("BatteryGaugeBq27441 (I2C 0x%02x): now sealed.\n", gAddress >> 1); 00506 } else { 00507 printf("BatteryGaugeBq27441 (I2C 0x%02x): seal failed (control status 0x%04x).\n", gAddress >> 1, controlStatus); 00508 #endif 00509 } 00510 } 00511 } 00512 } 00513 00514 return success; 00515 } 00516 00517 // Send the seal code to the device to unseal it. 00518 // Note: gpI2c should be locked before this is called. 00519 bool BatteryGaugeBq27441::unseal(uint16_t sealCode) 00520 { 00521 bool success = false; 00522 char data[3]; 00523 uint16_t controlStatus; 00524 00525 // Send the unseal code to the control register 00526 data[0] = 0x00; // Set address to first register for control 00527 data[1] = (char) sealCode; // First byte of code 00528 data[2] = (char) (sealCode >> 8); // Second byte of code (register address will auto-increment) 00529 00530 00531 if ((gpI2c->write(gAddress, &(data[0]), 3) == 0) && 00532 (gpI2c->write(gAddress, &(data[0]), 3) == 0)) { 00533 // Check for success by reading the control status register 00534 data[0] = 0x00; // Set address to first register for control 00535 data[1] = 0x00; // First byte of CONTROL_STATUS sub-command (0x00) 00536 data[2] = 0x00; // Second byte of CONTROL_STATUS sub-command (0x00) (register address will auto-increment) 00537 00538 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00539 if (getTwoBytes (0, &controlStatus)) { 00540 // Bit 5 of the high byte is 0 if the device is unsealed 00541 if ((controlStatus & (1 << 13)) == 0) { 00542 success = true; 00543 #ifdef DEBUG_BQ27441 00544 printf("BatteryGaugeBq27441 (I2C 0x%02x): now unsealed with seal code 0x%04x (control status 0x%04x).\n", gAddress >> 1, sealCode, controlStatus); 00545 } else { 00546 printf("BatteryGaugeBq27441 (I2C 0x%02x): unseal failed (with seal code 0x%04x, control status 0x%04x).\n", gAddress >> 1, sealCode, controlStatus); 00547 #endif 00548 } 00549 } 00550 } 00551 } 00552 00553 return success; 00554 } 00555 00556 // Make sure that the device is awake and has taken a reading. 00557 // Note: the function does its own locking of gpI2C so that it isn't 00558 // locked for the entire time we wait for ADC readings to complete. 00559 bool BatteryGaugeBq27441::makeAdcReading(void) 00560 { 00561 bool success = false; 00562 char data[3]; 00563 00564 // Send CLEAR_HIBERNATE 00565 data[0] = 0x00; // Set address to first register for control 00566 data[1] = 0x12; // First byte of CLEAR_HIBERNATE sub-command (0x12) 00567 data[2] = 0x00; // Second byte of CLEAR_HIBERNATE sub-command (0x00) (register address will auto-increment) 00568 00569 gpI2c->lock(); 00570 success = (gpI2c->write(gAddress, &(data[0]), 3) == 0); 00571 gpI2c->unlock(); 00572 wait_ms (ADC_READ_WAIT_MS); 00573 00574 return success; 00575 } 00576 00577 // Set Hibernate mode. 00578 // Note: gpI2c should be locked before this is called. 00579 bool BatteryGaugeBq27441::setHibernate(void) 00580 { 00581 char data[3]; 00582 00583 // Send SET_HIBERNATE 00584 data[0] = 0x00; // Set address to first register for control 00585 data[1] = 0x11; // First byte of SET_HIBERNATE sub-command (0x11) 00586 data[2] = 0x00; // Second byte of SET_HIBERNATE sub-command (0x00) (register address will auto-increment) 00587 00588 return (gpI2c->write(gAddress, &(data[0]), 3) == 0); 00589 } 00590 00591 //---------------------------------------------------------------- 00592 // PUBLIC FUNCTIONS 00593 // ---------------------------------------------------------------- 00594 00595 // Constructor. 00596 BatteryGaugeBq27441::BatteryGaugeBq27441(void) 00597 { 00598 gpI2c = NULL; 00599 gReady = false; 00600 gGaugeOn = false; 00601 gSealCode = 0; 00602 } 00603 00604 // Destructor. 00605 BatteryGaugeBq27441::~BatteryGaugeBq27441(void) 00606 { 00607 } 00608 00609 // Initialise ourselves. 00610 bool BatteryGaugeBq27441::init (I2C * pI2c, uint8_t address, uint16_t sealCode) 00611 { 00612 uint16_t answer; 00613 char data[4]; 00614 00615 gpI2c = pI2c; 00616 gAddress = address << 1; 00617 gSealCode = sealCode; 00618 00619 if (gpI2c != NULL) { 00620 gpI2c->lock(); 00621 00622 // Send a control command to read the firmware version 00623 data[0] = 0x00; // Set address to first register for control 00624 data[1] = 0x02; // First byte of FW_VERSION sub-command (0x02) 00625 data[2] = 0x00; // Second byte of FW_VERSION sub-command (0x00) (register address will auto-increment) 00626 00627 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00628 if (getTwoBytes (0, &answer)) { 00629 // The expected response is 0x0109 00630 if (((answer >> 8) == 0x01) && ((answer & 0xff) == 0x09)) { 00631 #ifdef DEBUG_BQ27441 00632 if (readExtendedData(112, 0, 4, &(data[0]))) { 00633 printf("BatteryGaugeBq27441 (I2C 0x%02x): seal code stored in chip is 0x%02x%02x%02x%02x.\n", gAddress >> 1, data[0], data[1], data[2], data[3]); 00634 } 00635 #endif 00636 // Set the Sleep Current to the maximum value so that, if 00637 // we tell the chip to go to sleep mode, it will do so 00638 // straight away. Sleep Current is offset 31 in the State 00639 // sub-class (82) and max value is 1000. Since offset 31 00640 // and a length of 2 crosses a 32 bytes boundary this needs 00641 // two separate writes. 00642 data[0] = (char) (1000 >> 8); 00643 data[1] = (char) 1000; 00644 00645 if (writeExtendedData(82, 31, 1, &(data[0])) && 00646 writeExtendedData(82, 32, 1, &(data[1]))) { 00647 // Now enter Hibernate mode to minimise power consumption 00648 // Need to set either the Hibernate Current or Hibernate Voltage value 00649 // to max, otherwise we won't hibernate, then set the SET_HIBERNATE 00650 // bit. Here we set Hibernate V element (offset 9) in the Power 00651 // sub-class (68) to its max value (see section 6.4.1.6.2 of the 00652 // BQ27441 technical reference manual). 00653 // Note: the cell must also be "relaxed" for this to occur and so 00654 // the chip may still not enter Hibernate mode for a little while. 00655 data[0] = (char) (5000 >> 8); 00656 data[1] = (char) 5000; 00657 00658 if (writeExtendedData(68, 9, 2, &(data[0]))) { 00659 // Now send SET_HIBERNATE 00660 gReady = setHibernate(); 00661 } 00662 } 00663 } 00664 #ifdef DEBUG_BQ27441 00665 printf("BatteryGaugeBq27441 (I2C 0x%02x): read 0x%04x as FW_VERSION, expected 0x0109.\n", gAddress >> 1, answer); 00666 #endif 00667 } 00668 } 00669 gpI2c->unlock(); 00670 } 00671 00672 #ifdef DEBUG_BQ27441 00673 if (gReady) { 00674 printf("BatteryGaugeBq27441 (I2C 0x%02x): handler initialised.\r\n", gAddress >> 1); 00675 } else { 00676 printf("BatteryGaugeBq27441 (I2C 0x%02x): init NOT successful.\r\n", gAddress >> 1); 00677 } 00678 #endif 00679 00680 return gReady; 00681 } 00682 00683 // Switch on the battery capacity monitor. 00684 bool BatteryGaugeBq27441::enableGauge (bool isSlow) 00685 { 00686 bool success = false; 00687 char data[3]; 00688 00689 if (gReady && (gpI2c != NULL)) { 00690 gpI2c->lock(); 00691 // Make sure that we are not in hibernate 00692 data[0] = 0x00; // Set address to first register for control 00693 data[1] = 0x12; // First byte of CLEAR_HIBERNATE sub-command (0x12) 00694 data[2] = 0x00; // Second byte of CLEAR_HIBERNATE sub-command (0x00) 00695 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 00696 gGaugeOn = true; 00697 // Read the OpConfig register which is in the Registers sub-class 00698 // (64) at offset 0. 00699 if (readExtendedData(64, 0, 2, &(data[0]))) { 00700 #ifdef DEBUG_BQ27441 00701 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig is 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]); 00702 #endif 00703 // SLEEP mode is bit 5 of the low byte of OpConfig. In SLEEP 00704 // mode a reading is taken every 20 seconds. 00705 if (isSlow && ((data[1] & (1 << 5)) == 0)) { 00706 // Set the SLEEP bit 'cos it's not set and needs to be 00707 data[1] |= 1 << 5; 00708 // Write the new value back 00709 success = writeExtendedData(64, 0, 2, &(data[0])); 00710 #ifdef DEBUG_BQ27441 00711 if (success) { 00712 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]); 00713 } 00714 #endif 00715 } else if (!isSlow && ((data[1] & (1 << 5)) != 0)) { 00716 // Clear the SLEEP bit 'cos it's set and shouldn't be 00717 data[1] &= ~(1 << 5); 00718 // Write the new value back 00719 success = writeExtendedData(64, 0, 2, &(data[0])); 00720 #ifdef DEBUG_BQ27441 00721 if (success) { 00722 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]); 00723 } 00724 #endif 00725 } else { 00726 success = true; 00727 } 00728 } 00729 } 00730 00731 gpI2c->unlock(); 00732 } 00733 00734 return success; 00735 } 00736 00737 // Switch off the battery capacity monitor. 00738 bool BatteryGaugeBq27441::disableGauge (void) 00739 { 00740 bool success = false; 00741 00742 if (gReady && (gpI2c != NULL)) { 00743 gpI2c->lock(); 00744 // Send SET_HIBERNATE 00745 if (setHibernate()) { 00746 success = true; 00747 gGaugeOn = false; 00748 } 00749 00750 gpI2c->unlock(); 00751 } 00752 00753 return success; 00754 } 00755 00756 // Determine whether battery gauging is enabled. 00757 bool BatteryGaugeBq27441::isGaugeEnabled(void) 00758 { 00759 return gGaugeOn; 00760 } 00761 00762 // Disable the battery detect pin. 00763 bool BatteryGaugeBq27441::disableBatteryDetect (void) 00764 { 00765 bool success = false; 00766 char data[3]; 00767 00768 if (gReady && (gpI2c != NULL)) { 00769 gpI2c->lock(); 00770 // Read the OpConfig register which is in the Registers sub-class 00771 // (64) at offset 0. 00772 if (readExtendedData(64, 0, 2, &(data[0]))) { 00773 #ifdef DEBUG_BQ27441 00774 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig is 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]); 00775 #endif 00776 // Battery Insertion Enabled is bit 5 of the high byte of OpConfig. 00777 // 1 means that the battery input pin is enabled 00778 if (((data[0] & (1 << 5)) != 0)) { 00779 // Clear the BIE bit 'cos it's set and is shouldn't be 00780 data[0] &= ~(1 << 5); 00781 // Write the new value back 00782 if (writeExtendedData(64, 0, 2, &(data[0]))) { 00783 // Send the Battery Inserted message as we can't do gauging otherwise 00784 data[0] = 0x00; // Set address to first register for control 00785 data[1] = 0x0C; // First byte of BAT_INSERT sub-command (0x0C) 00786 data[2] = 0x00; // Second byte of BAT_INSERT sub-command (0x00) 00787 success = gpI2c->write(gAddress, &(data[0]), 3) == 0; 00788 #ifdef DEBUG_BQ27441 00789 if (success) { 00790 printf("BatteryGaugeBq27441 (I2C 0x%02x): BIE disabled, BAT_INSERT sent, OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]); 00791 } 00792 #endif 00793 } 00794 } else { 00795 success = true; 00796 } 00797 } 00798 00799 // Set hibernate again if we are not monitoring 00800 if (!gGaugeOn) { 00801 setHibernate(); 00802 } 00803 00804 gpI2c->unlock(); 00805 } 00806 00807 return success; 00808 } 00809 00810 // Enable the battery detect pin. 00811 bool BatteryGaugeBq27441::enableBatteryDetect (void) 00812 { 00813 bool success = false; 00814 char data[3]; 00815 00816 if (gReady && (gpI2c != NULL)) { 00817 gpI2c->lock(); 00818 // Read the OpConfig register which is in the Registers sub-class 00819 // (64) at offset 0. 00820 if (readExtendedData(64, 0, 2, &(data[0]))) { 00821 #ifdef DEBUG_BQ27441 00822 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig is 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]); 00823 #endif 00824 // Battery Insertion Enabled is bit 5 of the high byte of OpConfig. 00825 // 1 means that the battery input pin is enabled 00826 if (((data[0] & (1 << 5)) == 0)) { 00827 // Set the BIE bit 'cos it's not set and needs to be 00828 data[0] |= 1 << 5; 00829 // Write the new value back 00830 success = writeExtendedData(64, 0, 2, &(data[0])); 00831 #ifdef DEBUG_BQ27441 00832 if (success) { 00833 printf("BatteryGaugeBq27441 (I2C 0x%02x): BIE enabled, OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]); 00834 } 00835 #endif 00836 } else { 00837 success = true; 00838 } 00839 } 00840 00841 // Set hibernate again if we are not monitoring 00842 if (!gGaugeOn) { 00843 setHibernate(); 00844 } 00845 00846 gpI2c->unlock(); 00847 } 00848 00849 return success; 00850 } 00851 00852 // Check whether a battery has been detected or not. 00853 bool BatteryGaugeBq27441::isBatteryDetected (void) 00854 { 00855 bool isDetected = false; 00856 uint16_t data; 00857 00858 if (gReady && (gpI2c != NULL)) { 00859 00860 // Make sure there's a recent reading 00861 if (gGaugeOn || makeAdcReading()) { 00862 gpI2c->lock(); 00863 // Read from the flags register address 00864 if (getTwoBytes (0x06, &data)) { 00865 00866 // If bit 3 is set then a battery has been detected 00867 if (data & (1 << 3)) { 00868 isDetected = true; 00869 } 00870 00871 #ifdef DEBUG_BQ27441 00872 if (isDetected) { 00873 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery detected (flags 0x%04x).\n", gAddress >> 1, data); 00874 } else { 00875 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery NOT detected (flags 0x%04x).\n", gAddress >> 1, data); 00876 } 00877 #endif 00878 } 00879 00880 // Set hibernate again if we are not monitoring 00881 if (!gGaugeOn) { 00882 setHibernate(); 00883 } 00884 00885 gpI2c->unlock(); 00886 } 00887 } 00888 00889 return isDetected; 00890 } 00891 00892 // Get the temperature of the chip. 00893 bool BatteryGaugeBq27441::getTemperature (int32_t *pTemperatureC) 00894 { 00895 bool success = false; 00896 int32_t temperatureC = 0; 00897 uint16_t data; 00898 00899 if (gReady && (gpI2c != NULL)) { 00900 // Make sure there's a recent reading 00901 if (gGaugeOn || makeAdcReading()) { 00902 gpI2c->lock(); 00903 // Read from the temperature register address 00904 if (getTwoBytes (0x02, &data)) { 00905 success = true; 00906 00907 // The answer is in units of 0.1 K, so convert to C 00908 temperatureC = ((int32_t) data / 10) - 273; 00909 00910 if (pTemperatureC) { 00911 *pTemperatureC = temperatureC; 00912 } 00913 00914 #ifdef DEBUG_BQ27441 00915 printf("BatteryGaugeBq27441 (I2C 0x%02x): chip temperature %.1f K, so %d C.\n", gAddress >> 1, ((float) data) / 10, (int) temperatureC); 00916 #endif 00917 } 00918 00919 // Return to sleep if we are allowed to 00920 if (!gGaugeOn && !setHibernate()) { 00921 success = false; 00922 } 00923 00924 gpI2c->unlock(); 00925 } 00926 } 00927 00928 return success; 00929 } 00930 00931 // Get the voltage of the battery. 00932 bool BatteryGaugeBq27441::getVoltage (int32_t *pVoltageMV) 00933 { 00934 bool success = false; 00935 uint16_t data = 0; 00936 00937 if (gReady && (gpI2c != NULL)) { 00938 // Make sure there's a recent reading 00939 if (gGaugeOn || makeAdcReading()) { 00940 gpI2c->lock(); 00941 // Read from the voltage register address 00942 if (getTwoBytes (0x04, &data)) { 00943 success = true; 00944 00945 // The answer is in mV 00946 if (pVoltageMV) { 00947 *pVoltageMV = (int32_t) data; 00948 } 00949 00950 #ifdef DEBUG_BQ27441 00951 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery voltage %.3f V.\n", gAddress >> 1, ((float) data) / 1000); 00952 #endif 00953 } 00954 00955 // Return to sleep if we are allowed to 00956 if (!gGaugeOn && !setHibernate()) { 00957 success = false; 00958 } 00959 00960 gpI2c->unlock(); 00961 } 00962 } 00963 00964 return success; 00965 } 00966 00967 // Get the power output of the battery 00968 bool BatteryGaugeBq27441::getPower (int32_t *pPowerMW) 00969 { 00970 bool success = false; 00971 int16_t data = 0; 00972 00973 if (gReady && (gpI2c != NULL)) { 00974 // Make sure there's a recent reading 00975 if (gGaugeOn || makeAdcReading()) { 00976 gpI2c->lock(); 00977 // Read from the power register address 00978 if (getTwoBytesSigned (0x18, &data)) { 00979 success = true; 00980 00981 // The answer is in mW 00982 if (pPowerMW) { 00983 *pPowerMW = (int32_t) data; 00984 } 00985 00986 } 00987 00988 // Return to sleep if we are allowed to 00989 if (!gGaugeOn && !setHibernate()) { 00990 success = false; 00991 } 00992 00993 gpI2c->unlock(); 00994 } 00995 } 00996 00997 return success; 00998 } 00999 01000 // Get the current flowing from the battery. 01001 bool BatteryGaugeBq27441::getCurrent (int32_t *pCurrentMA) 01002 { 01003 bool success = false; 01004 int16_t data; 01005 01006 if (gReady && (gpI2c != NULL)) { 01007 // Make sure there's a recent reading 01008 if (gGaugeOn || makeAdcReading()) { 01009 gpI2c->lock(); 01010 // Read from the average current register address 01011 if (getTwoBytesSigned (0x10, &data)) { 01012 success = true; 01013 01014 if (pCurrentMA) { 01015 *pCurrentMA = (int32_t) data; 01016 } 01017 } 01018 01019 // Return to sleep if we are allowed to 01020 if (!gGaugeOn && !setHibernate()) { 01021 success = false; 01022 } 01023 01024 gpI2c->unlock(); 01025 } 01026 } 01027 01028 return success; 01029 } 01030 01031 // Get the remaining battery capacity. 01032 bool BatteryGaugeBq27441::getRemainingCapacity (int32_t *pCapacityMAh) 01033 { 01034 bool success = false; 01035 uint16_t data = 0; 01036 01037 if (gReady && (gpI2c != NULL)) { 01038 // Make sure there's a recent reading 01039 if (gGaugeOn || makeAdcReading()) { 01040 gpI2c->lock(); 01041 // Read from the RemainingCapacity register address 01042 01043 if (getTwoBytes (0x0c, &data)) { 01044 success = true; 01045 01046 // The answer is in mAh 01047 if (pCapacityMAh) { 01048 *pCapacityMAh = (int32_t) data; 01049 } 01050 01051 #ifdef DEBUG_BQ27441 01052 printf("BatteryGaugeBq27441 (I2C 0x%02x): remaining battery capacity %u mAh.\n", gAddress >> 1, data); 01053 #endif 01054 } 01055 01056 // Return to sleep if we are allowed to 01057 if (!gGaugeOn && !setHibernate()) { 01058 success = false; 01059 } 01060 01061 gpI2c->unlock(); 01062 } 01063 } 01064 01065 return success; 01066 } 01067 01068 // Get the battery percentage remaining 01069 bool BatteryGaugeBq27441::getRemainingPercentage (int32_t *pBatteryPercent) 01070 { 01071 bool success = false; 01072 uint16_t data = 0; 01073 01074 if (gReady && (gpI2c != NULL)) { 01075 // Make sure there's a recent reading 01076 if (gGaugeOn || makeAdcReading()) { 01077 gpI2c->lock(); 01078 01079 // Wake up and take a reading if we have to 01080 if (!gGaugeOn && !setHibernate()) { 01081 success = false; 01082 } 01083 01084 // Read from the StateOfCharge register address 01085 if (getTwoBytes (0x1c, &data)) { 01086 success = true; 01087 01088 if (pBatteryPercent) { 01089 *pBatteryPercent = (int32_t) data; 01090 } 01091 01092 #ifdef DEBUG_BQ27441 01093 printf("BatteryGaugeBq27441 (I2C 0x%02x): remaining battery percentage %u%%.\n", gAddress >> 1, data); 01094 #endif 01095 } 01096 01097 // Return to sleep if we are allowed to 01098 if (!gGaugeOn && !setHibernate()) { 01099 success = false; 01100 } 01101 01102 gpI2c->unlock(); 01103 } 01104 } 01105 01106 return success; 01107 } 01108 01109 // Advanced function to read a configuration data block. 01110 bool BatteryGaugeBq27441::advancedGetConfig(uint8_t subClassId, int32_t offset, int32_t length, char * pData) 01111 { 01112 bool success = false; 01113 01114 if (gReady && (gpI2c != NULL) && (pData != NULL)) { 01115 gpI2c->lock(); 01116 // Read the extended configuration data 01117 success = readExtendedData(subClassId, offset, length, pData); 01118 #ifdef DEBUG_BQ27441 01119 if (success) { 01120 printf("BatteryGaugeBq27441 (I2C 0x%02x): read extended data with subClassId %d from offset %d.\n", gAddress >> 1, subClassId, (int) offset); 01121 } 01122 #endif 01123 01124 // Return to sleep if we are allowed to 01125 if (!gGaugeOn && !setHibernate()) { 01126 success = false; 01127 } 01128 01129 gpI2c->unlock(); 01130 } 01131 01132 return success; 01133 } 01134 01135 // Advanced function to write a configuration data block. 01136 bool BatteryGaugeBq27441::advancedSetConfig(uint8_t subClassId, int32_t offset, int32_t length, const char * pData) 01137 { 01138 bool success = false; 01139 01140 if (gReady && (gpI2c != NULL) && (pData != NULL)) { 01141 gpI2c->lock(); 01142 // Write the extended configuration data 01143 success = writeExtendedData(subClassId, offset, length, pData); 01144 #ifdef DEBUG_BQ27441 01145 if (success) { 01146 printf("BatteryGaugeBq27441 (I2C 0x%02x): written %d byte(s) of extended data with subClassId %d from offset %d.\n", gAddress >> 1, (int) length, subClassId, (int) offset); 01147 } 01148 #endif 01149 01150 // Return to sleep if we are allowed to 01151 if (!gGaugeOn && !setHibernate()) { 01152 success = false; 01153 } 01154 01155 gpI2c->unlock(); 01156 } 01157 01158 return success; 01159 } 01160 01161 // Send a control word. 01162 bool BatteryGaugeBq27441::advancedSendControlWord (uint16_t controlWord, uint16_t *pDataReturned) 01163 { 01164 bool success = false; 01165 char data[3]; 01166 01167 if (gReady && (gpI2c != NULL)) { 01168 gpI2c->lock(); 01169 // Send the control command 01170 data[0] = 0x00; // Set address to first register for control 01171 data[1] = (char) controlWord; // First byte of controlWord 01172 data[2] = (char) (controlWord >> 8); // Second byte of controlWord 01173 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 01174 // Read the two bytes returned if requested 01175 if (pDataReturned != NULL) { 01176 if (getTwoBytes(0, pDataReturned)) { 01177 success = true; 01178 #ifdef DEBUG_BQ27441 01179 printf("BatteryGaugeBq27441 (I2C 0x%02x): sent control word 0x%04x, read back 0x%04x.\n", gAddress >> 1, controlWord, *pDataReturned); 01180 #endif 01181 } 01182 } else { 01183 success = true; 01184 #ifdef DEBUG_BQ27441 01185 printf("BatteryGaugeBq27441 (I2C 0x%02x): sent control word 0x%04x.\n", gAddress >> 1, controlWord); 01186 #endif 01187 } 01188 } 01189 gpI2c->unlock(); 01190 } 01191 01192 return success; 01193 } 01194 01195 // Read two bytes starting at a given address on the chip. 01196 bool BatteryGaugeBq27441::advancedGet (uint8_t address, uint16_t *pDataReturned) 01197 { 01198 bool success = false; 01199 uint16_t value; 01200 01201 if (gReady && (gpI2c != NULL)) { 01202 // Make sure there's a recent reading, as most 01203 // of these commands involve the chip having done one 01204 if (gGaugeOn || makeAdcReading()) { 01205 gpI2c->lock(); 01206 // Read the data 01207 if (getTwoBytes(address, &value)) { 01208 success = true; 01209 #ifdef DEBUG_BQ27441 01210 printf("BatteryGaugeBq27441 (I2C 0x%02x): read 0x%04x from addresses 0x%02x and 0x%02x.\n", gAddress >> 1, value, address, address + 1); 01211 #endif 01212 if (pDataReturned != NULL) { 01213 *pDataReturned = value; 01214 } 01215 } 01216 gpI2c->unlock(); 01217 } 01218 } 01219 01220 return success; 01221 } 01222 01223 // Check if the chip is SEALED or UNSEALED. 01224 bool BatteryGaugeBq27441::advancedIsSealed() 01225 { 01226 bool sealed = false; 01227 01228 if (gReady && (gpI2c != NULL)) { 01229 gpI2c->lock(); 01230 // Check for sealedness 01231 sealed = isSealed(); 01232 01233 // Return to sleep if we are allowed to 01234 if (!gGaugeOn) { 01235 setHibernate(); 01236 } 01237 01238 gpI2c->unlock(); 01239 } 01240 01241 return sealed; 01242 } 01243 01244 // Put the chip into SEALED mode. 01245 bool BatteryGaugeBq27441::advancedSeal() 01246 { 01247 bool success = false; 01248 01249 if (gReady && (gpI2c != NULL)) { 01250 gpI2c->lock(); 01251 // Seal 01252 success = seal(); 01253 01254 // Return to sleep if we are allowed to 01255 if (!gGaugeOn && !setHibernate()) { 01256 success = false; 01257 } 01258 01259 gpI2c->unlock(); 01260 } 01261 01262 return success; 01263 } 01264 01265 // Unseal the device. 01266 bool BatteryGaugeBq27441::advancedUnseal(uint16_t sealCode) 01267 { 01268 bool success = false; 01269 char updateStatus; 01270 01271 if (gReady && (gpI2c != NULL)) { 01272 gpI2c->lock(); 01273 // Unseal and read the Update Status value 01274 if (unseal(sealCode) && readExtendedData(82, 2, 1, &updateStatus)) { 01275 // If the update status value has the top bit set then the chip will 01276 // reseal itself on the next reset, so this bit needs to be cleared to 01277 // unseal it properly 01278 if ((updateStatus & (1 << 7)) != 0) { 01279 updateStatus &= ~(1 << 7); 01280 success = writeExtendedData(82, 2, 1, &updateStatus); 01281 } else { 01282 success = true; 01283 } 01284 } 01285 01286 // Return to sleep if we are allowed to 01287 if (!gGaugeOn && !setHibernate()) { 01288 success = false; 01289 } 01290 01291 gpI2c->unlock(); 01292 } 01293 01294 return success; 01295 } 01296 01297 // Do a hard reset of the chip. 01298 bool BatteryGaugeBq27441::advancedReset(void) 01299 { 01300 bool success = false; 01301 bool wasSealed; 01302 char data[3]; 01303 01304 if (gReady && (gpI2c != NULL)) { 01305 gpI2c->lock(); 01306 01307 // Handle unsealing, as this command only works when unsealed 01308 wasSealed = isSealed(); 01309 if (!wasSealed || unseal(gSealCode)) { 01310 // Send a RESET sub-command 01311 data[0] = 0x00; // Set address to first register for control 01312 data[1] = 0x41; // First byte of RESET sub-command (0x41) 01313 data[2] = 0x00; // Second byte of RESET sub-command (0x00) (register address will auto-increment) 01314 01315 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { 01316 success = true; 01317 #ifdef DEBUG_BQ27441 01318 printf("BatteryGaugeBq27441 (I2C 0x%02x): chip hard reset.\n", gAddress >> 1); 01319 #endif 01320 } 01321 01322 // Handle re-sealing and fail if we need to re-seal but can't 01323 if (wasSealed && !seal()) { 01324 success = false; 01325 } 01326 } 01327 01328 // Return to sleep if we are allowed to 01329 if (!gGaugeOn && !setHibernate()) { 01330 success = false; 01331 } 01332 01333 gpI2c->unlock(); 01334 } 01335 01336 return success; 01337 } 01338 01339 /* End Of File */
Generated on Sat Jul 16 2022 02:44:34 by
1.7.2
