Library to interface to the TI BQ27441, a fuel gauge monitor

Dependents:   rcCar

Fork of battery-gauge-bq27441 by u-blox

Committer:
rob.meades@u-blox.com
Date:
Mon Apr 10 11:18:51 2017 +0100
Revision:
1:566163f17cde
Child:
2:93310a83401a
Add files to repo, removing temp.txt placeholder.

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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 37 /// How many loops to wait for a configuration update to be permitted.
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 47 /// Delay after the last config update before we can unseal the
rob.meades@u-blox.com 1:566163f17cde 48 // chip again (see section 6.4.5.1.1 of the BQ27441 technical
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 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
rob.meades@u-blox.com 1:566163f17cde 1192 // End Of File