u-blox / battery-gauge-bq35100

Dependents:   example-battery-gauge-bq35100

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers bq35100.cpp Source File

bq35100.cpp

Go to the documentation of this file.
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 */