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:
Wed Jun 14 17:11:40 2017 +0100
Revision:
5:63b325f2c21a
Parent:
3:ebd56471d57c
Child:
6:998cc334f8f2
Add ability to enable/disable battery detection and make sure that it is switched off when the tests are run on the u-blox C030 platform (since the BIN pin is not connected).

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 5:63b325f2c21a 140 printf("BatteryGaugeBq27441 (I2C 0x%02x): preparing to read %d byte(s) from offset %d of sub-class %d.\n", gAddress >> 1, (int) length, (int) offset, subClassId);
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 5:63b325f2c21a 185 printf("BatteryGaugeBq27441 (I2C 0x%02x): couldn't read all %d bytes of config.\r", gAddress >> 1, (int) 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 5:63b325f2c21a 220 printf("BatteryGaugeBq27441 (I2C 0x%02x): offset (%d) is in different 32 byte block to offset + length (%d) [length is %d].\n", gAddress >> 1, (int) offset, (int) (offset + length), (int) length);
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 5:63b325f2c21a 253 printf("BatteryGaugeBq27441 (I2C 0x%02x): preparing to write %d byte(s) to offset %d of sub-class %d.\n", gAddress >> 1, (int) length, (int) offset, subClassId);
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 5:63b325f2c21a 364 printf("BatteryGaugeBq27441 (I2C 0x%02x): couldn't write all %d bytes during config update.\n", gAddress >> 1, (int) 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 5:63b325f2c21a 409 printf("BatteryGaugeBq27441 (I2C 0x%02x): offset (%d) is in different 32 byte block to offset + length (%d) [length is %d].\n", gAddress >> 1, (int) offset, (int) (offset + length), (int) length);
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
rob.meades@u-blox.com 3:ebd56471d57c 733 // Determine whether battery gauging is enabled.
rob.meades@u-blox.com 3:ebd56471d57c 734 bool BatteryGaugeBq27441::isGaugeEnabled(void)
rob.meades@u-blox.com 3:ebd56471d57c 735 {
rob.meades@u-blox.com 3:ebd56471d57c 736 return gGaugeOn;
rob.meades@u-blox.com 3:ebd56471d57c 737 }
rob.meades@u-blox.com 3:ebd56471d57c 738
rob.meades@u-blox.com 5:63b325f2c21a 739 // Disable the battery detect pin.
rob.meades@u-blox.com 5:63b325f2c21a 740 bool BatteryGaugeBq27441::disableBatteryDetect (void)
rob.meades@u-blox.com 5:63b325f2c21a 741 {
rob.meades@u-blox.com 5:63b325f2c21a 742 bool success = false;
rob.meades@u-blox.com 5:63b325f2c21a 743 char data[3];
rob.meades@u-blox.com 5:63b325f2c21a 744
rob.meades@u-blox.com 5:63b325f2c21a 745 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 5:63b325f2c21a 746 gpI2c->lock();
rob.meades@u-blox.com 5:63b325f2c21a 747 // Read the OpConfig register which is in the Registers sub-class
rob.meades@u-blox.com 5:63b325f2c21a 748 // (64) at offset 0.
rob.meades@u-blox.com 5:63b325f2c21a 749 if (readExtendedData(64, 0, 2, &(data[0]))) {
rob.meades@u-blox.com 5:63b325f2c21a 750 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 5:63b325f2c21a 751 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig is 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
rob.meades@u-blox.com 5:63b325f2c21a 752 #endif
rob.meades@u-blox.com 5:63b325f2c21a 753 // Battery Insertion Enabled is bit 5 of the high byte of OpConfig.
rob.meades@u-blox.com 5:63b325f2c21a 754 // 1 means that the battery input pin is enabled
rob.meades@u-blox.com 5:63b325f2c21a 755 if (((data[0] & (1 << 5)) != 0)) {
rob.meades@u-blox.com 5:63b325f2c21a 756 // Clear the BIE bit 'cos it's set and is shouldn't be
rob.meades@u-blox.com 5:63b325f2c21a 757 data[0] &= ~(1 << 5);
rob.meades@u-blox.com 5:63b325f2c21a 758 // Write the new value back
rob.meades@u-blox.com 5:63b325f2c21a 759 if (writeExtendedData(64, 0, 2, &(data[0]))) {
rob.meades@u-blox.com 5:63b325f2c21a 760 // Send the Battery Inserted message as we can't do gauging otherwise
rob.meades@u-blox.com 5:63b325f2c21a 761 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 5:63b325f2c21a 762 data[1] = 0x0C; // First byte of BAT_INSERT sub-command (0x0C)
rob.meades@u-blox.com 5:63b325f2c21a 763 data[2] = 0x00; // Second byte of BAT_INSERT sub-command (0x00)
rob.meades@u-blox.com 5:63b325f2c21a 764 success = gpI2c->write(gAddress, &(data[0]), 3) == 0;
rob.meades@u-blox.com 5:63b325f2c21a 765 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 5:63b325f2c21a 766 if (success) {
rob.meades@u-blox.com 5:63b325f2c21a 767 printf("BatteryGaugeBq27441 (I2C 0x%02x): BIE disabled, BAT_INSERT sent, OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
rob.meades@u-blox.com 5:63b325f2c21a 768 }
rob.meades@u-blox.com 5:63b325f2c21a 769 #endif
rob.meades@u-blox.com 5:63b325f2c21a 770 }
rob.meades@u-blox.com 5:63b325f2c21a 771 } else {
rob.meades@u-blox.com 5:63b325f2c21a 772 success = true;
rob.meades@u-blox.com 5:63b325f2c21a 773 }
rob.meades@u-blox.com 5:63b325f2c21a 774 }
rob.meades@u-blox.com 5:63b325f2c21a 775
rob.meades@u-blox.com 5:63b325f2c21a 776 // Set hibernate again if we are not monitoring
rob.meades@u-blox.com 5:63b325f2c21a 777 if (!gGaugeOn) {
rob.meades@u-blox.com 5:63b325f2c21a 778 setHibernate();
rob.meades@u-blox.com 5:63b325f2c21a 779 }
rob.meades@u-blox.com 5:63b325f2c21a 780
rob.meades@u-blox.com 5:63b325f2c21a 781 gpI2c->unlock();
rob.meades@u-blox.com 5:63b325f2c21a 782 }
rob.meades@u-blox.com 5:63b325f2c21a 783
rob.meades@u-blox.com 5:63b325f2c21a 784 return success;
rob.meades@u-blox.com 5:63b325f2c21a 785 }
rob.meades@u-blox.com 5:63b325f2c21a 786
rob.meades@u-blox.com 5:63b325f2c21a 787 // Enable the battery detect pin.
rob.meades@u-blox.com 5:63b325f2c21a 788 bool BatteryGaugeBq27441::enableBatteryDetect (void)
rob.meades@u-blox.com 5:63b325f2c21a 789 {
rob.meades@u-blox.com 5:63b325f2c21a 790 bool success = false;
rob.meades@u-blox.com 5:63b325f2c21a 791 char data[3];
rob.meades@u-blox.com 5:63b325f2c21a 792
rob.meades@u-blox.com 5:63b325f2c21a 793 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 5:63b325f2c21a 794 gpI2c->lock();
rob.meades@u-blox.com 5:63b325f2c21a 795 // Read the OpConfig register which is in the Registers sub-class
rob.meades@u-blox.com 5:63b325f2c21a 796 // (64) at offset 0.
rob.meades@u-blox.com 5:63b325f2c21a 797 if (readExtendedData(64, 0, 2, &(data[0]))) {
rob.meades@u-blox.com 5:63b325f2c21a 798 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 5:63b325f2c21a 799 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig is 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
rob.meades@u-blox.com 5:63b325f2c21a 800 #endif
rob.meades@u-blox.com 5:63b325f2c21a 801 // Battery Insertion Enabled is bit 5 of the high byte of OpConfig.
rob.meades@u-blox.com 5:63b325f2c21a 802 // 1 means that the battery input pin is enabled
rob.meades@u-blox.com 5:63b325f2c21a 803 if (((data[0] & (1 << 5)) == 0)) {
rob.meades@u-blox.com 5:63b325f2c21a 804 // Set the BIE bit 'cos it's not set and needs to be
rob.meades@u-blox.com 5:63b325f2c21a 805 data[0] |= 1 << 5;
rob.meades@u-blox.com 5:63b325f2c21a 806 // Write the new value back
rob.meades@u-blox.com 5:63b325f2c21a 807 success = writeExtendedData(64, 0, 2, &(data[0]));
rob.meades@u-blox.com 5:63b325f2c21a 808 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 5:63b325f2c21a 809 if (success) {
rob.meades@u-blox.com 5:63b325f2c21a 810 printf("BatteryGaugeBq27441 (I2C 0x%02x): BIE enabled, OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
rob.meades@u-blox.com 5:63b325f2c21a 811 }
rob.meades@u-blox.com 5:63b325f2c21a 812 #endif
rob.meades@u-blox.com 5:63b325f2c21a 813 } else {
rob.meades@u-blox.com 5:63b325f2c21a 814 success = true;
rob.meades@u-blox.com 5:63b325f2c21a 815 }
rob.meades@u-blox.com 5:63b325f2c21a 816 }
rob.meades@u-blox.com 5:63b325f2c21a 817
rob.meades@u-blox.com 5:63b325f2c21a 818 // Set hibernate again if we are not monitoring
rob.meades@u-blox.com 5:63b325f2c21a 819 if (!gGaugeOn) {
rob.meades@u-blox.com 5:63b325f2c21a 820 setHibernate();
rob.meades@u-blox.com 5:63b325f2c21a 821 }
rob.meades@u-blox.com 5:63b325f2c21a 822
rob.meades@u-blox.com 5:63b325f2c21a 823 gpI2c->unlock();
rob.meades@u-blox.com 5:63b325f2c21a 824 }
rob.meades@u-blox.com 5:63b325f2c21a 825
rob.meades@u-blox.com 5:63b325f2c21a 826 return success;
rob.meades@u-blox.com 5:63b325f2c21a 827 }
rob.meades@u-blox.com 5:63b325f2c21a 828
RobMeades 2:93310a83401a 829 // Check whether a battery has been detected or not.
rob.meades@u-blox.com 1:566163f17cde 830 bool BatteryGaugeBq27441::isBatteryDetected (void)
rob.meades@u-blox.com 1:566163f17cde 831 {
rob.meades@u-blox.com 1:566163f17cde 832 bool isDetected = false;
rob.meades@u-blox.com 1:566163f17cde 833 uint16_t data;
rob.meades@u-blox.com 1:566163f17cde 834
rob.meades@u-blox.com 1:566163f17cde 835 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 836
rob.meades@u-blox.com 1:566163f17cde 837 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 838 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 839 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 840 // Read from the flags register address
rob.meades@u-blox.com 1:566163f17cde 841 if (getTwoBytes (0x06, &data)) {
rob.meades@u-blox.com 1:566163f17cde 842
rob.meades@u-blox.com 1:566163f17cde 843 // If bit 3 is set then a battery has been detected
rob.meades@u-blox.com 1:566163f17cde 844 if (data & (1 << 3)) {
rob.meades@u-blox.com 1:566163f17cde 845 isDetected = true;
rob.meades@u-blox.com 1:566163f17cde 846 }
rob.meades@u-blox.com 1:566163f17cde 847
rob.meades@u-blox.com 1:566163f17cde 848 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 849 if (isDetected) {
rob.meades@u-blox.com 1:566163f17cde 850 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery detected (flags 0x%04x).\n", gAddress >> 1, data);
rob.meades@u-blox.com 1:566163f17cde 851 } else {
rob.meades@u-blox.com 1:566163f17cde 852 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery NOT detected (flags 0x%04x).\n", gAddress >> 1, data);
rob.meades@u-blox.com 1:566163f17cde 853 }
rob.meades@u-blox.com 1:566163f17cde 854 #endif
rob.meades@u-blox.com 1:566163f17cde 855 }
rob.meades@u-blox.com 1:566163f17cde 856
rob.meades@u-blox.com 1:566163f17cde 857 // Set hibernate again if we are not monitoring
rob.meades@u-blox.com 1:566163f17cde 858 if (!gGaugeOn) {
rob.meades@u-blox.com 1:566163f17cde 859 setHibernate();
rob.meades@u-blox.com 1:566163f17cde 860 }
rob.meades@u-blox.com 1:566163f17cde 861
rob.meades@u-blox.com 1:566163f17cde 862 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 863 }
rob.meades@u-blox.com 1:566163f17cde 864 }
rob.meades@u-blox.com 1:566163f17cde 865
rob.meades@u-blox.com 1:566163f17cde 866 return isDetected;
rob.meades@u-blox.com 1:566163f17cde 867 }
rob.meades@u-blox.com 1:566163f17cde 868
RobMeades 2:93310a83401a 869 // Get the temperature of the chip.
rob.meades@u-blox.com 1:566163f17cde 870 bool BatteryGaugeBq27441::getTemperature (int32_t *pTemperatureC)
rob.meades@u-blox.com 1:566163f17cde 871 {
rob.meades@u-blox.com 1:566163f17cde 872 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 873 int32_t temperatureC = 0;
rob.meades@u-blox.com 1:566163f17cde 874 uint16_t data;
rob.meades@u-blox.com 1:566163f17cde 875
rob.meades@u-blox.com 1:566163f17cde 876 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 877 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 878 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 879 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 880 // Read from the temperature register address
rob.meades@u-blox.com 1:566163f17cde 881 if (getTwoBytes (0x02, &data)) {
rob.meades@u-blox.com 1:566163f17cde 882 success = true;
rob.meades@u-blox.com 1:566163f17cde 883
rob.meades@u-blox.com 1:566163f17cde 884 // The answer is in units of 0.1 K, so convert to C
rob.meades@u-blox.com 1:566163f17cde 885 temperatureC = ((int32_t) data / 10) - 273;
rob.meades@u-blox.com 1:566163f17cde 886
rob.meades@u-blox.com 1:566163f17cde 887 if (pTemperatureC) {
rob.meades@u-blox.com 1:566163f17cde 888 *pTemperatureC = temperatureC;
rob.meades@u-blox.com 1:566163f17cde 889 }
rob.meades@u-blox.com 1:566163f17cde 890
rob.meades@u-blox.com 1:566163f17cde 891 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 5:63b325f2c21a 892 printf("BatteryGaugeBq27441 (I2C 0x%02x): chip temperature %.1f K, so %d C.\n", gAddress >> 1, ((float) data) / 10, (int) temperatureC);
rob.meades@u-blox.com 1:566163f17cde 893 #endif
rob.meades@u-blox.com 1:566163f17cde 894 }
rob.meades@u-blox.com 1:566163f17cde 895
rob.meades@u-blox.com 1:566163f17cde 896 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 897 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 898 success = false;
rob.meades@u-blox.com 1:566163f17cde 899 }
rob.meades@u-blox.com 1:566163f17cde 900
rob.meades@u-blox.com 1:566163f17cde 901 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 902 }
rob.meades@u-blox.com 1:566163f17cde 903 }
rob.meades@u-blox.com 1:566163f17cde 904
rob.meades@u-blox.com 1:566163f17cde 905 return success;
rob.meades@u-blox.com 1:566163f17cde 906 }
rob.meades@u-blox.com 1:566163f17cde 907
RobMeades 2:93310a83401a 908 // Get the voltage of the battery.
rob.meades@u-blox.com 1:566163f17cde 909 bool BatteryGaugeBq27441::getVoltage (int32_t *pVoltageMV)
rob.meades@u-blox.com 1:566163f17cde 910 {
rob.meades@u-blox.com 1:566163f17cde 911 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 912 uint16_t data = 0;
rob.meades@u-blox.com 1:566163f17cde 913
rob.meades@u-blox.com 1:566163f17cde 914 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 915 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 916 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 917 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 918 // Read from the voltage register address
rob.meades@u-blox.com 1:566163f17cde 919 if (getTwoBytes (0x04, &data)) {
rob.meades@u-blox.com 1:566163f17cde 920 success = true;
rob.meades@u-blox.com 1:566163f17cde 921
rob.meades@u-blox.com 1:566163f17cde 922 // The answer is in mV
rob.meades@u-blox.com 1:566163f17cde 923 if (pVoltageMV) {
rob.meades@u-blox.com 1:566163f17cde 924 *pVoltageMV = (int32_t) data;
rob.meades@u-blox.com 1:566163f17cde 925 }
rob.meades@u-blox.com 1:566163f17cde 926
rob.meades@u-blox.com 1:566163f17cde 927 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 928 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery voltage %.3f V.\n", gAddress >> 1, ((float) data) / 1000);
rob.meades@u-blox.com 1:566163f17cde 929 #endif
rob.meades@u-blox.com 1:566163f17cde 930 }
rob.meades@u-blox.com 1:566163f17cde 931
rob.meades@u-blox.com 1:566163f17cde 932 // Return to sleep if we are allowed 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 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 938 }
rob.meades@u-blox.com 1:566163f17cde 939 }
rob.meades@u-blox.com 1:566163f17cde 940
rob.meades@u-blox.com 1:566163f17cde 941 return success;
rob.meades@u-blox.com 1:566163f17cde 942 }
rob.meades@u-blox.com 1:566163f17cde 943
RobMeades 2:93310a83401a 944 // Get the current flowing from the battery.
rob.meades@u-blox.com 1:566163f17cde 945 bool BatteryGaugeBq27441::getCurrent (int32_t *pCurrentMA)
rob.meades@u-blox.com 1:566163f17cde 946 {
rob.meades@u-blox.com 1:566163f17cde 947 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 948 int32_t currentMA = 0;
rob.meades@u-blox.com 1:566163f17cde 949 uint16_t data;
rob.meades@u-blox.com 1:566163f17cde 950
rob.meades@u-blox.com 1:566163f17cde 951 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 952 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 953 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 954 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 955 // Read from the average current register address
rob.meades@u-blox.com 1:566163f17cde 956 if (getTwoBytes (0x10, &data)) {
rob.meades@u-blox.com 1:566163f17cde 957 success = true;
rob.meades@u-blox.com 1:566163f17cde 958
rob.meades@u-blox.com 1:566163f17cde 959 if (pCurrentMA) {
rob.meades@u-blox.com 1:566163f17cde 960 *pCurrentMA = currentMA;
rob.meades@u-blox.com 1:566163f17cde 961 }
rob.meades@u-blox.com 1:566163f17cde 962
rob.meades@u-blox.com 1:566163f17cde 963 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 5:63b325f2c21a 964 printf("BatteryGaugeBq27441 (I2C 0x%02x): current %d mA.\n", gAddress >> 1, (int) currentMA);
rob.meades@u-blox.com 1:566163f17cde 965 #endif
rob.meades@u-blox.com 1:566163f17cde 966 }
rob.meades@u-blox.com 1:566163f17cde 967
rob.meades@u-blox.com 1:566163f17cde 968 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 969 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 970 success = false;
rob.meades@u-blox.com 1:566163f17cde 971 }
rob.meades@u-blox.com 1:566163f17cde 972
rob.meades@u-blox.com 1:566163f17cde 973 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 974 }
rob.meades@u-blox.com 1:566163f17cde 975 }
rob.meades@u-blox.com 1:566163f17cde 976
rob.meades@u-blox.com 1:566163f17cde 977 return success;
rob.meades@u-blox.com 1:566163f17cde 978 }
rob.meades@u-blox.com 1:566163f17cde 979
RobMeades 2:93310a83401a 980 // Get the remaining battery capacity.
rob.meades@u-blox.com 1:566163f17cde 981 bool BatteryGaugeBq27441::getRemainingCapacity (int32_t *pCapacityMAh)
rob.meades@u-blox.com 1:566163f17cde 982 {
rob.meades@u-blox.com 1:566163f17cde 983 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 984 uint16_t data = 0;
rob.meades@u-blox.com 1:566163f17cde 985
rob.meades@u-blox.com 1:566163f17cde 986 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 987 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 988 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 989 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 990 // Read from the RemainingCapacity register address
rob.meades@u-blox.com 1:566163f17cde 991
rob.meades@u-blox.com 1:566163f17cde 992 if (getTwoBytes (0x0c, &data)) {
rob.meades@u-blox.com 1:566163f17cde 993 success = true;
rob.meades@u-blox.com 1:566163f17cde 994
rob.meades@u-blox.com 1:566163f17cde 995 // The answer is in mAh
rob.meades@u-blox.com 1:566163f17cde 996 if (pCapacityMAh) {
rob.meades@u-blox.com 1:566163f17cde 997 *pCapacityMAh = (int32_t) data;
rob.meades@u-blox.com 1:566163f17cde 998 }
rob.meades@u-blox.com 1:566163f17cde 999
rob.meades@u-blox.com 1:566163f17cde 1000 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1001 printf("BatteryGaugeBq27441 (I2C 0x%02x): remaining battery capacity %u mAh.\n", gAddress >> 1, data);
rob.meades@u-blox.com 1:566163f17cde 1002 #endif
rob.meades@u-blox.com 1:566163f17cde 1003 }
rob.meades@u-blox.com 1:566163f17cde 1004
rob.meades@u-blox.com 1:566163f17cde 1005 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1006 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1007 success = false;
rob.meades@u-blox.com 1:566163f17cde 1008 }
rob.meades@u-blox.com 1:566163f17cde 1009
rob.meades@u-blox.com 1:566163f17cde 1010 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1011 }
rob.meades@u-blox.com 1:566163f17cde 1012 }
rob.meades@u-blox.com 1:566163f17cde 1013
rob.meades@u-blox.com 1:566163f17cde 1014 return success;
rob.meades@u-blox.com 1:566163f17cde 1015 }
rob.meades@u-blox.com 1:566163f17cde 1016
RobMeades 2:93310a83401a 1017 // Get the battery percentage remaining
rob.meades@u-blox.com 1:566163f17cde 1018 bool BatteryGaugeBq27441::getRemainingPercentage (int32_t *pBatteryPercent)
rob.meades@u-blox.com 1:566163f17cde 1019 {
rob.meades@u-blox.com 1:566163f17cde 1020 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1021 uint16_t data = 0;
rob.meades@u-blox.com 1:566163f17cde 1022
rob.meades@u-blox.com 1:566163f17cde 1023 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1024 // Make sure there's a recent reading
rob.meades@u-blox.com 1:566163f17cde 1025 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 1026 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1027
rob.meades@u-blox.com 1:566163f17cde 1028 // Wake up and take a reading if we have to
rob.meades@u-blox.com 1:566163f17cde 1029 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1030 success = false;
rob.meades@u-blox.com 1:566163f17cde 1031 }
rob.meades@u-blox.com 1:566163f17cde 1032
rob.meades@u-blox.com 1:566163f17cde 1033 // Read from the StateOfCharge register address
rob.meades@u-blox.com 1:566163f17cde 1034 if (getTwoBytes (0x1c, &data)) {
rob.meades@u-blox.com 1:566163f17cde 1035 success = true;
rob.meades@u-blox.com 1:566163f17cde 1036
rob.meades@u-blox.com 1:566163f17cde 1037 if (pBatteryPercent) {
rob.meades@u-blox.com 1:566163f17cde 1038 *pBatteryPercent = (int32_t) data;
rob.meades@u-blox.com 1:566163f17cde 1039 }
rob.meades@u-blox.com 1:566163f17cde 1040
rob.meades@u-blox.com 1:566163f17cde 1041 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1042 printf("BatteryGaugeBq27441 (I2C 0x%02x): remaining battery percentage %u%%.\n", gAddress >> 1, data);
rob.meades@u-blox.com 1:566163f17cde 1043 #endif
rob.meades@u-blox.com 1:566163f17cde 1044 }
rob.meades@u-blox.com 1:566163f17cde 1045
rob.meades@u-blox.com 1:566163f17cde 1046 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1047 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1048 success = false;
rob.meades@u-blox.com 1:566163f17cde 1049 }
rob.meades@u-blox.com 1:566163f17cde 1050
rob.meades@u-blox.com 1:566163f17cde 1051 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1052 }
rob.meades@u-blox.com 1:566163f17cde 1053 }
rob.meades@u-blox.com 1:566163f17cde 1054
rob.meades@u-blox.com 1:566163f17cde 1055 return success;
rob.meades@u-blox.com 1:566163f17cde 1056 }
rob.meades@u-blox.com 1:566163f17cde 1057
RobMeades 2:93310a83401a 1058 // Advanced function to read a configuration data block.
rob.meades@u-blox.com 1:566163f17cde 1059 bool BatteryGaugeBq27441::advancedGetConfig(uint8_t subClassId, int32_t offset, int32_t length, char * pData)
rob.meades@u-blox.com 1:566163f17cde 1060 {
rob.meades@u-blox.com 1:566163f17cde 1061 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1062
rob.meades@u-blox.com 1:566163f17cde 1063 if (gReady && (gpI2c != NULL) && (pData != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1064 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1065 // Read the extended configuration data
rob.meades@u-blox.com 1:566163f17cde 1066 success = readExtendedData(subClassId, offset, length, pData);
rob.meades@u-blox.com 1:566163f17cde 1067 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1068 if (success) {
rob.meades@u-blox.com 5:63b325f2c21a 1069 printf("BatteryGaugeBq27441 (I2C 0x%02x): read extended data with subClassId %d from offset %d.\n", gAddress >> 1, subClassId, (int) offset);
rob.meades@u-blox.com 1:566163f17cde 1070 }
rob.meades@u-blox.com 1:566163f17cde 1071 #endif
rob.meades@u-blox.com 1:566163f17cde 1072
rob.meades@u-blox.com 1:566163f17cde 1073 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1074 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1075 success = false;
rob.meades@u-blox.com 1:566163f17cde 1076 }
rob.meades@u-blox.com 1:566163f17cde 1077
rob.meades@u-blox.com 1:566163f17cde 1078 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1079 }
rob.meades@u-blox.com 1:566163f17cde 1080
rob.meades@u-blox.com 1:566163f17cde 1081 return success;
rob.meades@u-blox.com 1:566163f17cde 1082 }
rob.meades@u-blox.com 1:566163f17cde 1083
RobMeades 2:93310a83401a 1084 // Advanced function to write a configuration data block.
rob.meades@u-blox.com 1:566163f17cde 1085 bool BatteryGaugeBq27441::advancedSetConfig(uint8_t subClassId, int32_t offset, int32_t length, const char * pData)
rob.meades@u-blox.com 1:566163f17cde 1086 {
rob.meades@u-blox.com 1:566163f17cde 1087 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1088
rob.meades@u-blox.com 1:566163f17cde 1089 if (gReady && (gpI2c != NULL) && (pData != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1090 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1091 // Write the extended configuration data
rob.meades@u-blox.com 1:566163f17cde 1092 success = writeExtendedData(subClassId, offset, length, pData);
rob.meades@u-blox.com 1:566163f17cde 1093 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1094 if (success) {
rob.meades@u-blox.com 5:63b325f2c21a 1095 printf("BatteryGaugeBq27441 (I2C 0x%02x): written %d byte(s) of extended data with subClassId %d from offset %d.\n", gAddress >> 1, (int) length, subClassId, (int) offset);
rob.meades@u-blox.com 1:566163f17cde 1096 }
rob.meades@u-blox.com 1:566163f17cde 1097 #endif
rob.meades@u-blox.com 1:566163f17cde 1098
rob.meades@u-blox.com 1:566163f17cde 1099 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1100 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1101 success = false;
rob.meades@u-blox.com 1:566163f17cde 1102 }
rob.meades@u-blox.com 1:566163f17cde 1103
rob.meades@u-blox.com 1:566163f17cde 1104 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1105 }
rob.meades@u-blox.com 1:566163f17cde 1106
rob.meades@u-blox.com 1:566163f17cde 1107 return success;
rob.meades@u-blox.com 1:566163f17cde 1108 }
rob.meades@u-blox.com 1:566163f17cde 1109
RobMeades 2:93310a83401a 1110 // Send a control word.
rob.meades@u-blox.com 1:566163f17cde 1111 bool BatteryGaugeBq27441::advancedSendControlWord (uint16_t controlWord, uint16_t *pDataReturned)
rob.meades@u-blox.com 1:566163f17cde 1112 {
rob.meades@u-blox.com 1:566163f17cde 1113 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1114 char data[3];
rob.meades@u-blox.com 1:566163f17cde 1115
rob.meades@u-blox.com 1:566163f17cde 1116 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1117 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1118 // Send the control command
rob.meades@u-blox.com 1:566163f17cde 1119 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 1120 data[1] = (char) controlWord; // First byte of controlWord
rob.meades@u-blox.com 1:566163f17cde 1121 data[2] = (char) (controlWord >> 8); // Second byte of controlWord
rob.meades@u-blox.com 1:566163f17cde 1122 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 1123 // Read the two bytes returned if requested
rob.meades@u-blox.com 1:566163f17cde 1124 if (pDataReturned != NULL) {
rob.meades@u-blox.com 1:566163f17cde 1125 if (getTwoBytes(0, pDataReturned)) {
rob.meades@u-blox.com 1:566163f17cde 1126 success = true;
rob.meades@u-blox.com 1:566163f17cde 1127 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1128 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 1129 #endif
rob.meades@u-blox.com 1:566163f17cde 1130 }
rob.meades@u-blox.com 1:566163f17cde 1131 } else {
rob.meades@u-blox.com 1:566163f17cde 1132 success = true;
rob.meades@u-blox.com 1:566163f17cde 1133 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1134 printf("BatteryGaugeBq27441 (I2C 0x%02x): sent control word 0x%04x.\n", gAddress >> 1, controlWord);
rob.meades@u-blox.com 1:566163f17cde 1135 #endif
rob.meades@u-blox.com 1:566163f17cde 1136 }
rob.meades@u-blox.com 1:566163f17cde 1137 }
rob.meades@u-blox.com 1:566163f17cde 1138 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1139 }
rob.meades@u-blox.com 1:566163f17cde 1140
rob.meades@u-blox.com 1:566163f17cde 1141 return success;
rob.meades@u-blox.com 1:566163f17cde 1142 }
rob.meades@u-blox.com 1:566163f17cde 1143
RobMeades 2:93310a83401a 1144 // Read two bytes starting at a given address on the chip.
rob.meades@u-blox.com 1:566163f17cde 1145 bool BatteryGaugeBq27441::advancedGet (uint8_t address, uint16_t *pDataReturned)
rob.meades@u-blox.com 1:566163f17cde 1146 {
rob.meades@u-blox.com 1:566163f17cde 1147 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1148 uint16_t value;
rob.meades@u-blox.com 1:566163f17cde 1149
rob.meades@u-blox.com 1:566163f17cde 1150 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1151 // Make sure there's a recent reading, as most
rob.meades@u-blox.com 1:566163f17cde 1152 // of these commands involve the chip having done one
rob.meades@u-blox.com 1:566163f17cde 1153 if (gGaugeOn || makeAdcReading()) {
rob.meades@u-blox.com 1:566163f17cde 1154 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1155 // Read the data
rob.meades@u-blox.com 1:566163f17cde 1156 if (getTwoBytes(address, &value)) {
rob.meades@u-blox.com 1:566163f17cde 1157 success = true;
rob.meades@u-blox.com 1:566163f17cde 1158 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1159 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 1160 #endif
rob.meades@u-blox.com 1:566163f17cde 1161 if (pDataReturned != NULL) {
rob.meades@u-blox.com 1:566163f17cde 1162 *pDataReturned = value;
rob.meades@u-blox.com 1:566163f17cde 1163 }
rob.meades@u-blox.com 1:566163f17cde 1164 }
rob.meades@u-blox.com 1:566163f17cde 1165 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1166 }
rob.meades@u-blox.com 1:566163f17cde 1167 }
rob.meades@u-blox.com 1:566163f17cde 1168
rob.meades@u-blox.com 1:566163f17cde 1169 return success;
rob.meades@u-blox.com 1:566163f17cde 1170 }
rob.meades@u-blox.com 1:566163f17cde 1171
RobMeades 2:93310a83401a 1172 // Check if the chip is SEALED or UNSEALED.
rob.meades@u-blox.com 1:566163f17cde 1173 bool BatteryGaugeBq27441::advancedIsSealed()
rob.meades@u-blox.com 1:566163f17cde 1174 {
rob.meades@u-blox.com 1:566163f17cde 1175 bool sealed = false;
rob.meades@u-blox.com 1:566163f17cde 1176
rob.meades@u-blox.com 1:566163f17cde 1177 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1178 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1179 // Check for sealedness
rob.meades@u-blox.com 1:566163f17cde 1180 sealed = isSealed();
rob.meades@u-blox.com 1:566163f17cde 1181
rob.meades@u-blox.com 1:566163f17cde 1182 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1183 if (!gGaugeOn) {
rob.meades@u-blox.com 1:566163f17cde 1184 setHibernate();
rob.meades@u-blox.com 1:566163f17cde 1185 }
rob.meades@u-blox.com 1:566163f17cde 1186
rob.meades@u-blox.com 1:566163f17cde 1187 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1188 }
rob.meades@u-blox.com 1:566163f17cde 1189
rob.meades@u-blox.com 1:566163f17cde 1190 return sealed;
rob.meades@u-blox.com 1:566163f17cde 1191 }
rob.meades@u-blox.com 1:566163f17cde 1192
RobMeades 2:93310a83401a 1193 // Put the chip into SEALED mode.
rob.meades@u-blox.com 1:566163f17cde 1194 bool BatteryGaugeBq27441::advancedSeal()
rob.meades@u-blox.com 1:566163f17cde 1195 {
rob.meades@u-blox.com 1:566163f17cde 1196 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1197
rob.meades@u-blox.com 1:566163f17cde 1198 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1199 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1200 // Seal
rob.meades@u-blox.com 1:566163f17cde 1201 success = seal();
rob.meades@u-blox.com 1:566163f17cde 1202
rob.meades@u-blox.com 1:566163f17cde 1203 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1204 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1205 success = false;
rob.meades@u-blox.com 1:566163f17cde 1206 }
rob.meades@u-blox.com 1:566163f17cde 1207
rob.meades@u-blox.com 1:566163f17cde 1208 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1209 }
rob.meades@u-blox.com 1:566163f17cde 1210
rob.meades@u-blox.com 1:566163f17cde 1211 return success;
rob.meades@u-blox.com 1:566163f17cde 1212 }
rob.meades@u-blox.com 1:566163f17cde 1213
RobMeades 2:93310a83401a 1214 // Unseal the device.
rob.meades@u-blox.com 1:566163f17cde 1215 bool BatteryGaugeBq27441::advancedUnseal(uint16_t sealCode)
rob.meades@u-blox.com 1:566163f17cde 1216 {
rob.meades@u-blox.com 1:566163f17cde 1217 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1218 char updateStatus;
rob.meades@u-blox.com 1:566163f17cde 1219
rob.meades@u-blox.com 1:566163f17cde 1220 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1221 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1222 // Unseal and read the Update Status value
rob.meades@u-blox.com 1:566163f17cde 1223 if (unseal(sealCode) && readExtendedData(82, 2, 1, &updateStatus)) {
rob.meades@u-blox.com 1:566163f17cde 1224 // If the update status value has the top bit set then the chip will
rob.meades@u-blox.com 1:566163f17cde 1225 // reseal itself on the next reset, so this bit needs to be cleared to
rob.meades@u-blox.com 1:566163f17cde 1226 // unseal it properly
rob.meades@u-blox.com 1:566163f17cde 1227 if ((updateStatus & (1 << 7)) != 0) {
rob.meades@u-blox.com 1:566163f17cde 1228 updateStatus &= ~(1 << 7);
rob.meades@u-blox.com 1:566163f17cde 1229 success = writeExtendedData(82, 2, 1, &updateStatus);
rob.meades@u-blox.com 1:566163f17cde 1230 } else {
rob.meades@u-blox.com 1:566163f17cde 1231 success = true;
rob.meades@u-blox.com 1:566163f17cde 1232 }
rob.meades@u-blox.com 1:566163f17cde 1233 }
rob.meades@u-blox.com 1:566163f17cde 1234
rob.meades@u-blox.com 1:566163f17cde 1235 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1236 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1237 success = false;
rob.meades@u-blox.com 1:566163f17cde 1238 }
rob.meades@u-blox.com 1:566163f17cde 1239
rob.meades@u-blox.com 1:566163f17cde 1240 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1241 }
rob.meades@u-blox.com 1:566163f17cde 1242
rob.meades@u-blox.com 1:566163f17cde 1243 return success;
rob.meades@u-blox.com 1:566163f17cde 1244 }
rob.meades@u-blox.com 1:566163f17cde 1245
RobMeades 2:93310a83401a 1246 // Do a hard reset of the chip.
rob.meades@u-blox.com 1:566163f17cde 1247 bool BatteryGaugeBq27441::advancedReset(void)
rob.meades@u-blox.com 1:566163f17cde 1248 {
rob.meades@u-blox.com 1:566163f17cde 1249 bool success = false;
rob.meades@u-blox.com 1:566163f17cde 1250 bool wasSealed;
rob.meades@u-blox.com 1:566163f17cde 1251 char data[3];
rob.meades@u-blox.com 1:566163f17cde 1252
rob.meades@u-blox.com 1:566163f17cde 1253 if (gReady && (gpI2c != NULL)) {
rob.meades@u-blox.com 1:566163f17cde 1254 gpI2c->lock();
rob.meades@u-blox.com 1:566163f17cde 1255
rob.meades@u-blox.com 1:566163f17cde 1256 // Handle unsealing, as this command only works when unsealed
rob.meades@u-blox.com 1:566163f17cde 1257 wasSealed = isSealed();
rob.meades@u-blox.com 1:566163f17cde 1258 if (!wasSealed || unseal(gSealCode)) {
rob.meades@u-blox.com 1:566163f17cde 1259 // Send a RESET sub-command
rob.meades@u-blox.com 1:566163f17cde 1260 data[0] = 0x00; // Set address to first register for control
rob.meades@u-blox.com 1:566163f17cde 1261 data[1] = 0x41; // First byte of RESET sub-command (0x41)
rob.meades@u-blox.com 1:566163f17cde 1262 data[2] = 0x00; // Second byte of RESET sub-command (0x00) (register address will auto-increment)
rob.meades@u-blox.com 1:566163f17cde 1263
rob.meades@u-blox.com 1:566163f17cde 1264 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
rob.meades@u-blox.com 1:566163f17cde 1265 success = true;
rob.meades@u-blox.com 1:566163f17cde 1266 #ifdef DEBUG_BQ27441
rob.meades@u-blox.com 1:566163f17cde 1267 printf("BatteryGaugeBq27441 (I2C 0x%02x): chip hard reset.\n", gAddress >> 1);
rob.meades@u-blox.com 1:566163f17cde 1268 #endif
rob.meades@u-blox.com 1:566163f17cde 1269 }
rob.meades@u-blox.com 1:566163f17cde 1270
rob.meades@u-blox.com 1:566163f17cde 1271 // Handle re-sealing and fail if we need to re-seal but can't
rob.meades@u-blox.com 1:566163f17cde 1272 if (wasSealed && !seal()) {
rob.meades@u-blox.com 1:566163f17cde 1273 success = false;
rob.meades@u-blox.com 1:566163f17cde 1274 }
rob.meades@u-blox.com 1:566163f17cde 1275 }
rob.meades@u-blox.com 1:566163f17cde 1276
rob.meades@u-blox.com 1:566163f17cde 1277 // Return to sleep if we are allowed to
rob.meades@u-blox.com 1:566163f17cde 1278 if (!gGaugeOn && !setHibernate()) {
rob.meades@u-blox.com 1:566163f17cde 1279 success = false;
rob.meades@u-blox.com 1:566163f17cde 1280 }
rob.meades@u-blox.com 1:566163f17cde 1281
rob.meades@u-blox.com 1:566163f17cde 1282 gpI2c->unlock();
rob.meades@u-blox.com 1:566163f17cde 1283 }
rob.meades@u-blox.com 1:566163f17cde 1284
rob.meades@u-blox.com 1:566163f17cde 1285 return success;
rob.meades@u-blox.com 1:566163f17cde 1286 }
rob.meades@u-blox.com 1:566163f17cde 1287
RobMeades 2:93310a83401a 1288 /* End Of File */