This class provides APIs to all of the registers of the TI BQ27441 battery gauge, as used on the u-blox C030 board. The caller should instantiate an I2C interface and pass this to init(), which will initialise the chip and place it into its lowest power state. When battery gauging is enabled, the getRemainingCapacity()/getRemainingPercentage() API calls may be used; otherwise the chip will be maintained in its lowest power state until a voltage/current/temperature reading is requested.

Dependents:   example-battery-gauge-bq27441

Committer:
RobMeades
Date:
Tue Apr 11 09:57:10 2017 +0000
Revision:
2:93310a83401a
Parent:
1:566163f17cde
Child:
3:ebd56471d57c
Change Doxygen comment format to match mbed on-line IDE's somewhat restrictive expectations.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rob.meades@u-blox.com 1:566163f17cde 1 /* mbed Microcontroller Library
rob.meades@u-blox.com 1:566163f17cde 2 * Copyright (c) 2017 u-blox
rob.meades@u-blox.com 1:566163f17cde 3 *
rob.meades@u-blox.com 1:566163f17cde 4 * Licensed under the Apache License, Version 2.0 (the "License");
rob.meades@u-blox.com 1:566163f17cde 5 * you may not use this file except in compliance with the License.
rob.meades@u-blox.com 1:566163f17cde 6 * You may obtain a copy of the License at
rob.meades@u-blox.com 1:566163f17cde 7 *
rob.meades@u-blox.com 1:566163f17cde 8 * http://www.apache.org/licenses/LICENSE-2.0
rob.meades@u-blox.com 1:566163f17cde 9 *
rob.meades@u-blox.com 1:566163f17cde 10 * Unless required by applicable law or agreed to in writing, software
rob.meades@u-blox.com 1:566163f17cde 11 * distributed under the License is distributed on an "AS IS" BASIS,
rob.meades@u-blox.com 1:566163f17cde 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rob.meades@u-blox.com 1:566163f17cde 13 * See the License for the specific language governing permissions and
rob.meades@u-blox.com 1:566163f17cde 14 * limitations under the License.
rob.meades@u-blox.com 1:566163f17cde 15 */
rob.meades@u-blox.com 1:566163f17cde 16
rob.meades@u-blox.com 1:566163f17cde 17 /**
rob.meades@u-blox.com 1:566163f17cde 18 * @file bq27441.cpp
rob.meades@u-blox.com 1:566163f17cde 19 * This file defines the API to the TI BQ27441 battery gauge chip.
rob.meades@u-blox.com 1:566163f17cde 20 */
rob.meades@u-blox.com 1:566163f17cde 21
RobMeades 2:93310a83401a 22 /** Define these to print debug information. */
rob.meades@u-blox.com 1:566163f17cde 23 //#define DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 24 //#define DEBUG_BQ27441_BLOCK_DATA
rob.meades@u-blox.com 1:566163f17cde 25
rob.meades@u-blox.com 1:566163f17cde 26 #include <mbed.h>
rob.meades@u-blox.com 1:566163f17cde 27 #include <battery_gauge_bq27441.h>
rob.meades@u-blox.com 1:566163f17cde 28
rob.meades@u-blox.com 1:566163f17cde 29 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 30 # include <stdio.h>
rob.meades@u-blox.com 1:566163f17cde 31 #endif
rob.meades@u-blox.com 1:566163f17cde 32
rob.meades@u-blox.com 1:566163f17cde 33 // ----------------------------------------------------------------
rob.meades@u-blox.com 1:566163f17cde 34 // COMPILE-TIME MACROS
rob.meades@u-blox.com 1:566163f17cde 35 // ----------------------------------------------------------------
rob.meades@u-blox.com 1:566163f17cde 36
RobMeades 2:93310a83401a 37 /** How many loops to wait for a configuration update to be permitted.
RobMeades 2:93310a83401a 38 * Experience suggests that the limit really does need to be this large. */
rob.meades@u-blox.com 1:566163f17cde 39 #define CONFIG_UPDATE_LOOPS 200
rob.meades@u-blox.com 1:566163f17cde 40
RobMeades 2:93310a83401a 41 /** How long to delay when running around the config update loop. */
rob.meades@u-blox.com 1:566163f17cde 42 #define CONFIG_UPDATE_LOOP_DELAY_MS 100
rob.meades@u-blox.com 1:566163f17cde 43
RobMeades 2:93310a83401a 44 /** How long to wait for all the ADC readings to be performed. */
rob.meades@u-blox.com 1:566163f17cde 45 #define ADC_READ_WAIT_MS 1000
rob.meades@u-blox.com 1:566163f17cde 46
RobMeades 2:93310a83401a 47 /** Delay after the last config update before we can unseal the
RobMeades 2:93310a83401a 48 * chip again (see section 6.4.5.1.1 of the BQ27441 technical
RobMeades 2:93310a83401a 49 * reference manual). */
rob.meades@u-blox.com 1:566163f17cde 50 #define UNSEAL_DELAY_MS 4000
rob.meades@u-blox.com 1:566163f17cde 51
rob.meades@u-blox.com 1:566163f17cde 52 // ----------------------------------------------------------------
rob.meades@u-blox.com 1:566163f17cde 53 // PRIVATE VARIABLES
rob.meades@u-blox.com 1:566163f17cde 54 // ----------------------------------------------------------------
rob.meades@u-blox.com 1:566163f17cde 55
rob.meades@u-blox.com 1:566163f17cde 56 // ----------------------------------------------------------------
rob.meades@u-blox.com 1:566163f17cde 57 // GENERIC PRIVATE FUNCTIONS
rob.meades@u-blox.com 1:566163f17cde 58 // ----------------------------------------------------------------
rob.meades@u-blox.com 1:566163f17cde 59
RobMeades 2:93310a83401a 60 // Read two bytes from an address.
rob.meades@u-blox.com 1:566163f17cde 61 // Note: gpI2c should be locked before this is called.
rob.meades@u-blox.com 1:566163f17cde 62 bool BatteryGaugeBq27441::getTwoBytes (uint8_t registerAddress, uint16_t *pBytes)
rob.meades@u-blox.com 1:566163f17cde 63 {
rob.meades@u-blox.com 1:566163f17cde 64 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 65 char data[3];
rob.meades@u-blox.com 1:566163f17cde 66
rob.meades@u-blox.com 1:566163f17cde 67 if (gpI2c != NULL) {
rob.meades@u-blox.com 1:566163f17cde 68 // Send a command to read from registerAddress
rob.meades@u-blox.com 1:566163f17cde 69 data[0] = registerAddress;
rob.meades@u-blox.com 1:566163f17cde 70 data[1] = 0;
rob.meades@u-blox.com 1:566163f17cde 71 data[2] = 0;
rob.meades@u-blox.com 1:566163f17cde 72
rob.meades@u-blox.com 1:566163f17cde 73 if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) &&
rob.meades@u-blox.com 1:566163f17cde 74 (gpI2c->read(gAddress, &(data[1]), 2) == 0)) {
rob.meades@u-blox.com 1:566163f17cde 75 success = true;
rob.meades@u-blox.com 1:566163f17cde 76 if (pBytes) {
rob.meades@u-blox.com 1:566163f17cde 77 *pBytes = (((uint16_t) data[2]) << 8) + data[1];
rob.meades@u-blox.com 1:566163f17cde 78 }
rob.meades@u-blox.com 1:566163f17cde 79 }
rob.meades@u-blox.com 1:566163f17cde 80 }
rob.meades@u-blox.com 1:566163f17cde 81
rob.meades@u-blox.com 1:566163f17cde 82 return success;
rob.meades@u-blox.com 1:566163f17cde 83 }
rob.meades@u-blox.com 1:566163f17cde 84
RobMeades 2:93310a83401a 85 // Compute the checksum over a block of data.
rob.meades@u-blox.com 1:566163f17cde 86 uint8_t BatteryGaugeBq27441::computeChecksum(const char * pData)
rob.meades@u-blox.com 1:566163f17cde 87 {
rob.meades@u-blox.com 1:566163f17cde 88 uint8_t checkSum = 0;
rob.meades@u-blox.com 1:566163f17cde 89 uint8_t x;
rob.meades@u-blox.com 1:566163f17cde 90
rob.meades@u-blox.com 1:566163f17cde 91 if (pData != NULL) {
rob.meades@u-blox.com 1:566163f17cde 92 #ifdef DEBUG_BQ27441_BLOCK_DATA
rob.meades@u-blox.com 1:566163f17cde 93 printf ("BatteryGaugeBq27441 (I2C 0x%02x): computing check sum on data block.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 94 printf (" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
rob.meades@u-blox.com 1:566163f17cde 95 #endif
rob.meades@u-blox.com 1:566163f17cde 96 for (x = 1; x <= 32; x++) {
rob.meades@u-blox.com 1:566163f17cde 97 checkSum += *pData;
rob.meades@u-blox.com 1:566163f17cde 98
rob.meades@u-blox.com 1:566163f17cde 99 #ifdef DEBUG_BQ27441_BLOCK_DATA
rob.meades@u-blox.com 1:566163f17cde 100 if (x % 16 == 8) {
rob.meades@u-blox.com 1:566163f17cde 101 printf ("%02x ", *pData);
rob.meades@u-blox.com 1:566163f17cde 102 } else if (x % 16 == 0) {
rob.meades@u-blox.com 1:566163f17cde 103 printf ("%02x\n", *pData);
rob.meades@u-blox.com 1:566163f17cde 104 } else {
rob.meades@u-blox.com 1:566163f17cde 105 printf ("%02x-", *pData);
rob.meades@u-blox.com 1:566163f17cde 106 }
rob.meades@u-blox.com 1:566163f17cde 107 #endif
rob.meades@u-blox.com 1:566163f17cde 108 pData++;
rob.meades@u-blox.com 1:566163f17cde 109 }
rob.meades@u-blox.com 1:566163f17cde 110
rob.meades@u-blox.com 1:566163f17cde 111 checkSum = 0xff - checkSum;
rob.meades@u-blox.com 1:566163f17cde 112 }
rob.meades@u-blox.com 1:566163f17cde 113
rob.meades@u-blox.com 1:566163f17cde 114 #ifdef DEBUG_BQ27441_BLOCK_DATA
rob.meades@u-blox.com 1:566163f17cde 115 if (x % 16 != 1) {
rob.meades@u-blox.com 1:566163f17cde 116 printf("\n");
rob.meades@u-blox.com 1:566163f17cde 117 }
rob.meades@u-blox.com 1:566163f17cde 118
rob.meades@u-blox.com 1:566163f17cde 119 printf ("BatteryGaugeBq27441 (I2C 0x%02x): check sum is 0x%02x.\n", gAddress >> 1, checkSum);
rob.meades@u-blox.com 1:566163f17cde 120 #endif
rob.meades@u-blox.com 1:566163f17cde 121
rob.meades@u-blox.com 1:566163f17cde 122 return checkSum;
rob.meades@u-blox.com 1:566163f17cde 123 }
rob.meades@u-blox.com 1:566163f17cde 124
RobMeades 2:93310a83401a 125 // Read data of a given length and class ID.
rob.meades@u-blox.com 1:566163f17cde 126 // Note: gpI2c should be locked before this is called.
rob.meades@u-blox.com 1:566163f17cde 127 bool BatteryGaugeBq27441::readExtendedData(uint8_t subClassId, int32_t offset, int32_t length, char * pData)
rob.meades@u-blox.com 1:566163f17cde 128 {
rob.meades@u-blox.com 1:566163f17cde 129 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 130 bool wasSealed = false;
rob.meades@u-blox.com 1:566163f17cde 131 char block[32];
rob.meades@u-blox.com 1:566163f17cde 132 char data[3];
rob.meades@u-blox.com 1:566163f17cde 133
rob.meades@u-blox.com 1:566163f17cde 134 if ((gpI2c != NULL) && (length <= 32) && (pData != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 135
rob.meades@u-blox.com 1:566163f17cde 136 // The offset + length combination must not cross a 32-byte boundary
rob.meades@u-blox.com 1:566163f17cde 137 if (offset / 32 == (offset + length - 1) / 32) {
rob.meades@u-blox.com 1:566163f17cde 138
rob.meades@u-blox.com 1:566163f17cde 139 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 140 printf("BatteryGaugeBq27441 (I2C 0x%02x): preparing to read %d byte(s) from offset %d of sub-class %d.\n", gAddress >> 1, length, offset, subClassId);
rob.meades@u-blox.com 1:566163f17cde 141 #endif
rob.meades@u-blox.com 1:566163f17cde 142 // Handle unsealing
rob.meades@u-blox.com 1:566163f17cde 143 wasSealed = isSealed();
rob.meades@u-blox.com 1:566163f17cde 144 if (!wasSealed || unseal(gSealCode)) {
rob.meades@u-blox.com 1:566163f17cde 145
rob.meades@u-blox.com 1:566163f17cde 146 // Enable Block Data Control (0x61)
rob.meades@u-blox.com 1:566163f17cde 147 data[0] = 0x61;
rob.meades@u-blox.com 1:566163f17cde 148 data[1] = 0;
rob.meades@u-blox.com 1:566163f17cde 149
rob.meades@u-blox.com 1:566163f17cde 150 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
rob.meades@u-blox.com 1:566163f17cde 151 // Write sub-class ID using Data Block Class (0x3e)
rob.meades@u-blox.com 1:566163f17cde 152 data[0] = 0x3e;
rob.meades@u-blox.com 1:566163f17cde 153 data[1] = subClassId;
rob.meades@u-blox.com 1:566163f17cde 154
rob.meades@u-blox.com 1:566163f17cde 155 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
rob.meades@u-blox.com 1:566163f17cde 156 // Write offset using Block Offset (0x3f) and then
rob.meades@u-blox.com 1:566163f17cde 157 // read the data block
rob.meades@u-blox.com 1:566163f17cde 158 data[0] = 0x3f;
rob.meades@u-blox.com 1:566163f17cde 159 data[1] = offset / 32;
rob.meades@u-blox.com 1:566163f17cde 160
rob.meades@u-blox.com 1:566163f17cde 161 if ((gpI2c->write(gAddress, &(data[0]), 2, true) == 0) &&
rob.meades@u-blox.com 1:566163f17cde 162 (gpI2c->read(gAddress, &(block[0]), 32) == 0)) {
rob.meades@u-blox.com 1:566163f17cde 163 // Compute the block checksum and then read it
rob.meades@u-blox.com 1:566163f17cde 164 data[2] = computeChecksum(&(block[0]));
rob.meades@u-blox.com 1:566163f17cde 165 data[0] = 0x60;
rob.meades@u-blox.com 1:566163f17cde 166 data[1] = 0;
rob.meades@u-blox.com 1:566163f17cde 167
rob.meades@u-blox.com 1:566163f17cde 168 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
rob.meades@u-blox.com 1:566163f17cde 169 (gpI2c->read(gAddress, &(data[1]), 1) == 0)) {
rob.meades@u-blox.com 1:566163f17cde 170
rob.meades@u-blox.com 1:566163f17cde 171 // Does the checksum match?
rob.meades@u-blox.com 1:566163f17cde 172 if (data[1] == data[2]) {
rob.meades@u-blox.com 1:566163f17cde 173 // If so read the new data from the block data area at 0x40 plus
rob.meades@u-blox.com 1:566163f17cde 174 // the offset (plus the Block Offset already written)
rob.meades@u-blox.com 1:566163f17cde 175 data[0] = 0x40 + (offset % 32);
rob.meades@u-blox.com 1:566163f17cde 176
rob.meades@u-blox.com 1:566163f17cde 177 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
rob.meades@u-blox.com 1:566163f17cde 178 (gpI2c->read(gAddress, pData, length) == 0)) {
rob.meades@u-blox.com 1:566163f17cde 179 success = true;
rob.meades@u-blox.com 1:566163f17cde 180 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 181 printf("BatteryGaugeBq27441 (I2C 0x%02x): read successful.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 182 #endif
rob.meades@u-blox.com 1:566163f17cde 183 } else {
rob.meades@u-blox.com 1:566163f17cde 184 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 185 printf("BatteryGaugeBq27441 (I2C 0x%02x): couldn't read all %d bytes of config.\r", gAddress >> 1, length);
rob.meades@u-blox.com 1:566163f17cde 186 #endif
rob.meades@u-blox.com 1:566163f17cde 187 }
rob.meades@u-blox.com 1:566163f17cde 188 } else {
rob.meades@u-blox.com 1:566163f17cde 189 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 190 printf("BatteryGaugeBq27441 (I2C 0x%02x): checksum on data block incorrect (expected 0x%02x, received 0x%02x).\n", gAddress >> 1, data[2], data[1]);
rob.meades@u-blox.com 1:566163f17cde 191 #endif
rob.meades@u-blox.com 1:566163f17cde 192 }
rob.meades@u-blox.com 1:566163f17cde 193 } else {
rob.meades@u-blox.com 1:566163f17cde 194 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 195 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to read Block Data Checksum for config.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 196 #endif
rob.meades@u-blox.com 1:566163f17cde 197 }
rob.meades@u-blox.com 1:566163f17cde 198 } else {
rob.meades@u-blox.com 1:566163f17cde 199 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 200 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write Block Offset (%d), or maybe read the data block, for config.\n", gAddress >> 1, data[1]);
rob.meades@u-blox.com 1:566163f17cde 201 #endif
rob.meades@u-blox.com 1:566163f17cde 202 }
rob.meades@u-blox.com 1:566163f17cde 203 } else {
rob.meades@u-blox.com 1:566163f17cde 204 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 205 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable set sub-class ID (0x%02x) for config.\n", gAddress >> 1, subClassId);
rob.meades@u-blox.com 1:566163f17cde 206 #endif
rob.meades@u-blox.com 1:566163f17cde 207 }
rob.meades@u-blox.com 1:566163f17cde 208 } else {
rob.meades@u-blox.com 1:566163f17cde 209 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 210 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to set Block Data Control for config.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 211 #endif
rob.meades@u-blox.com 1:566163f17cde 212 }
rob.meades@u-blox.com 1:566163f17cde 213 } else {
rob.meades@u-blox.com 1:566163f17cde 214 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 215 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to unseal chip.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 216 #endif
rob.meades@u-blox.com 1:566163f17cde 217 }
rob.meades@u-blox.com 1:566163f17cde 218 } else {
rob.meades@u-blox.com 1:566163f17cde 219 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 220 printf("BatteryGaugeBq27441 (I2C 0x%02x): offset (%d) is in different 32 byte block to offset + length (%d) [length is %d].\n", gAddress >> 1, offset, offset + length, length);
rob.meades@u-blox.com 1:566163f17cde 221 #endif
rob.meades@u-blox.com 1:566163f17cde 222 }
rob.meades@u-blox.com 1:566163f17cde 223 }
rob.meades@u-blox.com 1:566163f17cde 224
rob.meades@u-blox.com 1:566163f17cde 225 // Reseal if required, and fail if it fails
rob.meades@u-blox.com 1:566163f17cde 226 if (wasSealed) {
rob.meades@u-blox.com 1:566163f17cde 227 if (!seal()) {
rob.meades@u-blox.com 1:566163f17cde 228 success = false;
rob.meades@u-blox.com 1:566163f17cde 229 }
rob.meades@u-blox.com 1:566163f17cde 230 }
rob.meades@u-blox.com 1:566163f17cde 231
rob.meades@u-blox.com 1:566163f17cde 232 return success;
rob.meades@u-blox.com 1:566163f17cde 233 }
rob.meades@u-blox.com 1:566163f17cde 234
RobMeades 2:93310a83401a 235 // Write data of a given length and class ID to a given offset. This code taken from
rob.meades@u-blox.com 1:566163f17cde 236 // section 3.1 of the SLUUAC9A application technical reference manual with hints from:
rob.meades@u-blox.com 1:566163f17cde 237 // https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library/blob/master/src/SparkFunBQ27441.cpp.
rob.meades@u-blox.com 1:566163f17cde 238 // Note: gpI2c should be locked before this is called.
rob.meades@u-blox.com 1:566163f17cde 239 bool BatteryGaugeBq27441::writeExtendedData(uint8_t subClassId, int32_t offset, int32_t length, const char * pData)
rob.meades@u-blox.com 1:566163f17cde 240 {
rob.meades@u-blox.com 1:566163f17cde 241 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 242 bool wasSealed = false;
rob.meades@u-blox.com 1:566163f17cde 243 char data[3 + 32];
rob.meades@u-blox.com 1:566163f17cde 244 char block[32];
rob.meades@u-blox.com 1:566163f17cde 245 uint16_t answer;
rob.meades@u-blox.com 1:566163f17cde 246 uint32_t count = 0;
rob.meades@u-blox.com 1:566163f17cde 247
rob.meades@u-blox.com 1:566163f17cde 248 if ((gpI2c != NULL) && (length <= 32) && (pData != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 249
rob.meades@u-blox.com 1:566163f17cde 250 // The offset + length combination must not cross a 32-byte boundary
rob.meades@u-blox.com 1:566163f17cde 251 if (offset / 32 == (offset + length - 1) / 32) {
rob.meades@u-blox.com 1:566163f17cde 252 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 253 printf("BatteryGaugeBq27441 (I2C 0x%02x): preparing to write %d byte(s) to offset %d of sub-class %d.\n", gAddress >> 1, length, offset, subClassId);
rob.meades@u-blox.com 1:566163f17cde 254 #endif
rob.meades@u-blox.com 1:566163f17cde 255 // Handle unsealing
rob.meades@u-blox.com 1:566163f17cde 256 wasSealed = isSealed();
rob.meades@u-blox.com 1:566163f17cde 257 if (!wasSealed || unseal(gSealCode)) {
rob.meades@u-blox.com 1:566163f17cde 258
rob.meades@u-blox.com 1:566163f17cde 259 // Send Config Update (command 0x13)
rob.meades@u-blox.com 1:566163f17cde 260 data[0] = 0;
rob.meades@u-blox.com 1:566163f17cde 261 data[1] = 0x13;
rob.meades@u-blox.com 1:566163f17cde 262 data[2] = 0;
rob.meades@u-blox.com 1:566163f17cde 263
rob.meades@u-blox.com 1:566163f17cde 264 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 265 // Wait for CONFIGUPDATE to be set in Flags register (bit 4)
rob.meades@u-blox.com 1:566163f17cde 266 count = 0;
rob.meades@u-blox.com 1:566163f17cde 267 do {
rob.meades@u-blox.com 1:566163f17cde 268 answer = 0;
rob.meades@u-blox.com 1:566163f17cde 269 getTwoBytes(0x06, &answer);
rob.meades@u-blox.com 1:566163f17cde 270 count++;
rob.meades@u-blox.com 1:566163f17cde 271 wait_ms(CONFIG_UPDATE_LOOP_DELAY_MS);
rob.meades@u-blox.com 1:566163f17cde 272 } while (((answer & (1 << 4)) == 0) && (count < CONFIG_UPDATE_LOOPS));
rob.meades@u-blox.com 1:566163f17cde 273
rob.meades@u-blox.com 1:566163f17cde 274 if ((answer & (1 << 4)) != 0) {
rob.meades@u-blox.com 1:566163f17cde 275 // Enable Block Data Control (0x61)
rob.meades@u-blox.com 1:566163f17cde 276 data[0] = 0x61;
rob.meades@u-blox.com 1:566163f17cde 277 data[1] = 0;
rob.meades@u-blox.com 1:566163f17cde 278
rob.meades@u-blox.com 1:566163f17cde 279 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
rob.meades@u-blox.com 1:566163f17cde 280 // Write sub-class ID using Data Block Class (0x3e)
rob.meades@u-blox.com 1:566163f17cde 281 data[0] = 0x3e;
rob.meades@u-blox.com 1:566163f17cde 282 data[1] = subClassId;
rob.meades@u-blox.com 1:566163f17cde 283
rob.meades@u-blox.com 1:566163f17cde 284 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
rob.meades@u-blox.com 1:566163f17cde 285 // Write offset using Block Offset (0x3f) and then
rob.meades@u-blox.com 1:566163f17cde 286 // read the data block
rob.meades@u-blox.com 1:566163f17cde 287 data[0] = 0x3f;
rob.meades@u-blox.com 1:566163f17cde 288 data[1] = offset / 32;
rob.meades@u-blox.com 1:566163f17cde 289
rob.meades@u-blox.com 1:566163f17cde 290 if ((gpI2c->write(gAddress, &(data[0]), 2, true) == 0) &&
rob.meades@u-blox.com 1:566163f17cde 291 (gpI2c->read(gAddress, &(block[0]), 32) == 0)) {
rob.meades@u-blox.com 1:566163f17cde 292 // Compute the existing block checksum and then read it
rob.meades@u-blox.com 1:566163f17cde 293 data[2] = computeChecksum(&(block[0]));
rob.meades@u-blox.com 1:566163f17cde 294 data[0] = 0x60;
rob.meades@u-blox.com 1:566163f17cde 295 data[1] = 0;
rob.meades@u-blox.com 1:566163f17cde 296
rob.meades@u-blox.com 1:566163f17cde 297 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
rob.meades@u-blox.com 1:566163f17cde 298 (gpI2c->read(gAddress, &(data[1]), 1) == 0)) {
rob.meades@u-blox.com 1:566163f17cde 299
rob.meades@u-blox.com 1:566163f17cde 300 // Does the checksum match?
rob.meades@u-blox.com 1:566163f17cde 301 if (data[1] == data[2]) {
rob.meades@u-blox.com 1:566163f17cde 302 // If so write the new data to the block data area at 0x40 plus the offset (plus the Block Offset already written)
rob.meades@u-blox.com 1:566163f17cde 303 // NOTE: I tried doing this as two separate writes, one of the offset and then another of the
rob.meades@u-blox.com 1:566163f17cde 304 // data block (so that I could use pData directly rather than having to extend the local
rob.meades@u-blox.com 1:566163f17cde 305 // data array by 32) but the chip didn't like that, hence we have to copy pData into the
rob.meades@u-blox.com 1:566163f17cde 306 // local array and do a single contiguous write.
rob.meades@u-blox.com 1:566163f17cde 307 data[0] = 0x40 + (offset % 32);
rob.meades@u-blox.com 1:566163f17cde 308 memcpy (&(data[1]), pData, length);
rob.meades@u-blox.com 1:566163f17cde 309
rob.meades@u-blox.com 1:566163f17cde 310 if (gpI2c->write(gAddress, &(data[0]), length + 1) == 0) {
rob.meades@u-blox.com 1:566163f17cde 311 // Also write the data into our local block variable
rob.meades@u-blox.com 1:566163f17cde 312 // on top of the previously read data and use
rob.meades@u-blox.com 1:566163f17cde 313 // that to compute the new block checksum, then write it
rob.meades@u-blox.com 1:566163f17cde 314 memcpy (&(block[offset % 32]), pData, length);
rob.meades@u-blox.com 1:566163f17cde 315 data[0] = 0x60;
rob.meades@u-blox.com 1:566163f17cde 316 data[1] = computeChecksum(&(block[0]));
rob.meades@u-blox.com 1:566163f17cde 317
rob.meades@u-blox.com 1:566163f17cde 318 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
rob.meades@u-blox.com 1:566163f17cde 319 // Exit config mode with SOFT_RESET command 0x42
rob.meades@u-blox.com 1:566163f17cde 320 data[0] = 0;
rob.meades@u-blox.com 1:566163f17cde 321 data[1] = 0x42;
rob.meades@u-blox.com 1:566163f17cde 322 data[2] = 0;
rob.meades@u-blox.com 1:566163f17cde 323
rob.meades@u-blox.com 1:566163f17cde 324 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 325 // Finally, wait for CONFIGUPDATE to be unset in Flags register (bit 4)
rob.meades@u-blox.com 1:566163f17cde 326 count = 0;
rob.meades@u-blox.com 1:566163f17cde 327 do {
rob.meades@u-blox.com 1:566163f17cde 328 answer = 0xFFFF;
rob.meades@u-blox.com 1:566163f17cde 329 getTwoBytes(0x06, &answer);
rob.meades@u-blox.com 1:566163f17cde 330 count++;
rob.meades@u-blox.com 1:566163f17cde 331 wait_ms(CONFIG_UPDATE_LOOP_DELAY_MS);
rob.meades@u-blox.com 1:566163f17cde 332 } while (((answer & (1 << 4)) != 0) && (count < CONFIG_UPDATE_LOOPS));
rob.meades@u-blox.com 1:566163f17cde 333
rob.meades@u-blox.com 1:566163f17cde 334 if ((answer & (1 << 4)) == 0) {
rob.meades@u-blox.com 1:566163f17cde 335 success = true;
rob.meades@u-blox.com 1:566163f17cde 336 // Wait around for 4 seconds if there has been a config update
rob.meades@u-blox.com 1:566163f17cde 337 // and there is a danger that we might have to unseal the device
rob.meades@u-blox.com 1:566163f17cde 338 // Note: would be nice if we could note the time and do other
rob.meades@u-blox.com 1:566163f17cde 339 // things but the timer is restarted when certain commands are sent,
rob.meades@u-blox.com 1:566163f17cde 340 // so it is better to be dumb
rob.meades@u-blox.com 1:566163f17cde 341 if (wasSealed) {
rob.meades@u-blox.com 1:566163f17cde 342 wait_ms(UNSEAL_DELAY_MS);
rob.meades@u-blox.com 1:566163f17cde 343 }
rob.meades@u-blox.com 1:566163f17cde 344 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 345 printf("BatteryGaugeBq27441 (I2C 0x%02x): write successful.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 346 #endif
rob.meades@u-blox.com 1:566163f17cde 347 } else {
rob.meades@u-blox.com 1:566163f17cde 348 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 349 printf("BatteryGaugeBq27441 (I2C 0x%02x): Flags register didn't show config update flag unset in time (0x%04x).\n", gAddress >> 1, answer);
rob.meades@u-blox.com 1:566163f17cde 350 #endif
rob.meades@u-blox.com 1:566163f17cde 351 }
rob.meades@u-blox.com 1:566163f17cde 352 } else {
rob.meades@u-blox.com 1:566163f17cde 353 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 354 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write config update exit after update.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 355 #endif
rob.meades@u-blox.com 1:566163f17cde 356 }
rob.meades@u-blox.com 1:566163f17cde 357 } else {
rob.meades@u-blox.com 1:566163f17cde 358 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 359 printf("BatteryGaugeBq27441 (I2C 0x%02x): checksum on modified data block incorrect (0x%02x) during config update.\n", gAddress >> 1, data[1]);
rob.meades@u-blox.com 1:566163f17cde 360 #endif
rob.meades@u-blox.com 1:566163f17cde 361 }
rob.meades@u-blox.com 1:566163f17cde 362 } else {
rob.meades@u-blox.com 1:566163f17cde 363 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 364 printf("BatteryGaugeBq27441 (I2C 0x%02x): couldn't write all %d bytes during config update.\n", gAddress >> 1, length);
rob.meades@u-blox.com 1:566163f17cde 365 #endif
rob.meades@u-blox.com 1:566163f17cde 366 }
rob.meades@u-blox.com 1:566163f17cde 367 } else {
rob.meades@u-blox.com 1:566163f17cde 368 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 369 printf("BatteryGaugeBq27441 (I2C 0x%02x): checksum on read data block incorrect (expected 0x%02x, received 0x%02x).\n", gAddress >> 1, data[2], data[1]);
rob.meades@u-blox.com 1:566163f17cde 370 #endif
rob.meades@u-blox.com 1:566163f17cde 371 }
rob.meades@u-blox.com 1:566163f17cde 372 } else {
rob.meades@u-blox.com 1:566163f17cde 373 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 374 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to read Block Data Checksum for config update.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 375 #endif
rob.meades@u-blox.com 1:566163f17cde 376 }
rob.meades@u-blox.com 1:566163f17cde 377 } else {
rob.meades@u-blox.com 1:566163f17cde 378 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 379 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]);
rob.meades@u-blox.com 1:566163f17cde 380 #endif
rob.meades@u-blox.com 1:566163f17cde 381 }
rob.meades@u-blox.com 1:566163f17cde 382 } else {
rob.meades@u-blox.com 1:566163f17cde 383 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 384 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to set sub-class ID (0x%02x) for config update.\r", gAddress >> 1, subClassId);
rob.meades@u-blox.com 1:566163f17cde 385 #endif
rob.meades@u-blox.com 1:566163f17cde 386 }
rob.meades@u-blox.com 1:566163f17cde 387 } else {
rob.meades@u-blox.com 1:566163f17cde 388 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 389 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to set Block Data Control for config update.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 390 #endif
rob.meades@u-blox.com 1:566163f17cde 391 }
rob.meades@u-blox.com 1:566163f17cde 392 } else {
rob.meades@u-blox.com 1:566163f17cde 393 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 394 printf("BatteryGaugeBq27441 (I2C 0x%02x): Flags register didn't show config update flag set in time (0x%04x).\n", gAddress >> 1, answer);
rob.meades@u-blox.com 1:566163f17cde 395 #endif
rob.meades@u-blox.com 1:566163f17cde 396 }
rob.meades@u-blox.com 1:566163f17cde 397 } else {
rob.meades@u-blox.com 1:566163f17cde 398 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 399 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write to control register for config update.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 400 #endif
rob.meades@u-blox.com 1:566163f17cde 401 }
rob.meades@u-blox.com 1:566163f17cde 402 } else {
rob.meades@u-blox.com 1:566163f17cde 403 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 404 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to unseal chip.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 405 #endif
rob.meades@u-blox.com 1:566163f17cde 406 }
rob.meades@u-blox.com 1:566163f17cde 407 } else {
rob.meades@u-blox.com 1:566163f17cde 408 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 409 printf("BatteryGaugeBq27441 (I2C 0x%02x): offset (%d) is in different 32 byte block to offset + length (%d) [length is %d].\n", gAddress >> 1, offset, offset + length, length);
rob.meades@u-blox.com 1:566163f17cde 410 #endif
rob.meades@u-blox.com 1:566163f17cde 411 }
rob.meades@u-blox.com 1:566163f17cde 412 }
rob.meades@u-blox.com 1:566163f17cde 413
rob.meades@u-blox.com 1:566163f17cde 414 // If the write succeeded the exit from config update state will
rob.meades@u-blox.com 1:566163f17cde 415 // re-seal things. If it failed, we need to re-seal the device
rob.meades@u-blox.com 1:566163f17cde 416 // manually if it was previously sealed.
rob.meades@u-blox.com 1:566163f17cde 417 if (!success && wasSealed) {
rob.meades@u-blox.com 1:566163f17cde 418 if (!seal()) {
rob.meades@u-blox.com 1:566163f17cde 419 success = false;
rob.meades@u-blox.com 1:566163f17cde 420 }
rob.meades@u-blox.com 1:566163f17cde 421 }
rob.meades@u-blox.com 1:566163f17cde 422
rob.meades@u-blox.com 1:566163f17cde 423 return success;
rob.meades@u-blox.com 1:566163f17cde 424 }
rob.meades@u-blox.com 1:566163f17cde 425
rob.meades@u-blox.com 1:566163f17cde 426
RobMeades 2:93310a83401a 427 // Check if the chip is SEALED or UNSEALED.
rob.meades@u-blox.com 1:566163f17cde 428 // Note: gpI2c should be locked before this is called.
rob.meades@u-blox.com 1:566163f17cde 429 bool BatteryGaugeBq27441::isSealed(void)
rob.meades@u-blox.com 1:566163f17cde 430 {
rob.meades@u-blox.com 1:566163f17cde 431 bool sealed = false;
rob.meades@u-blox.com 1:566163f17cde 432 char data[3];
rob.meades@u-blox.com 1:566163f17cde 433 uint16_t controlStatus;
rob.meades@u-blox.com 1:566163f17cde 434
rob.meades@u-blox.com 1:566163f17cde 435 // Send a control command to read the control status register
rob.meades@u-blox.com 1:566163f17cde 436 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 437 data[1] = 0x00; // First byte of CONTROL_STATUS sub-command (0x00)
rob.meades@u-blox.com 1:566163f17cde 438 data[2] = 0x00; // Second byte of CONTROL_STATUS sub-command (0x00) (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 439
rob.meades@u-blox.com 1:566163f17cde 440 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 441 if (getTwoBytes (0, &controlStatus)) {
rob.meades@u-blox.com 1:566163f17cde 442 // Bit 5 of the high byte is set to 1 if the device is sealed
rob.meades@u-blox.com 1:566163f17cde 443 if (controlStatus & (1 << 13)) {
rob.meades@u-blox.com 1:566163f17cde 444 sealed = true;
rob.meades@u-blox.com 1:566163f17cde 445 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 446 printf("BatteryGaugeBq27441 (I2C 0x%02x): is sealed (control status 0x%04x).\r\n", gAddress >> 1, controlStatus);
rob.meades@u-blox.com 1:566163f17cde 447 } else {
rob.meades@u-blox.com 1:566163f17cde 448 printf("BatteryGaugeBq27441 (I2C 0x%02x): is unsealed (control status 0x%04x).\r\n", gAddress >> 1, controlStatus);
rob.meades@u-blox.com 1:566163f17cde 449 #endif
rob.meades@u-blox.com 1:566163f17cde 450 }
rob.meades@u-blox.com 1:566163f17cde 451 }
rob.meades@u-blox.com 1:566163f17cde 452 }
rob.meades@u-blox.com 1:566163f17cde 453
rob.meades@u-blox.com 1:566163f17cde 454 return sealed;
rob.meades@u-blox.com 1:566163f17cde 455 }
rob.meades@u-blox.com 1:566163f17cde 456
RobMeades 2:93310a83401a 457 // Put the chip into SEALED mode.
rob.meades@u-blox.com 1:566163f17cde 458 // Note: gpI2c should be locked before this is called.
rob.meades@u-blox.com 1:566163f17cde 459 bool BatteryGaugeBq27441::seal(void)
rob.meades@u-blox.com 1:566163f17cde 460 {
rob.meades@u-blox.com 1:566163f17cde 461 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 462 char data[3];
rob.meades@u-blox.com 1:566163f17cde 463 uint16_t controlStatus;
rob.meades@u-blox.com 1:566163f17cde 464
rob.meades@u-blox.com 1:566163f17cde 465 // Send a SEALED sub-command
rob.meades@u-blox.com 1:566163f17cde 466 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 467 data[1] = 0x20; // First byte of SEALED sub-command (0x20)
rob.meades@u-blox.com 1:566163f17cde 468 data[2] = 0x00; // Second byte of SEALED sub-command (0x00) (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 469
rob.meades@u-blox.com 1:566163f17cde 470 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 471 // Check for success by reading the control status register
rob.meades@u-blox.com 1:566163f17cde 472 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 473 data[1] = 0x00; // First byte of CONTROL_STATUS sub-command (0x00)
rob.meades@u-blox.com 1:566163f17cde 474 data[2] = 0x00; // Second byte of CONTROL_STATUS sub-command (0x00) (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 475
rob.meades@u-blox.com 1:566163f17cde 476 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 477 if (getTwoBytes (0, &controlStatus)) {
rob.meades@u-blox.com 1:566163f17cde 478 // Bit 5 of the high byte is set to 1 if the device is sealed
rob.meades@u-blox.com 1:566163f17cde 479 if (controlStatus & (1 << 13)) {
rob.meades@u-blox.com 1:566163f17cde 480 success = true;
rob.meades@u-blox.com 1:566163f17cde 481 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 482 printf("BatteryGaugeBq27441 (I2C 0x%02x): now sealed.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 483 } else {
rob.meades@u-blox.com 1:566163f17cde 484 printf("BatteryGaugeBq27441 (I2C 0x%02x): seal failed (control status 0x%04x).\n", gAddress >> 1, controlStatus);
rob.meades@u-blox.com 1:566163f17cde 485 #endif
rob.meades@u-blox.com 1:566163f17cde 486 }
rob.meades@u-blox.com 1:566163f17cde 487 }
rob.meades@u-blox.com 1:566163f17cde 488 }
rob.meades@u-blox.com 1:566163f17cde 489 }
rob.meades@u-blox.com 1:566163f17cde 490
rob.meades@u-blox.com 1:566163f17cde 491 return success;
rob.meades@u-blox.com 1:566163f17cde 492 }
rob.meades@u-blox.com 1:566163f17cde 493
RobMeades 2:93310a83401a 494 // Send the seal code to the device to unseal it.
rob.meades@u-blox.com 1:566163f17cde 495 // Note: gpI2c should be locked before this is called.
rob.meades@u-blox.com 1:566163f17cde 496 bool BatteryGaugeBq27441::unseal(uint16_t sealCode)
rob.meades@u-blox.com 1:566163f17cde 497 {
rob.meades@u-blox.com 1:566163f17cde 498 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 499 char data[3];
rob.meades@u-blox.com 1:566163f17cde 500 uint16_t controlStatus;
rob.meades@u-blox.com 1:566163f17cde 501
rob.meades@u-blox.com 1:566163f17cde 502 // Send the unseal code to the control register
rob.meades@u-blox.com 1:566163f17cde 503 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 504 data[1] = (char) sealCode; // First byte of code
rob.meades@u-blox.com 1:566163f17cde 505 data[2] = (char) (sealCode >> 8); // Second byte of code (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 506
rob.meades@u-blox.com 1:566163f17cde 507
rob.meades@u-blox.com 1:566163f17cde 508 if ((gpI2c->write(gAddress, &(data[0]), 3) == 0) &&
rob.meades@u-blox.com 1:566163f17cde 509 (gpI2c->write(gAddress, &(data[0]), 3) == 0)) {
rob.meades@u-blox.com 1:566163f17cde 510 // Check for success by reading the control status register
rob.meades@u-blox.com 1:566163f17cde 511 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 512 data[1] = 0x00; // First byte of CONTROL_STATUS sub-command (0x00)
rob.meades@u-blox.com 1:566163f17cde 513 data[2] = 0x00; // Second byte of CONTROL_STATUS sub-command (0x00) (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 514
rob.meades@u-blox.com 1:566163f17cde 515 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 516 if (getTwoBytes (0, &controlStatus)) {
rob.meades@u-blox.com 1:566163f17cde 517 // Bit 5 of the high byte is 0 if the device is unsealed
rob.meades@u-blox.com 1:566163f17cde 518 if ((controlStatus & (1 << 13)) == 0) {
rob.meades@u-blox.com 1:566163f17cde 519 success = true;
rob.meades@u-blox.com 1:566163f17cde 520 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 521 printf("BatteryGaugeBq27441 (I2C 0x%02x): now unsealed with seal code 0x%04x (control status 0x%04x).\n", gAddress >> 1, sealCode, controlStatus);
rob.meades@u-blox.com 1:566163f17cde 522 } else {
rob.meades@u-blox.com 1:566163f17cde 523 printf("BatteryGaugeBq27441 (I2C 0x%02x): unseal failed (with seal code 0x%04x, control status 0x%04x).\n", gAddress >> 1, sealCode, controlStatus);
rob.meades@u-blox.com 1:566163f17cde 524 #endif
rob.meades@u-blox.com 1:566163f17cde 525 }
rob.meades@u-blox.com 1:566163f17cde 526 }
rob.meades@u-blox.com 1:566163f17cde 527 }
rob.meades@u-blox.com 1:566163f17cde 528 }
rob.meades@u-blox.com 1:566163f17cde 529
rob.meades@u-blox.com 1:566163f17cde 530 return success;
rob.meades@u-blox.com 1:566163f17cde 531 }
rob.meades@u-blox.com 1:566163f17cde 532
RobMeades 2:93310a83401a 533 // Make sure that the device is awake and has taken a reading.
rob.meades@u-blox.com 1:566163f17cde 534 // Note: the function does its own locking of gpI2C so that it isn't
rob.meades@u-blox.com 1:566163f17cde 535 // locked for the entire time we wait for ADC readings to complete.
rob.meades@u-blox.com 1:566163f17cde 536 bool BatteryGaugeBq27441::makeAdcReading(void)
rob.meades@u-blox.com 1:566163f17cde 537 {
rob.meades@u-blox.com 1:566163f17cde 538 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 539 char data[3];
rob.meades@u-blox.com 1:566163f17cde 540
rob.meades@u-blox.com 1:566163f17cde 541 // Send CLEAR_HIBERNATE
rob.meades@u-blox.com 1:566163f17cde 542 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 543 data[1] = 0x12; // First byte of CLEAR_HIBERNATE sub-command (0x12)
rob.meades@u-blox.com 1:566163f17cde 544 data[2] = 0x00; // Second byte of CLEAR_HIBERNATE sub-command (0x00) (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 545
rob.meades@u-blox.com 1:566163f17cde 546 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 547 success = (gpI2c->write(gAddress, &(data[0]), 3) == 0);
rob.meades@u-blox.com 1:566163f17cde 548 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 549 wait_ms (ADC_READ_WAIT_MS);
rob.meades@u-blox.com 1:566163f17cde 550
rob.meades@u-blox.com 1:566163f17cde 551 return success;
rob.meades@u-blox.com 1:566163f17cde 552 }
rob.meades@u-blox.com 1:566163f17cde 553
RobMeades 2:93310a83401a 554 // Set Hibernate mode.
rob.meades@u-blox.com 1:566163f17cde 555 // Note: gpI2c should be locked before this is called.
rob.meades@u-blox.com 1:566163f17cde 556 bool BatteryGaugeBq27441::setHibernate(void)
rob.meades@u-blox.com 1:566163f17cde 557 {
rob.meades@u-blox.com 1:566163f17cde 558 char data[3];
rob.meades@u-blox.com 1:566163f17cde 559
rob.meades@u-blox.com 1:566163f17cde 560 // Send SET_HIBERNATE
rob.meades@u-blox.com 1:566163f17cde 561 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 562 data[1] = 0x11; // First byte of SET_HIBERNATE sub-command (0x11)
rob.meades@u-blox.com 1:566163f17cde 563 data[2] = 0x00; // Second byte of SET_HIBERNATE sub-command (0x00) (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 564
rob.meades@u-blox.com 1:566163f17cde 565 return (gpI2c->write(gAddress, &(data[0]), 3) == 0);
rob.meades@u-blox.com 1:566163f17cde 566 }
rob.meades@u-blox.com 1:566163f17cde 567
rob.meades@u-blox.com 1:566163f17cde 568 //----------------------------------------------------------------
rob.meades@u-blox.com 1:566163f17cde 569 // PUBLIC FUNCTIONS
rob.meades@u-blox.com 1:566163f17cde 570 // ----------------------------------------------------------------
rob.meades@u-blox.com 1:566163f17cde 571
RobMeades 2:93310a83401a 572 // Constructor.
rob.meades@u-blox.com 1:566163f17cde 573 BatteryGaugeBq27441::BatteryGaugeBq27441(void)
rob.meades@u-blox.com 1:566163f17cde 574 {
rob.meades@u-blox.com 1:566163f17cde 575 gpI2c = NULL;
rob.meades@u-blox.com 1:566163f17cde 576 gReady = false;
rob.meades@u-blox.com 1:566163f17cde 577 gGaugeOn = false;
rob.meades@u-blox.com 1:566163f17cde 578 gSealCode = 0;
rob.meades@u-blox.com 1:566163f17cde 579 }
rob.meades@u-blox.com 1:566163f17cde 580
RobMeades 2:93310a83401a 581 // Destructor.
rob.meades@u-blox.com 1:566163f17cde 582 BatteryGaugeBq27441::~BatteryGaugeBq27441(void)
rob.meades@u-blox.com 1:566163f17cde 583 {
rob.meades@u-blox.com 1:566163f17cde 584 }
rob.meades@u-blox.com 1:566163f17cde 585
RobMeades 2:93310a83401a 586 // Initialise ourselves.
rob.meades@u-blox.com 1:566163f17cde 587 bool BatteryGaugeBq27441::init (I2C * pI2c, uint8_t address, uint16_t sealCode)
rob.meades@u-blox.com 1:566163f17cde 588 {
rob.meades@u-blox.com 1:566163f17cde 589 uint16_t answer;
rob.meades@u-blox.com 1:566163f17cde 590 char data[4];
rob.meades@u-blox.com 1:566163f17cde 591
rob.meades@u-blox.com 1:566163f17cde 592 gpI2c = pI2c;
rob.meades@u-blox.com 1:566163f17cde 593 gAddress = address << 1;
rob.meades@u-blox.com 1:566163f17cde 594 gSealCode = sealCode;
rob.meades@u-blox.com 1:566163f17cde 595
rob.meades@u-blox.com 1:566163f17cde 596 if (gpI2c != NULL) {
rob.meades@u-blox.com 1:566163f17cde 597 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 598
rob.meades@u-blox.com 1:566163f17cde 599 // Send a control command to read the firmware version
rob.meades@u-blox.com 1:566163f17cde 600 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 601 data[1] = 0x02; // First byte of FW_VERSION sub-command (0x02)
rob.meades@u-blox.com 1:566163f17cde 602 data[2] = 0x00; // Second byte of FW_VERSION sub-command (0x00) (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 603
rob.meades@u-blox.com 1:566163f17cde 604 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 605 if (getTwoBytes (0, &answer)) {
rob.meades@u-blox.com 1:566163f17cde 606 // The expected response is 0x0109
rob.meades@u-blox.com 1:566163f17cde 607 if (((answer >> 8) == 0x01) && ((answer & 0xff) == 0x09)) {
rob.meades@u-blox.com 1:566163f17cde 608 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 609 if (readExtendedData(112, 0, 4, &(data[0]))) {
rob.meades@u-blox.com 1:566163f17cde 610 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]);
rob.meades@u-blox.com 1:566163f17cde 611 }
rob.meades@u-blox.com 1:566163f17cde 612 #endif
rob.meades@u-blox.com 1:566163f17cde 613 // Set the Sleep Current to the maximum value so that, if
rob.meades@u-blox.com 1:566163f17cde 614 // we tell the chip to go to sleep mode, it will do so
rob.meades@u-blox.com 1:566163f17cde 615 // straight away. Sleep Current is offset 31 in the State
rob.meades@u-blox.com 1:566163f17cde 616 // sub-class (82) and max value is 1000. Since offset 31
rob.meades@u-blox.com 1:566163f17cde 617 // and a length of 2 crosses a 32 bytes boundary this needs
rob.meades@u-blox.com 1:566163f17cde 618 // two separate writes.
rob.meades@u-blox.com 1:566163f17cde 619 data[0] = (char) (1000 >> 8);
rob.meades@u-blox.com 1:566163f17cde 620 data[1] = (char) 1000;
rob.meades@u-blox.com 1:566163f17cde 621
rob.meades@u-blox.com 1:566163f17cde 622 if (writeExtendedData(82, 31, 1, &(data[0])) &&
rob.meades@u-blox.com 1:566163f17cde 623 writeExtendedData(82, 32, 1, &(data[1]))) {
rob.meades@u-blox.com 1:566163f17cde 624 // Now enter Hibernate mode to minimise power consumption
rob.meades@u-blox.com 1:566163f17cde 625 // Need to set either the Hibernate Current or Hibernate Voltage value
rob.meades@u-blox.com 1:566163f17cde 626 // to max, otherwise we won't hibernate, then set the SET_HIBERNATE
rob.meades@u-blox.com 1:566163f17cde 627 // bit. Here we set Hibernate V element (offset 9) in the Power
rob.meades@u-blox.com 1:566163f17cde 628 // sub-class (68) to its max value (see section 6.4.1.6.2 of the
rob.meades@u-blox.com 1:566163f17cde 629 // BQ27441 technical reference manual).
rob.meades@u-blox.com 1:566163f17cde 630 // Note: the cell must also be "relaxed" for this to occur and so
rob.meades@u-blox.com 1:566163f17cde 631 // the chip may still not enter Hibernate mode for a little while.
rob.meades@u-blox.com 1:566163f17cde 632 data[0] = (char) (5000 >> 8);
rob.meades@u-blox.com 1:566163f17cde 633 data[1] = (char) 5000;
rob.meades@u-blox.com 1:566163f17cde 634
rob.meades@u-blox.com 1:566163f17cde 635 if (writeExtendedData(68, 9, 2, &(data[0]))) {
rob.meades@u-blox.com 1:566163f17cde 636 // Now send SET_HIBERNATE
rob.meades@u-blox.com 1:566163f17cde 637 gReady = setHibernate();
rob.meades@u-blox.com 1:566163f17cde 638 }
rob.meades@u-blox.com 1:566163f17cde 639 }
rob.meades@u-blox.com 1:566163f17cde 640 }
rob.meades@u-blox.com 1:566163f17cde 641 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 642 printf("BatteryGaugeBq27441 (I2C 0x%02x): read 0x%04x as FW_VERSION, expected 0x0109.\n", gAddress >> 1, answer);
rob.meades@u-blox.com 1:566163f17cde 643 #endif
rob.meades@u-blox.com 1:566163f17cde 644 }
rob.meades@u-blox.com 1:566163f17cde 645 }
rob.meades@u-blox.com 1:566163f17cde 646 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 647 }
rob.meades@u-blox.com 1:566163f17cde 648
rob.meades@u-blox.com 1:566163f17cde 649 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 650 if (gReady) {
rob.meades@u-blox.com 1:566163f17cde 651 printf("BatteryGaugeBq27441 (I2C 0x%02x): handler initialised.\r\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 652 } else {
rob.meades@u-blox.com 1:566163f17cde 653 printf("BatteryGaugeBq27441 (I2C 0x%02x): init NOT successful.\r\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 654 }
rob.meades@u-blox.com 1:566163f17cde 655 #endif
rob.meades@u-blox.com 1:566163f17cde 656
rob.meades@u-blox.com 1:566163f17cde 657 return gReady;
rob.meades@u-blox.com 1:566163f17cde 658 }
rob.meades@u-blox.com 1:566163f17cde 659
RobMeades 2:93310a83401a 660 // Switch on the battery capacity monitor.
rob.meades@u-blox.com 1:566163f17cde 661 bool BatteryGaugeBq27441::enableGauge (bool isSlow)
rob.meades@u-blox.com 1:566163f17cde 662 {
rob.meades@u-blox.com 1:566163f17cde 663 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 664 char data[3];
rob.meades@u-blox.com 1:566163f17cde 665
rob.meades@u-blox.com 1:566163f17cde 666 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 667 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 668 // Make sure that we are not in hibernate
rob.meades@u-blox.com 1:566163f17cde 669 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 670 data[1] = 0x12; // First byte of CLEAR_HIBERNATE sub-command (0x12)
rob.meades@u-blox.com 1:566163f17cde 671 data[2] = 0x00; // Second byte of CLEAR_HIBERNATE sub-command (0x00)
rob.meades@u-blox.com 1:566163f17cde 672 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 673 gGaugeOn = true;
rob.meades@u-blox.com 1:566163f17cde 674 // Read the OpConfig register which is in the Registers sub-class
rob.meades@u-blox.com 1:566163f17cde 675 // (64) at offset 0.
rob.meades@u-blox.com 1:566163f17cde 676 if (readExtendedData(64, 0, 2, &(data[0]))) {
rob.meades@u-blox.com 1:566163f17cde 677 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 678 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig is 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
rob.meades@u-blox.com 1:566163f17cde 679 #endif
rob.meades@u-blox.com 1:566163f17cde 680 // SLEEP mode is bit 5 of the low byte of OpConfig. In SLEEP
rob.meades@u-blox.com 1:566163f17cde 681 // mode a reading is taken every 20 seconds.
rob.meades@u-blox.com 1:566163f17cde 682 if (isSlow && ((data[1] & (1 << 5)) == 0)) {
rob.meades@u-blox.com 1:566163f17cde 683 // Set the SLEEP bit 'cos it's not set and needs to be
rob.meades@u-blox.com 1:566163f17cde 684 data[1] |= 1 << 5;
rob.meades@u-blox.com 1:566163f17cde 685 // Write the new value back
rob.meades@u-blox.com 1:566163f17cde 686 success = writeExtendedData(64, 0, 2, &(data[0]));
rob.meades@u-blox.com 1:566163f17cde 687 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 688 if (success) {
rob.meades@u-blox.com 1:566163f17cde 689 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
rob.meades@u-blox.com 1:566163f17cde 690 }
rob.meades@u-blox.com 1:566163f17cde 691 #endif
rob.meades@u-blox.com 1:566163f17cde 692 } else if (!isSlow && ((data[1] & (1 << 5)) != 0)) {
rob.meades@u-blox.com 1:566163f17cde 693 // Clear the SLEEP bit 'cos it's set and shouldn't be
rob.meades@u-blox.com 1:566163f17cde 694 data[1] &= ~(1 << 5);
rob.meades@u-blox.com 1:566163f17cde 695 // Write the new value back
rob.meades@u-blox.com 1:566163f17cde 696 success = writeExtendedData(64, 0, 2, &(data[0]));
rob.meades@u-blox.com 1:566163f17cde 697 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 698 if (success) {
rob.meades@u-blox.com 1:566163f17cde 699 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
rob.meades@u-blox.com 1:566163f17cde 700 }
rob.meades@u-blox.com 1:566163f17cde 701 #endif
rob.meades@u-blox.com 1:566163f17cde 702 } else {
rob.meades@u-blox.com 1:566163f17cde 703 success = true;
rob.meades@u-blox.com 1:566163f17cde 704 }
rob.meades@u-blox.com 1:566163f17cde 705 }
rob.meades@u-blox.com 1:566163f17cde 706 }
rob.meades@u-blox.com 1:566163f17cde 707
rob.meades@u-blox.com 1:566163f17cde 708 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 709 }
rob.meades@u-blox.com 1:566163f17cde 710
rob.meades@u-blox.com 1:566163f17cde 711 return success;
rob.meades@u-blox.com 1:566163f17cde 712 }
rob.meades@u-blox.com 1:566163f17cde 713
RobMeades 2:93310a83401a 714 // Switch off the battery capacity monitor.
rob.meades@u-blox.com 1:566163f17cde 715 bool BatteryGaugeBq27441::disableGauge (void)
rob.meades@u-blox.com 1:566163f17cde 716 {
rob.meades@u-blox.com 1:566163f17cde 717 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 718
rob.meades@u-blox.com 1:566163f17cde 719 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 720 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 721 // Send SET_HIBERNATE
rob.meades@u-blox.com 1:566163f17cde 722 if (setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 723 success = true;
rob.meades@u-blox.com 1:566163f17cde 724 gGaugeOn = false;
rob.meades@u-blox.com 1:566163f17cde 725 }
rob.meades@u-blox.com 1:566163f17cde 726
rob.meades@u-blox.com 1:566163f17cde 727 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 728 }
rob.meades@u-blox.com 1:566163f17cde 729
rob.meades@u-blox.com 1:566163f17cde 730 return success;
rob.meades@u-blox.com 1:566163f17cde 731 }
rob.meades@u-blox.com 1:566163f17cde 732
RobMeades 2:93310a83401a 733 // Check whether a battery has been detected or not.
rob.meades@u-blox.com 1:566163f17cde 734 bool BatteryGaugeBq27441::isBatteryDetected (void)
rob.meades@u-blox.com 1:566163f17cde 735 {
rob.meades@u-blox.com 1:566163f17cde 736 bool isDetected = false;
rob.meades@u-blox.com 1:566163f17cde 737 uint16_t data;
rob.meades@u-blox.com 1:566163f17cde 738
rob.meades@u-blox.com 1:566163f17cde 739 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 740
rob.meades@u-blox.com 1:566163f17cde 741 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 742 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 743 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 744 // Read from the flags register address
rob.meades@u-blox.com 1:566163f17cde 745 if (getTwoBytes (0x06, &data)) {
rob.meades@u-blox.com 1:566163f17cde 746
rob.meades@u-blox.com 1:566163f17cde 747 // If bit 3 is set then a battery has been detected
rob.meades@u-blox.com 1:566163f17cde 748 if (data & (1 << 3)) {
rob.meades@u-blox.com 1:566163f17cde 749 isDetected = true;
rob.meades@u-blox.com 1:566163f17cde 750 }
rob.meades@u-blox.com 1:566163f17cde 751
rob.meades@u-blox.com 1:566163f17cde 752 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 753 if (isDetected) {
rob.meades@u-blox.com 1:566163f17cde 754 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery detected (flags 0x%04x).\n", gAddress >> 1, data);
rob.meades@u-blox.com 1:566163f17cde 755 } else {
rob.meades@u-blox.com 1:566163f17cde 756 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery NOT detected (flags 0x%04x).\n", gAddress >> 1, data);
rob.meades@u-blox.com 1:566163f17cde 757 }
rob.meades@u-blox.com 1:566163f17cde 758 #endif
rob.meades@u-blox.com 1:566163f17cde 759 }
rob.meades@u-blox.com 1:566163f17cde 760
rob.meades@u-blox.com 1:566163f17cde 761 // Set hibernate again if we are not monitoring
rob.meades@u-blox.com 1:566163f17cde 762 if (!gGaugeOn) {
rob.meades@u-blox.com 1:566163f17cde 763 setHibernate();
rob.meades@u-blox.com 1:566163f17cde 764 }
rob.meades@u-blox.com 1:566163f17cde 765
rob.meades@u-blox.com 1:566163f17cde 766 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 767 }
rob.meades@u-blox.com 1:566163f17cde 768 }
rob.meades@u-blox.com 1:566163f17cde 769
rob.meades@u-blox.com 1:566163f17cde 770 return isDetected;
rob.meades@u-blox.com 1:566163f17cde 771 }
rob.meades@u-blox.com 1:566163f17cde 772
RobMeades 2:93310a83401a 773 // Get the temperature of the chip.
rob.meades@u-blox.com 1:566163f17cde 774 bool BatteryGaugeBq27441::getTemperature (int32_t *pTemperatureC)
rob.meades@u-blox.com 1:566163f17cde 775 {
rob.meades@u-blox.com 1:566163f17cde 776 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 777 int32_t temperatureC = 0;
rob.meades@u-blox.com 1:566163f17cde 778 uint16_t data;
rob.meades@u-blox.com 1:566163f17cde 779
rob.meades@u-blox.com 1:566163f17cde 780 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 781 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 782 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 783 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 784 // Read from the temperature register address
rob.meades@u-blox.com 1:566163f17cde 785 if (getTwoBytes (0x02, &data)) {
rob.meades@u-blox.com 1:566163f17cde 786 success = true;
rob.meades@u-blox.com 1:566163f17cde 787
rob.meades@u-blox.com 1:566163f17cde 788 // The answer is in units of 0.1 K, so convert to C
rob.meades@u-blox.com 1:566163f17cde 789 temperatureC = ((int32_t) data / 10) - 273;
rob.meades@u-blox.com 1:566163f17cde 790
rob.meades@u-blox.com 1:566163f17cde 791 if (pTemperatureC) {
rob.meades@u-blox.com 1:566163f17cde 792 *pTemperatureC = temperatureC;
rob.meades@u-blox.com 1:566163f17cde 793 }
rob.meades@u-blox.com 1:566163f17cde 794
rob.meades@u-blox.com 1:566163f17cde 795 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 796 printf("BatteryGaugeBq27441 (I2C 0x%02x): chip temperature %.1f K, so %d C.\n", gAddress >> 1, ((float) data) / 10, temperatureC);
rob.meades@u-blox.com 1:566163f17cde 797 #endif
rob.meades@u-blox.com 1:566163f17cde 798 }
rob.meades@u-blox.com 1:566163f17cde 799
rob.meades@u-blox.com 1:566163f17cde 800 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 801 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 802 success = false;
rob.meades@u-blox.com 1:566163f17cde 803 }
rob.meades@u-blox.com 1:566163f17cde 804
rob.meades@u-blox.com 1:566163f17cde 805 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 806 }
rob.meades@u-blox.com 1:566163f17cde 807 }
rob.meades@u-blox.com 1:566163f17cde 808
rob.meades@u-blox.com 1:566163f17cde 809 return success;
rob.meades@u-blox.com 1:566163f17cde 810 }
rob.meades@u-blox.com 1:566163f17cde 811
RobMeades 2:93310a83401a 812 // Get the voltage of the battery.
rob.meades@u-blox.com 1:566163f17cde 813 bool BatteryGaugeBq27441::getVoltage (int32_t *pVoltageMV)
rob.meades@u-blox.com 1:566163f17cde 814 {
rob.meades@u-blox.com 1:566163f17cde 815 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 816 uint16_t data = 0;
rob.meades@u-blox.com 1:566163f17cde 817
rob.meades@u-blox.com 1:566163f17cde 818 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 819 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 820 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 821 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 822 // Read from the voltage register address
rob.meades@u-blox.com 1:566163f17cde 823 if (getTwoBytes (0x04, &data)) {
rob.meades@u-blox.com 1:566163f17cde 824 success = true;
rob.meades@u-blox.com 1:566163f17cde 825
rob.meades@u-blox.com 1:566163f17cde 826 // The answer is in mV
rob.meades@u-blox.com 1:566163f17cde 827 if (pVoltageMV) {
rob.meades@u-blox.com 1:566163f17cde 828 *pVoltageMV = (int32_t) data;
rob.meades@u-blox.com 1:566163f17cde 829 }
rob.meades@u-blox.com 1:566163f17cde 830
rob.meades@u-blox.com 1:566163f17cde 831 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 832 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery voltage %.3f V.\n", gAddress >> 1, ((float) data) / 1000);
rob.meades@u-blox.com 1:566163f17cde 833 #endif
rob.meades@u-blox.com 1:566163f17cde 834 }
rob.meades@u-blox.com 1:566163f17cde 835
rob.meades@u-blox.com 1:566163f17cde 836 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 837 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 838 success = false;
rob.meades@u-blox.com 1:566163f17cde 839 }
rob.meades@u-blox.com 1:566163f17cde 840
rob.meades@u-blox.com 1:566163f17cde 841 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 842 }
rob.meades@u-blox.com 1:566163f17cde 843 }
rob.meades@u-blox.com 1:566163f17cde 844
rob.meades@u-blox.com 1:566163f17cde 845 return success;
rob.meades@u-blox.com 1:566163f17cde 846 }
rob.meades@u-blox.com 1:566163f17cde 847
RobMeades 2:93310a83401a 848 // Get the current flowing from the battery.
rob.meades@u-blox.com 1:566163f17cde 849 bool BatteryGaugeBq27441::getCurrent (int32_t *pCurrentMA)
rob.meades@u-blox.com 1:566163f17cde 850 {
rob.meades@u-blox.com 1:566163f17cde 851 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 852 int32_t currentMA = 0;
rob.meades@u-blox.com 1:566163f17cde 853 uint16_t data;
rob.meades@u-blox.com 1:566163f17cde 854
rob.meades@u-blox.com 1:566163f17cde 855 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 856 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 857 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 858 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 859 // Read from the average current register address
rob.meades@u-blox.com 1:566163f17cde 860 if (getTwoBytes (0x10, &data)) {
rob.meades@u-blox.com 1:566163f17cde 861 success = true;
rob.meades@u-blox.com 1:566163f17cde 862
rob.meades@u-blox.com 1:566163f17cde 863 if (pCurrentMA) {
rob.meades@u-blox.com 1:566163f17cde 864 *pCurrentMA = currentMA;
rob.meades@u-blox.com 1:566163f17cde 865 }
rob.meades@u-blox.com 1:566163f17cde 866
rob.meades@u-blox.com 1:566163f17cde 867 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 868 printf("BatteryGaugeBq27441 (I2C 0x%02x): current %d mA.\n", gAddress >> 1, currentMA);
rob.meades@u-blox.com 1:566163f17cde 869 #endif
rob.meades@u-blox.com 1:566163f17cde 870 }
rob.meades@u-blox.com 1:566163f17cde 871
rob.meades@u-blox.com 1:566163f17cde 872 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 873 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 874 success = false;
rob.meades@u-blox.com 1:566163f17cde 875 }
rob.meades@u-blox.com 1:566163f17cde 876
rob.meades@u-blox.com 1:566163f17cde 877 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 878 }
rob.meades@u-blox.com 1:566163f17cde 879 }
rob.meades@u-blox.com 1:566163f17cde 880
rob.meades@u-blox.com 1:566163f17cde 881 return success;
rob.meades@u-blox.com 1:566163f17cde 882 }
rob.meades@u-blox.com 1:566163f17cde 883
RobMeades 2:93310a83401a 884 // Get the remaining battery capacity.
rob.meades@u-blox.com 1:566163f17cde 885 bool BatteryGaugeBq27441::getRemainingCapacity (int32_t *pCapacityMAh)
rob.meades@u-blox.com 1:566163f17cde 886 {
rob.meades@u-blox.com 1:566163f17cde 887 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 888 uint16_t data = 0;
rob.meades@u-blox.com 1:566163f17cde 889
rob.meades@u-blox.com 1:566163f17cde 890 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 891 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 892 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 893 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 894 // Read from the RemainingCapacity register address
rob.meades@u-blox.com 1:566163f17cde 895
rob.meades@u-blox.com 1:566163f17cde 896 if (getTwoBytes (0x0c, &data)) {
rob.meades@u-blox.com 1:566163f17cde 897 success = true;
rob.meades@u-blox.com 1:566163f17cde 898
rob.meades@u-blox.com 1:566163f17cde 899 // The answer is in mAh
rob.meades@u-blox.com 1:566163f17cde 900 if (pCapacityMAh) {
rob.meades@u-blox.com 1:566163f17cde 901 *pCapacityMAh = (int32_t) data;
rob.meades@u-blox.com 1:566163f17cde 902 }
rob.meades@u-blox.com 1:566163f17cde 903
rob.meades@u-blox.com 1:566163f17cde 904 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 905 printf("BatteryGaugeBq27441 (I2C 0x%02x): remaining battery capacity %u mAh.\n", gAddress >> 1, data);
rob.meades@u-blox.com 1:566163f17cde 906 #endif
rob.meades@u-blox.com 1:566163f17cde 907 }
rob.meades@u-blox.com 1:566163f17cde 908
rob.meades@u-blox.com 1:566163f17cde 909 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 910 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 911 success = false;
rob.meades@u-blox.com 1:566163f17cde 912 }
rob.meades@u-blox.com 1:566163f17cde 913
rob.meades@u-blox.com 1:566163f17cde 914 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 915 }
rob.meades@u-blox.com 1:566163f17cde 916 }
rob.meades@u-blox.com 1:566163f17cde 917
rob.meades@u-blox.com 1:566163f17cde 918 return success;
rob.meades@u-blox.com 1:566163f17cde 919 }
rob.meades@u-blox.com 1:566163f17cde 920
RobMeades 2:93310a83401a 921 // Get the battery percentage remaining
rob.meades@u-blox.com 1:566163f17cde 922 bool BatteryGaugeBq27441::getRemainingPercentage (int32_t *pBatteryPercent)
rob.meades@u-blox.com 1:566163f17cde 923 {
rob.meades@u-blox.com 1:566163f17cde 924 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 925 uint16_t data = 0;
rob.meades@u-blox.com 1:566163f17cde 926
rob.meades@u-blox.com 1:566163f17cde 927 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 928 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 929 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 930 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 931
rob.meades@u-blox.com 1:566163f17cde 932 // Wake up and take a reading if we have to
rob.meades@u-blox.com 1:566163f17cde 933 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 934 success = false;
rob.meades@u-blox.com 1:566163f17cde 935 }
rob.meades@u-blox.com 1:566163f17cde 936
rob.meades@u-blox.com 1:566163f17cde 937 // Read from the StateOfCharge register address
rob.meades@u-blox.com 1:566163f17cde 938 if (getTwoBytes (0x1c, &data)) {
rob.meades@u-blox.com 1:566163f17cde 939 success = true;
rob.meades@u-blox.com 1:566163f17cde 940
rob.meades@u-blox.com 1:566163f17cde 941 if (pBatteryPercent) {
rob.meades@u-blox.com 1:566163f17cde 942 *pBatteryPercent = (int32_t) data;
rob.meades@u-blox.com 1:566163f17cde 943 }
rob.meades@u-blox.com 1:566163f17cde 944
rob.meades@u-blox.com 1:566163f17cde 945 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 946 printf("BatteryGaugeBq27441 (I2C 0x%02x): remaining battery percentage %u%%.\n", gAddress >> 1, data);
rob.meades@u-blox.com 1:566163f17cde 947 #endif
rob.meades@u-blox.com 1:566163f17cde 948 }
rob.meades@u-blox.com 1:566163f17cde 949
rob.meades@u-blox.com 1:566163f17cde 950 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 951 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 952 success = false;
rob.meades@u-blox.com 1:566163f17cde 953 }
rob.meades@u-blox.com 1:566163f17cde 954
rob.meades@u-blox.com 1:566163f17cde 955 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 956 }
rob.meades@u-blox.com 1:566163f17cde 957 }
rob.meades@u-blox.com 1:566163f17cde 958
rob.meades@u-blox.com 1:566163f17cde 959 return success;
rob.meades@u-blox.com 1:566163f17cde 960 }
rob.meades@u-blox.com 1:566163f17cde 961
RobMeades 2:93310a83401a 962 // Advanced function to read a configuration data block.
rob.meades@u-blox.com 1:566163f17cde 963 bool BatteryGaugeBq27441::advancedGetConfig(uint8_t subClassId, int32_t offset, int32_t length, char * pData)
rob.meades@u-blox.com 1:566163f17cde 964 {
rob.meades@u-blox.com 1:566163f17cde 965 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 966
rob.meades@u-blox.com 1:566163f17cde 967 if (gReady && (gpI2c != NULL) && (pData != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 968 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 969 // Read the extended configuration data
rob.meades@u-blox.com 1:566163f17cde 970 success = readExtendedData(subClassId, offset, length, pData);
rob.meades@u-blox.com 1:566163f17cde 971 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 972 if (success) {
rob.meades@u-blox.com 1:566163f17cde 973 printf("BatteryGaugeBq27441 (I2C 0x%02x): read extended data with subClassId %d from offset %d.\n", gAddress >> 1, subClassId, offset);
rob.meades@u-blox.com 1:566163f17cde 974 }
rob.meades@u-blox.com 1:566163f17cde 975 #endif
rob.meades@u-blox.com 1:566163f17cde 976
rob.meades@u-blox.com 1:566163f17cde 977 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 978 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 979 success = false;
rob.meades@u-blox.com 1:566163f17cde 980 }
rob.meades@u-blox.com 1:566163f17cde 981
rob.meades@u-blox.com 1:566163f17cde 982 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 983 }
rob.meades@u-blox.com 1:566163f17cde 984
rob.meades@u-blox.com 1:566163f17cde 985 return success;
rob.meades@u-blox.com 1:566163f17cde 986 }
rob.meades@u-blox.com 1:566163f17cde 987
RobMeades 2:93310a83401a 988 // Advanced function to write a configuration data block.
rob.meades@u-blox.com 1:566163f17cde 989 bool BatteryGaugeBq27441::advancedSetConfig(uint8_t subClassId, int32_t offset, int32_t length, const char * pData)
rob.meades@u-blox.com 1:566163f17cde 990 {
rob.meades@u-blox.com 1:566163f17cde 991 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 992
rob.meades@u-blox.com 1:566163f17cde 993 if (gReady && (gpI2c != NULL) && (pData != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 994 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 995 // Write the extended configuration data
rob.meades@u-blox.com 1:566163f17cde 996 success = writeExtendedData(subClassId, offset, length, pData);
rob.meades@u-blox.com 1:566163f17cde 997 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 998 if (success) {
rob.meades@u-blox.com 1:566163f17cde 999 printf("BatteryGaugeBq27441 (I2C 0x%02x): written %d byte(s) of extended data with subClassId %d from offset %d.\n", gAddress >> 1, length, subClassId, offset);
rob.meades@u-blox.com 1:566163f17cde 1000 }
rob.meades@u-blox.com 1:566163f17cde 1001 #endif
rob.meades@u-blox.com 1:566163f17cde 1002
rob.meades@u-blox.com 1:566163f17cde 1003 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1004 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1005 success = false;
rob.meades@u-blox.com 1:566163f17cde 1006 }
rob.meades@u-blox.com 1:566163f17cde 1007
rob.meades@u-blox.com 1:566163f17cde 1008 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1009 }
rob.meades@u-blox.com 1:566163f17cde 1010
rob.meades@u-blox.com 1:566163f17cde 1011 return success;
rob.meades@u-blox.com 1:566163f17cde 1012 }
rob.meades@u-blox.com 1:566163f17cde 1013
RobMeades 2:93310a83401a 1014 // Send a control word.
rob.meades@u-blox.com 1:566163f17cde 1015 bool BatteryGaugeBq27441::advancedSendControlWord (uint16_t controlWord, uint16_t *pDataReturned)
rob.meades@u-blox.com 1:566163f17cde 1016 {
rob.meades@u-blox.com 1:566163f17cde 1017 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1018 char data[3];
rob.meades@u-blox.com 1:566163f17cde 1019
rob.meades@u-blox.com 1:566163f17cde 1020 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1021 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1022 // Send the control command
rob.meades@u-blox.com 1:566163f17cde 1023 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 1024 data[1] = (char) controlWord; // First byte of controlWord
rob.meades@u-blox.com 1:566163f17cde 1025 data[2] = (char) (controlWord >> 8); // Second byte of controlWord
rob.meades@u-blox.com 1:566163f17cde 1026 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 1027 // Read the two bytes returned if requested
rob.meades@u-blox.com 1:566163f17cde 1028 if (pDataReturned != NULL) {
rob.meades@u-blox.com 1:566163f17cde 1029 if (getTwoBytes(0, pDataReturned)) {
rob.meades@u-blox.com 1:566163f17cde 1030 success = true;
rob.meades@u-blox.com 1:566163f17cde 1031 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1032 printf("BatteryGaugeBq27441 (I2C 0x%02x): sent control word 0x%04x, read back 0x%04x.\n", gAddress >> 1, controlWord, *pDataReturned);
rob.meades@u-blox.com 1:566163f17cde 1033 #endif
rob.meades@u-blox.com 1:566163f17cde 1034 }
rob.meades@u-blox.com 1:566163f17cde 1035 } else {
rob.meades@u-blox.com 1:566163f17cde 1036 success = true;
rob.meades@u-blox.com 1:566163f17cde 1037 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1038 printf("BatteryGaugeBq27441 (I2C 0x%02x): sent control word 0x%04x.\n", gAddress >> 1, controlWord);
rob.meades@u-blox.com 1:566163f17cde 1039 #endif
rob.meades@u-blox.com 1:566163f17cde 1040 }
rob.meades@u-blox.com 1:566163f17cde 1041 }
rob.meades@u-blox.com 1:566163f17cde 1042 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1043 }
rob.meades@u-blox.com 1:566163f17cde 1044
rob.meades@u-blox.com 1:566163f17cde 1045 return success;
rob.meades@u-blox.com 1:566163f17cde 1046 }
rob.meades@u-blox.com 1:566163f17cde 1047
RobMeades 2:93310a83401a 1048 // Read two bytes starting at a given address on the chip.
rob.meades@u-blox.com 1:566163f17cde 1049 bool BatteryGaugeBq27441::advancedGet (uint8_t address, uint16_t *pDataReturned)
rob.meades@u-blox.com 1:566163f17cde 1050 {
rob.meades@u-blox.com 1:566163f17cde 1051 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1052 uint16_t value;
rob.meades@u-blox.com 1:566163f17cde 1053
rob.meades@u-blox.com 1:566163f17cde 1054 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1055 // Make sure there's a recent reading, as most
rob.meades@u-blox.com 1:566163f17cde 1056 // of these commands involve the chip having done one
rob.meades@u-blox.com 1:566163f17cde 1057 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 1058 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1059 // Read the data
rob.meades@u-blox.com 1:566163f17cde 1060 if (getTwoBytes(address, &value)) {
rob.meades@u-blox.com 1:566163f17cde 1061 success = true;
rob.meades@u-blox.com 1:566163f17cde 1062 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1063 printf("BatteryGaugeBq27441 (I2C 0x%02x): read 0x%04x from addresses 0x%02x and 0x%02x.\n", gAddress >> 1, value, address, address + 1);
rob.meades@u-blox.com 1:566163f17cde 1064 #endif
rob.meades@u-blox.com 1:566163f17cde 1065 if (pDataReturned != NULL) {
rob.meades@u-blox.com 1:566163f17cde 1066 *pDataReturned = value;
rob.meades@u-blox.com 1:566163f17cde 1067 }
rob.meades@u-blox.com 1:566163f17cde 1068 }
rob.meades@u-blox.com 1:566163f17cde 1069 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1070 }
rob.meades@u-blox.com 1:566163f17cde 1071 }
rob.meades@u-blox.com 1:566163f17cde 1072
rob.meades@u-blox.com 1:566163f17cde 1073 return success;
rob.meades@u-blox.com 1:566163f17cde 1074 }
rob.meades@u-blox.com 1:566163f17cde 1075
RobMeades 2:93310a83401a 1076 // Check if the chip is SEALED or UNSEALED.
rob.meades@u-blox.com 1:566163f17cde 1077 bool BatteryGaugeBq27441::advancedIsSealed()
rob.meades@u-blox.com 1:566163f17cde 1078 {
rob.meades@u-blox.com 1:566163f17cde 1079 bool sealed = false;
rob.meades@u-blox.com 1:566163f17cde 1080
rob.meades@u-blox.com 1:566163f17cde 1081 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1082 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1083 // Check for sealedness
rob.meades@u-blox.com 1:566163f17cde 1084 sealed = isSealed();
rob.meades@u-blox.com 1:566163f17cde 1085
rob.meades@u-blox.com 1:566163f17cde 1086 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1087 if (!gGaugeOn) {
rob.meades@u-blox.com 1:566163f17cde 1088 setHibernate();
rob.meades@u-blox.com 1:566163f17cde 1089 }
rob.meades@u-blox.com 1:566163f17cde 1090
rob.meades@u-blox.com 1:566163f17cde 1091 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1092 }
rob.meades@u-blox.com 1:566163f17cde 1093
rob.meades@u-blox.com 1:566163f17cde 1094 return sealed;
rob.meades@u-blox.com 1:566163f17cde 1095 }
rob.meades@u-blox.com 1:566163f17cde 1096
RobMeades 2:93310a83401a 1097 // Put the chip into SEALED mode.
rob.meades@u-blox.com 1:566163f17cde 1098 bool BatteryGaugeBq27441::advancedSeal()
rob.meades@u-blox.com 1:566163f17cde 1099 {
rob.meades@u-blox.com 1:566163f17cde 1100 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1101
rob.meades@u-blox.com 1:566163f17cde 1102 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1103 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1104 // Seal
rob.meades@u-blox.com 1:566163f17cde 1105 success = seal();
rob.meades@u-blox.com 1:566163f17cde 1106
rob.meades@u-blox.com 1:566163f17cde 1107 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1108 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1109 success = false;
rob.meades@u-blox.com 1:566163f17cde 1110 }
rob.meades@u-blox.com 1:566163f17cde 1111
rob.meades@u-blox.com 1:566163f17cde 1112 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1113 }
rob.meades@u-blox.com 1:566163f17cde 1114
rob.meades@u-blox.com 1:566163f17cde 1115 return success;
rob.meades@u-blox.com 1:566163f17cde 1116 }
rob.meades@u-blox.com 1:566163f17cde 1117
RobMeades 2:93310a83401a 1118 // Unseal the device.
rob.meades@u-blox.com 1:566163f17cde 1119 bool BatteryGaugeBq27441::advancedUnseal(uint16_t sealCode)
rob.meades@u-blox.com 1:566163f17cde 1120 {
rob.meades@u-blox.com 1:566163f17cde 1121 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1122 char updateStatus;
rob.meades@u-blox.com 1:566163f17cde 1123
rob.meades@u-blox.com 1:566163f17cde 1124 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1125 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1126 // Unseal and read the Update Status value
rob.meades@u-blox.com 1:566163f17cde 1127 if (unseal(sealCode) && readExtendedData(82, 2, 1, &updateStatus)) {
rob.meades@u-blox.com 1:566163f17cde 1128 // If the update status value has the top bit set then the chip will
rob.meades@u-blox.com 1:566163f17cde 1129 // reseal itself on the next reset, so this bit needs to be cleared to
rob.meades@u-blox.com 1:566163f17cde 1130 // unseal it properly
rob.meades@u-blox.com 1:566163f17cde 1131 if ((updateStatus & (1 << 7)) != 0) {
rob.meades@u-blox.com 1:566163f17cde 1132 updateStatus &= ~(1 << 7);
rob.meades@u-blox.com 1:566163f17cde 1133 success = writeExtendedData(82, 2, 1, &updateStatus);
rob.meades@u-blox.com 1:566163f17cde 1134 } else {
rob.meades@u-blox.com 1:566163f17cde 1135 success = true;
rob.meades@u-blox.com 1:566163f17cde 1136 }
rob.meades@u-blox.com 1:566163f17cde 1137 }
rob.meades@u-blox.com 1:566163f17cde 1138
rob.meades@u-blox.com 1:566163f17cde 1139 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1140 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1141 success = false;
rob.meades@u-blox.com 1:566163f17cde 1142 }
rob.meades@u-blox.com 1:566163f17cde 1143
rob.meades@u-blox.com 1:566163f17cde 1144 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1145 }
rob.meades@u-blox.com 1:566163f17cde 1146
rob.meades@u-blox.com 1:566163f17cde 1147 return success;
rob.meades@u-blox.com 1:566163f17cde 1148 }
rob.meades@u-blox.com 1:566163f17cde 1149
RobMeades 2:93310a83401a 1150 // Do a hard reset of the chip.
rob.meades@u-blox.com 1:566163f17cde 1151 bool BatteryGaugeBq27441::advancedReset(void)
rob.meades@u-blox.com 1:566163f17cde 1152 {
rob.meades@u-blox.com 1:566163f17cde 1153 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1154 bool wasSealed;
rob.meades@u-blox.com 1:566163f17cde 1155 char data[3];
rob.meades@u-blox.com 1:566163f17cde 1156
rob.meades@u-blox.com 1:566163f17cde 1157 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1158 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1159
rob.meades@u-blox.com 1:566163f17cde 1160 // Handle unsealing, as this command only works when unsealed
rob.meades@u-blox.com 1:566163f17cde 1161 wasSealed = isSealed();
rob.meades@u-blox.com 1:566163f17cde 1162 if (!wasSealed || unseal(gSealCode)) {
rob.meades@u-blox.com 1:566163f17cde 1163 // Send a RESET sub-command
rob.meades@u-blox.com 1:566163f17cde 1164 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 1165 data[1] = 0x41; // First byte of RESET sub-command (0x41)
rob.meades@u-blox.com 1:566163f17cde 1166 data[2] = 0x00; // Second byte of RESET sub-command (0x00) (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 1167
rob.meades@u-blox.com 1:566163f17cde 1168 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 1169 success = true;
rob.meades@u-blox.com 1:566163f17cde 1170 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1171 printf("BatteryGaugeBq27441 (I2C 0x%02x): chip hard reset.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 1172 #endif
rob.meades@u-blox.com 1:566163f17cde 1173 }
rob.meades@u-blox.com 1:566163f17cde 1174
rob.meades@u-blox.com 1:566163f17cde 1175 // Handle re-sealing and fail if we need to re-seal but can't
rob.meades@u-blox.com 1:566163f17cde 1176 if (wasSealed && !seal()) {
rob.meades@u-blox.com 1:566163f17cde 1177 success = false;
rob.meades@u-blox.com 1:566163f17cde 1178 }
rob.meades@u-blox.com 1:566163f17cde 1179 }
rob.meades@u-blox.com 1:566163f17cde 1180
rob.meades@u-blox.com 1:566163f17cde 1181 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1182 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1183 success = false;
rob.meades@u-blox.com 1:566163f17cde 1184 }
rob.meades@u-blox.com 1:566163f17cde 1185
rob.meades@u-blox.com 1:566163f17cde 1186 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1187 }
rob.meades@u-blox.com 1:566163f17cde 1188
rob.meades@u-blox.com 1:566163f17cde 1189 return success;
rob.meades@u-blox.com 1:566163f17cde 1190 }
rob.meades@u-blox.com 1:566163f17cde 1191
RobMeades 2:93310a83401a 1192 /* End Of File */