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

Dependents:   rcCar

Fork of battery-gauge-bq27441 by u-blox

Committer:
breadboardbasics
Date:
Wed Dec 13 17:14:51 2017 +0000
Revision:
6:998cc334f8f2
Parent:
5:63b325f2c21a
Fixes current = 0 problem and adds power measurement capability

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