This class provides APIs to all of the registers of the TI BQ35100 battery gauge, as used on the u-blox C030 primary battery shield.

Dependents:   example-battery-gauge-bq35100

Committer:
RobMeades
Date:
Fri Nov 10 17:07:06 2017 +0000
Revision:
2:4c699a813451
Parent:
1:ee7cc8d75283
Functionality at equivalent level to the BQ27411 battery driver.  Good enough for now.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
RobMeades 0:cec745c014b7 1 /* mbed Microcontroller Library
RobMeades 0:cec745c014b7 2 * Copyright (c) 2017 u-blox
RobMeades 0:cec745c014b7 3 *
RobMeades 0:cec745c014b7 4 * Licensed under the Apache License, Version 2.0 (the "License");
RobMeades 0:cec745c014b7 5 * you may not use this file except in compliance with the License.
RobMeades 0:cec745c014b7 6 * You may obtain a copy of the License at
RobMeades 0:cec745c014b7 7 *
RobMeades 0:cec745c014b7 8 * http://www.apache.org/licenses/LICENSE-2.0
RobMeades 0:cec745c014b7 9 *
RobMeades 0:cec745c014b7 10 * Unless required by applicable law or agreed to in writing, software
RobMeades 0:cec745c014b7 11 * distributed under the License is distributed on an "AS IS" BASIS,
RobMeades 0:cec745c014b7 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
RobMeades 0:cec745c014b7 13 * See the License for the specific language governing permissions and
RobMeades 0:cec745c014b7 14 * limitations under the License.
RobMeades 0:cec745c014b7 15 */
RobMeades 0:cec745c014b7 16
RobMeades 0:cec745c014b7 17 /**
RobMeades 0:cec745c014b7 18 * @file bq35100.cpp
RobMeades 0:cec745c014b7 19 * This file defines the API to the TI BQ35100 battery gauge chip.
RobMeades 0:cec745c014b7 20 */
RobMeades 0:cec745c014b7 21
RobMeades 0:cec745c014b7 22 /** Define these to print debug information. */
RobMeades 2:4c699a813451 23 //#define DEBUG_BQ35100
RobMeades 2:4c699a813451 24 //#define DEBUG_BQ35100_BLOCK_DATA
RobMeades 0:cec745c014b7 25
RobMeades 0:cec745c014b7 26 #include <mbed.h>
RobMeades 0:cec745c014b7 27 #include <battery_gauge_bq35100.h>
RobMeades 0:cec745c014b7 28
RobMeades 0:cec745c014b7 29 #ifdef DEBUG_BQ35100
RobMeades 0:cec745c014b7 30 # include <stdio.h>
RobMeades 0:cec745c014b7 31 #endif
RobMeades 0:cec745c014b7 32
RobMeades 0:cec745c014b7 33 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 34 // COMPILE-TIME MACROS
RobMeades 0:cec745c014b7 35 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 36
RobMeades 1:ee7cc8d75283 37 /** How long to wait for a security mode change to succeed. */
RobMeades 1:ee7cc8d75283 38 #define SET_SECURITY_MODE_RETRY_SECONDS 5
RobMeades 1:ee7cc8d75283 39
RobMeades 2:4c699a813451 40 /** How long to wait for accumulated capacity data to be written
RobMeades 2:4c699a813451 41 * to data flash when gauging is disabled */
RobMeades 2:4c699a813451 42 #define GAUGE_COMPLETE_WAIT_MS 10000
RobMeades 2:4c699a813451 43
RobMeades 0:cec745c014b7 44 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 45 // GENERIC PRIVATE FUNCTIONS
RobMeades 0:cec745c014b7 46 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 47
RobMeades 0:cec745c014b7 48 // Read two bytes from an address.
RobMeades 0:cec745c014b7 49 // Note: gpI2c should be locked before this is called.
RobMeades 2:4c699a813451 50 bool BatteryGaugeBq35100::getTwoBytes(uint8_t registerAddress, uint16_t *pBytes)
RobMeades 0:cec745c014b7 51 {
RobMeades 0:cec745c014b7 52 bool success = false;
RobMeades 0:cec745c014b7 53 char data[3];
RobMeades 0:cec745c014b7 54
RobMeades 0:cec745c014b7 55 if (gpI2c != NULL) {
RobMeades 0:cec745c014b7 56 data[0] = registerAddress;
RobMeades 0:cec745c014b7 57 data[1] = 0;
RobMeades 0:cec745c014b7 58 data[2] = 0;
RobMeades 0:cec745c014b7 59
RobMeades 1:ee7cc8d75283 60 // Send a command to read from registerAddress
RobMeades 1:ee7cc8d75283 61 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
RobMeades 0:cec745c014b7 62 (gpI2c->read(gAddress, &(data[1]), 2) == 0)) {
RobMeades 0:cec745c014b7 63 success = true;
RobMeades 0:cec745c014b7 64 if (pBytes) {
RobMeades 0:cec745c014b7 65 *pBytes = (((uint16_t) data[2]) << 8) + data[1];
RobMeades 0:cec745c014b7 66 }
RobMeades 0:cec745c014b7 67 }
RobMeades 0:cec745c014b7 68 }
RobMeades 0:cec745c014b7 69
RobMeades 0:cec745c014b7 70 return success;
RobMeades 0:cec745c014b7 71 }
RobMeades 0:cec745c014b7 72
RobMeades 1:ee7cc8d75283 73 // Compute the checksum over an address plus the block of data.
RobMeades 2:4c699a813451 74 uint8_t BatteryGaugeBq35100::computeChecksum(const char * pData, int32_t length)
RobMeades 1:ee7cc8d75283 75 {
RobMeades 1:ee7cc8d75283 76 uint8_t checkSum = 0;
RobMeades 1:ee7cc8d75283 77 uint8_t x = 0;
RobMeades 1:ee7cc8d75283 78
RobMeades 1:ee7cc8d75283 79 if (pData != NULL) {
RobMeades 1:ee7cc8d75283 80 #ifdef DEBUG_BQ35100_BLOCK_DATA
RobMeades 1:ee7cc8d75283 81 printf ("BatteryGaugeBq35100 (I2C 0x%02x): computing check sum on data block.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 82 printf (" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
RobMeades 1:ee7cc8d75283 83 #endif
RobMeades 1:ee7cc8d75283 84 for (x = 1; x <= length; x++) {
RobMeades 1:ee7cc8d75283 85 checkSum += *pData;
RobMeades 1:ee7cc8d75283 86
RobMeades 1:ee7cc8d75283 87 #ifdef DEBUG_BQ35100_BLOCK_DATA
RobMeades 1:ee7cc8d75283 88 if (x % 16 == 8) {
RobMeades 1:ee7cc8d75283 89 printf ("%02x ", *pData);
RobMeades 1:ee7cc8d75283 90 } else if (x % 16 == 0) {
RobMeades 1:ee7cc8d75283 91 printf ("%02x\n", *pData);
RobMeades 1:ee7cc8d75283 92 } else {
RobMeades 1:ee7cc8d75283 93 printf ("%02x-", *pData);
RobMeades 1:ee7cc8d75283 94 }
RobMeades 1:ee7cc8d75283 95 #endif
RobMeades 1:ee7cc8d75283 96 pData++;
RobMeades 1:ee7cc8d75283 97 }
RobMeades 1:ee7cc8d75283 98
RobMeades 1:ee7cc8d75283 99 checkSum = 0xff - checkSum;
RobMeades 1:ee7cc8d75283 100 }
RobMeades 1:ee7cc8d75283 101
RobMeades 1:ee7cc8d75283 102 #ifdef DEBUG_BQ35100_BLOCK_DATA
RobMeades 1:ee7cc8d75283 103 if (x % 16 != 1) {
RobMeades 1:ee7cc8d75283 104 printf("\n");
RobMeades 1:ee7cc8d75283 105 }
RobMeades 1:ee7cc8d75283 106
RobMeades 1:ee7cc8d75283 107 printf ("BatteryGaugeBq35100 (I2C 0x%02x): check sum is 0x%02x.\n", gAddress >> 1, checkSum);
RobMeades 1:ee7cc8d75283 108 #endif
RobMeades 1:ee7cc8d75283 109
RobMeades 1:ee7cc8d75283 110 return checkSum;
RobMeades 1:ee7cc8d75283 111 }
RobMeades 1:ee7cc8d75283 112
RobMeades 1:ee7cc8d75283 113 // Read data of a given length from a given address.
RobMeades 1:ee7cc8d75283 114 // Note: gpI2c should be locked before this is called.
RobMeades 2:4c699a813451 115 bool BatteryGaugeBq35100::readExtendedData(int32_t address, char * pData, int32_t length)
RobMeades 1:ee7cc8d75283 116 {
RobMeades 1:ee7cc8d75283 117 int32_t lengthRead;
RobMeades 1:ee7cc8d75283 118 bool success = false;
RobMeades 1:ee7cc8d75283 119 SecurityMode securityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 120 char block[32 + 2 + 2]; // 32 bytes of data, 2 bytes of address,
RobMeades 1:ee7cc8d75283 121 // 1 byte of MACDataSum and 1 byte of MACDataLen
RobMeades 1:ee7cc8d75283 122 char data[3];
RobMeades 1:ee7cc8d75283 123
RobMeades 1:ee7cc8d75283 124 // Handle security mode
RobMeades 1:ee7cc8d75283 125 if (setSecurityMode(SECURITY_MODE_UNSEALED)) {
RobMeades 1:ee7cc8d75283 126 if ((gpI2c != NULL) && (length <= 32) && (address >= 0x4000) && (address < 0x4400) && (pData != NULL)) {
RobMeades 1:ee7cc8d75283 127 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 128 printf("BatteryGaugeBq35100 (I2C 0x%02x): preparing to read %d byte(s) from address 0x%04x.\n", gAddress >> 1, (int) length, (unsigned int) address);
RobMeades 1:ee7cc8d75283 129 #endif
RobMeades 1:ee7cc8d75283 130 // Enable Block Data Control (0x61)
RobMeades 1:ee7cc8d75283 131 data[0] = 0x61;
RobMeades 1:ee7cc8d75283 132 data[1] = 0;
RobMeades 1:ee7cc8d75283 133
RobMeades 1:ee7cc8d75283 134 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
RobMeades 1:ee7cc8d75283 135 // Write address to ManufacturerAccessControl (0x3e)
RobMeades 1:ee7cc8d75283 136 data[0] = 0x3e;
RobMeades 1:ee7cc8d75283 137 data[1] = (char) address;
RobMeades 1:ee7cc8d75283 138 data[2] = (char) (address >> 8);
RobMeades 1:ee7cc8d75283 139
RobMeades 1:ee7cc8d75283 140 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
RobMeades 1:ee7cc8d75283 141 // Read the address from ManufacturerAccessControl (0x3e then 0x3f),
RobMeades 1:ee7cc8d75283 142 // data from MACData (0x40 to 0x5f), checksum from MACDataSum (0x60)
RobMeades 1:ee7cc8d75283 143 // and length from MACDataLen (0x61)
RobMeades 1:ee7cc8d75283 144 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
RobMeades 1:ee7cc8d75283 145 (gpI2c->read(gAddress, &(block[0]), sizeof (block)) == 0)) {
RobMeades 1:ee7cc8d75283 146 // Check that the address matches
RobMeades 1:ee7cc8d75283 147 if ((block[0] == (char) address) && (block[1] == (char) (address >> 8))) {
RobMeades 1:ee7cc8d75283 148 // Check that the checksum matches (-2 on MACDataLen as it includes MACDataSum and itself)
RobMeades 1:ee7cc8d75283 149 if (block[34] == computeChecksum (&(block[0]), block[35] - 2)) {
RobMeades 1:ee7cc8d75283 150 // All is good, copy the data to the user
RobMeades 1:ee7cc8d75283 151 lengthRead = block[35] - 4; // -4 rather than -2 to remove the two bytes of address as well
RobMeades 1:ee7cc8d75283 152 if (lengthRead > length) {
RobMeades 1:ee7cc8d75283 153 lengthRead = length;
RobMeades 1:ee7cc8d75283 154 }
RobMeades 1:ee7cc8d75283 155 memcpy(pData, &(block[2]), lengthRead);
RobMeades 1:ee7cc8d75283 156 success = true;
RobMeades 1:ee7cc8d75283 157 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 158 printf("BatteryGaugeBq35100 (I2C 0x%02x): %d byte(s) read successfully.\n", gAddress >> 1, (int) lengthRead);
RobMeades 1:ee7cc8d75283 159 #endif
RobMeades 1:ee7cc8d75283 160 } else {
RobMeades 1:ee7cc8d75283 161 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 162 printf("BatteryGaugeBq35100 (I2C 0x%02x): checksum didn't match (0x%02x expected).\n", gAddress >> 1, block[34]);
RobMeades 1:ee7cc8d75283 163 #endif
RobMeades 1:ee7cc8d75283 164 }
RobMeades 1:ee7cc8d75283 165 } else {
RobMeades 1:ee7cc8d75283 166 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 167 printf("BatteryGaugeBq35100 (I2C 0x%02x): address didn't match (expected 0x%04x, received 0x%02x%02x).\n", gAddress >> 1, (unsigned int) address, block[1], block[0]);
RobMeades 1:ee7cc8d75283 168 #endif
RobMeades 1:ee7cc8d75283 169 }
RobMeades 1:ee7cc8d75283 170 } else {
RobMeades 1:ee7cc8d75283 171 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 172 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to read %d bytes from ManufacturerAccessControl.\n", gAddress >> 1, sizeof (block));
RobMeades 1:ee7cc8d75283 173 #endif
RobMeades 1:ee7cc8d75283 174 }
RobMeades 1:ee7cc8d75283 175 } else {
RobMeades 1:ee7cc8d75283 176 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 177 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write %d bytes to ManufacturerAccessControl.\r", gAddress >> 1, 3);
RobMeades 1:ee7cc8d75283 178 #endif
RobMeades 1:ee7cc8d75283 179 }
RobMeades 1:ee7cc8d75283 180 } else {
RobMeades 1:ee7cc8d75283 181 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 182 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set Block Data Control.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 183 #endif
RobMeades 1:ee7cc8d75283 184 }
RobMeades 1:ee7cc8d75283 185 } else {
RobMeades 1:ee7cc8d75283 186 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 187 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set the security mode of the chip.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 188 #endif
RobMeades 1:ee7cc8d75283 189 }
RobMeades 1:ee7cc8d75283 190 }
RobMeades 1:ee7cc8d75283 191
RobMeades 1:ee7cc8d75283 192 // Put the security mode back to what it was
RobMeades 1:ee7cc8d75283 193 if (!setSecurityMode(securityMode)) {
RobMeades 1:ee7cc8d75283 194 success = false;
RobMeades 1:ee7cc8d75283 195 }
RobMeades 1:ee7cc8d75283 196
RobMeades 1:ee7cc8d75283 197 return success;
RobMeades 1:ee7cc8d75283 198 }
RobMeades 1:ee7cc8d75283 199
RobMeades 1:ee7cc8d75283 200 // Write data of a given length to a given address.
RobMeades 1:ee7cc8d75283 201 // Note: gpI2c should be locked before this is called.
RobMeades 2:4c699a813451 202 bool BatteryGaugeBq35100::writeExtendedData(int32_t address, const char * pData, int32_t length)
RobMeades 1:ee7cc8d75283 203 {
RobMeades 1:ee7cc8d75283 204 bool success = false;
RobMeades 1:ee7cc8d75283 205 SecurityMode securityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 206 char data[3 + 32];
RobMeades 2:4c699a813451 207 uint16_t controlStatus;
RobMeades 1:ee7cc8d75283 208
RobMeades 1:ee7cc8d75283 209 if ((gpI2c != NULL) && (length <= 32) && (address >= 0x4000) && (address < 0x4400) && (pData != NULL)) {
RobMeades 1:ee7cc8d75283 210 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 211 printf("BatteryGaugeBq35100 (I2C 0x%02x): preparing to write %d byte(s) to address 0x%04x.\n", gAddress >> 1, (int) length, (unsigned int) address);
RobMeades 1:ee7cc8d75283 212 #endif
RobMeades 1:ee7cc8d75283 213 // Handle security mode
RobMeades 1:ee7cc8d75283 214 if (setSecurityMode(SECURITY_MODE_UNSEALED)) {
RobMeades 1:ee7cc8d75283 215 // Enable Block Data Control (0x61)
RobMeades 1:ee7cc8d75283 216 data[0] = 0x61;
RobMeades 1:ee7cc8d75283 217 data[1] = 0;
RobMeades 1:ee7cc8d75283 218
RobMeades 1:ee7cc8d75283 219 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
RobMeades 1:ee7cc8d75283 220 // Start write at ManufacturerAccessControl (0x3e)
RobMeades 1:ee7cc8d75283 221 data[0] = 0x3e;
RobMeades 1:ee7cc8d75283 222 // Next two bytes are the address we will write to
RobMeades 1:ee7cc8d75283 223 data[1] = (char) address;
RobMeades 1:ee7cc8d75283 224 data[2] = (char) (address >> 8);
RobMeades 1:ee7cc8d75283 225 // Remaining bytes are the data bytes we wish to write
RobMeades 1:ee7cc8d75283 226 memcpy (&(data[3]), pData, length);
RobMeades 1:ee7cc8d75283 227
RobMeades 1:ee7cc8d75283 228 if (gpI2c->write(gAddress, &(data[0]), 3 + length) == 0) {
RobMeades 1:ee7cc8d75283 229 // Compute the checksum and write it to MACDataSum (0x60)
RobMeades 1:ee7cc8d75283 230 data[1] = computeChecksum (&(data[1]), length + 2);
RobMeades 1:ee7cc8d75283 231 data[0] = 0x60;
RobMeades 1:ee7cc8d75283 232
RobMeades 1:ee7cc8d75283 233 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
RobMeades 1:ee7cc8d75283 234 // Write 4 + length to MACDataLen (0x61)
RobMeades 1:ee7cc8d75283 235 data[1] = length + 4;
RobMeades 1:ee7cc8d75283 236 data[0] = 0x61;
RobMeades 1:ee7cc8d75283 237
RobMeades 1:ee7cc8d75283 238 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
RobMeades 2:4c699a813451 239 // Read the control status register to see if a bad
RobMeades 2:4c699a813451 240 // flash write has been detected (bit 15)
RobMeades 2:4c699a813451 241 data[0] = 0;
RobMeades 2:4c699a813451 242 if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) &&
RobMeades 2:4c699a813451 243 getTwoBytes(0, &controlStatus) &&
RobMeades 2:4c699a813451 244 (((controlStatus >> 15) & 0x01) != 0x01)) {
RobMeades 2:4c699a813451 245 success = true;
RobMeades 2:4c699a813451 246 }
RobMeades 1:ee7cc8d75283 247 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 248 printf("BatteryGaugeBq35100 (I2C 0x%02x): write successful.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 249 #endif
RobMeades 1:ee7cc8d75283 250 } else {
RobMeades 1:ee7cc8d75283 251 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 252 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to read write to MACDataLen.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 253 #endif
RobMeades 1:ee7cc8d75283 254 }
RobMeades 1:ee7cc8d75283 255 } else {
RobMeades 1:ee7cc8d75283 256 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 257 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write to MACDataSum.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 258 #endif
RobMeades 1:ee7cc8d75283 259 }
RobMeades 1:ee7cc8d75283 260 } else {
RobMeades 1:ee7cc8d75283 261 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 262 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write %d bytes to ManufacturerAccessControl.\r", gAddress >> 1, (int) length + 2);
RobMeades 1:ee7cc8d75283 263 #endif
RobMeades 1:ee7cc8d75283 264 }
RobMeades 1:ee7cc8d75283 265 } else {
RobMeades 1:ee7cc8d75283 266 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 267 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set Block Data Control.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 268 #endif
RobMeades 1:ee7cc8d75283 269 }
RobMeades 1:ee7cc8d75283 270 } else {
RobMeades 1:ee7cc8d75283 271 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 272 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set the security mode of the chip.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 273 #endif
RobMeades 1:ee7cc8d75283 274 }
RobMeades 1:ee7cc8d75283 275 }
RobMeades 1:ee7cc8d75283 276
RobMeades 1:ee7cc8d75283 277 // Put the security mode back to what it was
RobMeades 1:ee7cc8d75283 278 if (!setSecurityMode(securityMode)) {
RobMeades 1:ee7cc8d75283 279 success = false;
RobMeades 1:ee7cc8d75283 280 }
RobMeades 1:ee7cc8d75283 281
RobMeades 1:ee7cc8d75283 282 return success;
RobMeades 1:ee7cc8d75283 283 }
RobMeades 1:ee7cc8d75283 284
RobMeades 1:ee7cc8d75283 285 // Get the security mode of the chip.
RobMeades 1:ee7cc8d75283 286 // Note: gpI2c should be locked before this is called.
RobMeades 1:ee7cc8d75283 287 BatteryGaugeBq35100::SecurityMode BatteryGaugeBq35100::getSecurityMode(void)
RobMeades 1:ee7cc8d75283 288 {
RobMeades 1:ee7cc8d75283 289 SecurityMode securityMode = SECURITY_MODE_UNKNOWN;
RobMeades 1:ee7cc8d75283 290 char data[1];
RobMeades 1:ee7cc8d75283 291 uint16_t controlStatus;
RobMeades 1:ee7cc8d75283 292
RobMeades 2:4c699a813451 293 // Read the control status register
RobMeades 2:4c699a813451 294 data[0] = 0;
RobMeades 2:4c699a813451 295 if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) &&
RobMeades 2:4c699a813451 296 getTwoBytes(0, &controlStatus)) {
RobMeades 2:4c699a813451 297 // Bits 13 and 14 of the high byte represent the security status,
RobMeades 2:4c699a813451 298 // 01 = full access
RobMeades 2:4c699a813451 299 // 10 = unsealed access
RobMeades 2:4c699a813451 300 // 11 = sealed access
RobMeades 2:4c699a813451 301 securityMode = (SecurityMode) ((controlStatus >> 13) & 0x03);
RobMeades 1:ee7cc8d75283 302 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 303 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode is 0x%02x (control status 0x%04x).\r\n", gAddress >> 1, securityMode, controlStatus);
RobMeades 1:ee7cc8d75283 304 #endif
RobMeades 1:ee7cc8d75283 305 }
RobMeades 2:4c699a813451 306
RobMeades 1:ee7cc8d75283 307 return securityMode;
RobMeades 1:ee7cc8d75283 308 }
RobMeades 1:ee7cc8d75283 309
RobMeades 1:ee7cc8d75283 310 // Set the security mode of the chip.
RobMeades 1:ee7cc8d75283 311 // Note: gpI2c should be locked before this is called.
RobMeades 1:ee7cc8d75283 312 bool BatteryGaugeBq35100::setSecurityMode(SecurityMode securityMode)
RobMeades 1:ee7cc8d75283 313 {
RobMeades 1:ee7cc8d75283 314 bool success = false;
RobMeades 1:ee7cc8d75283 315 char data[3];
RobMeades 1:ee7cc8d75283 316 SecurityMode currentSecurityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 317
RobMeades 1:ee7cc8d75283 318 if (securityMode != SECURITY_MODE_UNKNOWN) {
RobMeades 1:ee7cc8d75283 319 if (securityMode != currentSecurityMode) {
RobMeades 1:ee7cc8d75283 320 // For reasons that aren't clear, the BQ35100 sometimes refuses
RobMeades 1:ee7cc8d75283 321 // to change security mode if a previous security mode change
RobMeades 1:ee7cc8d75283 322 // happend only a few seconds ago, hence the retry here
RobMeades 1:ee7cc8d75283 323 for (int32_t x = 0; (x < SET_SECURITY_MODE_RETRY_SECONDS) && !success; x++) {
RobMeades 2:4c699a813451 324 data[0] = 0x3e; // Set address to ManufacturerAccessControl
RobMeades 1:ee7cc8d75283 325 switch (securityMode) {
RobMeades 1:ee7cc8d75283 326 case SECURITY_MODE_SEALED:
RobMeades 1:ee7cc8d75283 327 // Just seal the chip
RobMeades 1:ee7cc8d75283 328 data[1] = 0x20; // First byte of SEALED sub-command (0x20)
RobMeades 1:ee7cc8d75283 329 data[2] = 0x00; // Second byte of SEALED sub-command (0x00) (register address will auto-increment)
RobMeades 1:ee7cc8d75283 330 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 331 break;
RobMeades 1:ee7cc8d75283 332 case SECURITY_MODE_FULL_ACCESS:
RobMeades 1:ee7cc8d75283 333 // Send the full access code with endianness conversion
RobMeades 1:ee7cc8d75283 334 // in TWO writes
RobMeades 1:ee7cc8d75283 335 data[2] = (char) (gFullAccessCodes >> 24);
RobMeades 1:ee7cc8d75283 336 data[1] = (char) (gFullAccessCodes >> 16);
RobMeades 1:ee7cc8d75283 337 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 338 data[2] = (char) (gFullAccessCodes >> 8);
RobMeades 1:ee7cc8d75283 339 data[1] = (char) gFullAccessCodes;
RobMeades 1:ee7cc8d75283 340 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 341 break;
RobMeades 1:ee7cc8d75283 342 case SECURITY_MODE_UNSEALED:
RobMeades 1:ee7cc8d75283 343 data[2] = (char) (gSealCodes >> 24);
RobMeades 1:ee7cc8d75283 344 data[1] = (char) (gSealCodes >> 16);
RobMeades 1:ee7cc8d75283 345 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 346 data[2] = (char) (gSealCodes >> 8);
RobMeades 1:ee7cc8d75283 347 data[1] = (char) gSealCodes;
RobMeades 1:ee7cc8d75283 348 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 349 break;
RobMeades 1:ee7cc8d75283 350 case SECURITY_MODE_UNKNOWN:
RobMeades 1:ee7cc8d75283 351 default:
RobMeades 1:ee7cc8d75283 352 MBED_ASSERT(false);
RobMeades 1:ee7cc8d75283 353 break;
RobMeades 1:ee7cc8d75283 354 }
RobMeades 1:ee7cc8d75283 355
RobMeades 1:ee7cc8d75283 356 currentSecurityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 357 if (currentSecurityMode == securityMode) {
RobMeades 1:ee7cc8d75283 358 success = true;
RobMeades 1:ee7cc8d75283 359 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 360 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode is now 0x%02x.\n", gAddress >> 1, currentSecurityMode);
RobMeades 1:ee7cc8d75283 361 #endif
RobMeades 1:ee7cc8d75283 362 } else {
RobMeades 1:ee7cc8d75283 363 wait_ms(1000);
RobMeades 1:ee7cc8d75283 364 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 365 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode set failed (wanted 0x%02x, got 0x%02x), will retry.\n", gAddress >> 1, securityMode, currentSecurityMode);
RobMeades 1:ee7cc8d75283 366 #endif
RobMeades 1:ee7cc8d75283 367 }
RobMeades 1:ee7cc8d75283 368 }
RobMeades 1:ee7cc8d75283 369 } else {
RobMeades 1:ee7cc8d75283 370 success = true;
RobMeades 1:ee7cc8d75283 371 }
RobMeades 1:ee7cc8d75283 372 }
RobMeades 1:ee7cc8d75283 373
RobMeades 1:ee7cc8d75283 374 return success;
RobMeades 1:ee7cc8d75283 375 }
RobMeades 1:ee7cc8d75283 376
RobMeades 1:ee7cc8d75283 377 // Make sure that the device is awake and has taken a reading.
RobMeades 1:ee7cc8d75283 378 bool BatteryGaugeBq35100::makeAdcReading(void)
RobMeades 1:ee7cc8d75283 379 {
RobMeades 1:ee7cc8d75283 380 bool success = false;
RobMeades 1:ee7cc8d75283 381
RobMeades 2:4c699a813451 382 if (isGaugeEnabled()) {
RobMeades 2:4c699a813451 383 success = true;
RobMeades 2:4c699a813451 384 } else {
RobMeades 2:4c699a813451 385 if (enableGauge() && disableGauge()) {
RobMeades 2:4c699a813451 386 success = true;
RobMeades 1:ee7cc8d75283 387 }
RobMeades 1:ee7cc8d75283 388 }
RobMeades 1:ee7cc8d75283 389
RobMeades 1:ee7cc8d75283 390 return success;
RobMeades 1:ee7cc8d75283 391 }
RobMeades 1:ee7cc8d75283 392
RobMeades 0:cec745c014b7 393 //----------------------------------------------------------------
RobMeades 0:cec745c014b7 394 // PUBLIC FUNCTIONS
RobMeades 0:cec745c014b7 395 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 396
RobMeades 0:cec745c014b7 397 // Constructor.
RobMeades 0:cec745c014b7 398 BatteryGaugeBq35100::BatteryGaugeBq35100(void)
RobMeades 0:cec745c014b7 399 {
RobMeades 0:cec745c014b7 400 gpI2c = NULL;
RobMeades 1:ee7cc8d75283 401 pGaugeEnable = NULL;
RobMeades 0:cec745c014b7 402 gReady = false;
RobMeades 1:ee7cc8d75283 403 gSealCodes = 0;
RobMeades 1:ee7cc8d75283 404 gFullAccessCodes = 0;
RobMeades 0:cec745c014b7 405 }
RobMeades 0:cec745c014b7 406
RobMeades 0:cec745c014b7 407 // Destructor.
RobMeades 0:cec745c014b7 408 BatteryGaugeBq35100::~BatteryGaugeBq35100(void)
RobMeades 0:cec745c014b7 409 {
RobMeades 0:cec745c014b7 410 }
RobMeades 0:cec745c014b7 411
RobMeades 0:cec745c014b7 412 // Initialise ourselves.
RobMeades 1:ee7cc8d75283 413 bool BatteryGaugeBq35100::init(I2C * pI2c, PinName gaugeEnable, uint8_t address, uint32_t sealCodes)
RobMeades 0:cec745c014b7 414 {
RobMeades 0:cec745c014b7 415 uint16_t answer;
RobMeades 0:cec745c014b7 416 char data[4];
RobMeades 0:cec745c014b7 417
RobMeades 0:cec745c014b7 418 gpI2c = pI2c;
RobMeades 0:cec745c014b7 419 gAddress = address << 1;
RobMeades 1:ee7cc8d75283 420 gSealCodes = sealCodes;
RobMeades 1:ee7cc8d75283 421
RobMeades 2:4c699a813451 422 if (gaugeEnable != NC) {
RobMeades 2:4c699a813451 423 pGaugeEnable = new DigitalOut(gaugeEnable, 1);
RobMeades 2:4c699a813451 424 wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS);
RobMeades 2:4c699a813451 425 }
RobMeades 0:cec745c014b7 426
RobMeades 0:cec745c014b7 427 if (gpI2c != NULL) {
RobMeades 0:cec745c014b7 428 gpI2c->lock();
RobMeades 1:ee7cc8d75283 429 gpI2c->frequency(I2C_CLOCK_FREQUENCY);
RobMeades 0:cec745c014b7 430
RobMeades 1:ee7cc8d75283 431 // Send a control command to read the device type
RobMeades 1:ee7cc8d75283 432 data[0] = 0x3e; // Set address to ManufacturerAccessControl
RobMeades 1:ee7cc8d75283 433 data[1] = 0x03; // First byte of HW_VERSION sub-command (0x03)
RobMeades 1:ee7cc8d75283 434 data[2] = 0x00; // Second byte of HW_VERSION sub-command (0x00) (register address will auto-increment)
RobMeades 0:cec745c014b7 435
RobMeades 1:ee7cc8d75283 436 if ((gpI2c->write(gAddress, &(data[0]), 3) == 0) &&
RobMeades 1:ee7cc8d75283 437 getTwoBytes(0x40, &answer)) { // Read from MACData address
RobMeades 1:ee7cc8d75283 438 if (answer == 0x00a8) {
RobMeades 1:ee7cc8d75283 439 // Read the full access codes, in case we need them
RobMeades 2:4c699a813451 440 if (readExtendedData(0x41d0, &(data[0]), sizeof (data))) {
RobMeades 1:ee7cc8d75283 441 // The four bytes are the full access codes
RobMeades 1:ee7cc8d75283 442 gFullAccessCodes = ((uint32_t) data[0] << 24) + ((uint32_t) data[1] << 16) + ((uint32_t) data[2] << 8) + data[3];
RobMeades 0:cec745c014b7 443 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 444 printf("BatteryGaugeBq35100 (I2C 0x%02x): full access code is 0x%08x.\n", gAddress >> 1,
RobMeades 1:ee7cc8d75283 445 (unsigned int) gFullAccessCodes);
RobMeades 0:cec745c014b7 446 #endif
RobMeades 1:ee7cc8d75283 447 gReady = true;
RobMeades 1:ee7cc8d75283 448 }
RobMeades 0:cec745c014b7 449 }
RobMeades 1:ee7cc8d75283 450
RobMeades 1:ee7cc8d75283 451 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 452 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x as HW_VERSION, expected 0x00a8.\n", gAddress >> 1, answer);
RobMeades 1:ee7cc8d75283 453 #endif
RobMeades 0:cec745c014b7 454 }
RobMeades 1:ee7cc8d75283 455
RobMeades 2:4c699a813451 456 disableGauge();
RobMeades 0:cec745c014b7 457 gpI2c->unlock();
RobMeades 0:cec745c014b7 458 }
RobMeades 0:cec745c014b7 459
RobMeades 0:cec745c014b7 460 #ifdef DEBUG_BQ35100
RobMeades 0:cec745c014b7 461 if (gReady) {
RobMeades 1:ee7cc8d75283 462 printf("BatteryGaugeBq35100 (I2C 0x%02x): handler initialised.\n", gAddress >> 1);
RobMeades 0:cec745c014b7 463 } else {
RobMeades 1:ee7cc8d75283 464 printf("BatteryGaugeBq35100 (I2C 0x%02x): init NOT successful.\n", gAddress >> 1);
RobMeades 0:cec745c014b7 465 }
RobMeades 0:cec745c014b7 466 #endif
RobMeades 0:cec745c014b7 467
RobMeades 0:cec745c014b7 468 return gReady;
RobMeades 0:cec745c014b7 469 }
RobMeades 0:cec745c014b7 470
RobMeades 1:ee7cc8d75283 471 // Switch on the battery capacity monitor.
RobMeades 2:4c699a813451 472 bool BatteryGaugeBq35100::enableGauge(bool nonVolatile)
RobMeades 1:ee7cc8d75283 473 {
RobMeades 2:4c699a813451 474 bool accumulatedCapacityOn = false;
RobMeades 1:ee7cc8d75283 475 bool success = false;
RobMeades 2:4c699a813451 476 char data[3];
RobMeades 2:4c699a813451 477 char opConfig;
RobMeades 2:4c699a813451 478 uint16_t controlStatus;
RobMeades 2:4c699a813451 479
RobMeades 1:ee7cc8d75283 480 if (gReady) {
RobMeades 2:4c699a813451 481 if (nonVolatile) {
RobMeades 2:4c699a813451 482 // Read the OpConfig register which is at address 0x41b1
RobMeades 2:4c699a813451 483 if (readExtendedData(0x41b1, &opConfig, sizeof (opConfig))) {
RobMeades 2:4c699a813451 484 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 485 printf("BatteryGaugeBq35100 (I2C 0x%02x): OpConfig is 0x%02x.\n", gAddress >> 1, opConfig);
RobMeades 2:4c699a813451 486 #endif
RobMeades 2:4c699a813451 487 // AccumulatedCapacity is achieved by setting GMSEL 1:0 (in bits 0 and 1) to 00
RobMeades 2:4c699a813451 488 if ((opConfig & 0x03) != 0) {
RobMeades 2:4c699a813451 489 opConfig &= ~0x03;
RobMeades 2:4c699a813451 490 // Write the new value back
RobMeades 2:4c699a813451 491 accumulatedCapacityOn = writeExtendedData(0x41b1, &opConfig, sizeof (opConfig));
RobMeades 2:4c699a813451 492 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 493 if (accumulatedCapacityOn) {
RobMeades 2:4c699a813451 494 printf("BatteryGaugeBq35100 (I2C 0x%02x): AccumulatedCapacity enabled, OpConfig becomes 0x%02x.\r\n", gAddress >> 1, opConfig);
RobMeades 2:4c699a813451 495 }
RobMeades 2:4c699a813451 496 #endif
RobMeades 2:4c699a813451 497 } else {
RobMeades 2:4c699a813451 498 accumulatedCapacityOn = true;
RobMeades 2:4c699a813451 499 }
RobMeades 2:4c699a813451 500 }
RobMeades 2:4c699a813451 501 }
RobMeades 2:4c699a813451 502
RobMeades 2:4c699a813451 503 if (accumulatedCapacityOn || !nonVolatile) {
RobMeades 2:4c699a813451 504 if (pGaugeEnable) {
RobMeades 2:4c699a813451 505 *pGaugeEnable = 1;
RobMeades 2:4c699a813451 506 wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS);
RobMeades 2:4c699a813451 507 }
RobMeades 2:4c699a813451 508 gpI2c->lock();
RobMeades 2:4c699a813451 509 data[0] = 0x3e; // Set address to ManufacturerAccessControl
RobMeades 2:4c699a813451 510 data[1] = 0x11; // First byte of GAUGE_START sub-command (0x11)
RobMeades 2:4c699a813451 511 data[2] = 0x00; // Second byte of GAUGE_START sub-command (0x00) (register address will auto-increment)
RobMeades 2:4c699a813451 512 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
RobMeades 2:4c699a813451 513 // Wait for GA bit of CONTROL_STATUS (bit 0) to become 1
RobMeades 2:4c699a813451 514 data[0] = 0;
RobMeades 2:4c699a813451 515 if (gpI2c->write(gAddress, &(data[0]), 1) == 0) {
RobMeades 2:4c699a813451 516 for (int x = 0; (x < GAUGE_COMPLETE_WAIT_MS / 10) && !success; x++) {
RobMeades 2:4c699a813451 517 if (getTwoBytes(0, &controlStatus)) {
RobMeades 2:4c699a813451 518 if ((controlStatus & 0x01) == 0x01) {
RobMeades 2:4c699a813451 519 success = true;
RobMeades 2:4c699a813451 520 } else {
RobMeades 2:4c699a813451 521 wait_ms(10);
RobMeades 2:4c699a813451 522 }
RobMeades 2:4c699a813451 523 } else {
RobMeades 2:4c699a813451 524 wait_ms(10);
RobMeades 2:4c699a813451 525 }
RobMeades 2:4c699a813451 526 }
RobMeades 2:4c699a813451 527 }
RobMeades 2:4c699a813451 528 }
RobMeades 2:4c699a813451 529 gpI2c->unlock();
RobMeades 2:4c699a813451 530 }
RobMeades 1:ee7cc8d75283 531 }
RobMeades 1:ee7cc8d75283 532
RobMeades 1:ee7cc8d75283 533 return success;
RobMeades 1:ee7cc8d75283 534 }
RobMeades 1:ee7cc8d75283 535
RobMeades 1:ee7cc8d75283 536 // Switch off the battery capacity monitor.
RobMeades 1:ee7cc8d75283 537 bool BatteryGaugeBq35100::disableGauge(void)
RobMeades 1:ee7cc8d75283 538 {
RobMeades 2:4c699a813451 539 bool accumulatedCapacityOn = false;
RobMeades 1:ee7cc8d75283 540 bool success = false;
RobMeades 2:4c699a813451 541 char data[3];
RobMeades 2:4c699a813451 542 char opConfig;
RobMeades 2:4c699a813451 543 uint16_t controlStatus;
RobMeades 1:ee7cc8d75283 544
RobMeades 1:ee7cc8d75283 545 if (gReady) {
RobMeades 2:4c699a813451 546 if (isGaugeEnabled()) {
RobMeades 2:4c699a813451 547 // Read the OpConfig register which is at address 0x41b1
RobMeades 2:4c699a813451 548 if (readExtendedData(0x41b1, &opConfig, sizeof (opConfig))) {
RobMeades 2:4c699a813451 549 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 550 printf("BatteryGaugeBq35100 (I2C 0x%02x): OpConfig is 0x%02x.\n", gAddress >> 1, opConfig);
RobMeades 2:4c699a813451 551 #endif
RobMeades 2:4c699a813451 552 // Check if AccumulatedCapacity is on
RobMeades 2:4c699a813451 553 if ((opConfig & 0x03) == 0) {
RobMeades 2:4c699a813451 554 accumulatedCapacityOn = true;
RobMeades 2:4c699a813451 555 }
RobMeades 2:4c699a813451 556
RobMeades 2:4c699a813451 557 // Send GAUGE_STOP
RobMeades 2:4c699a813451 558 gpI2c->lock();
RobMeades 2:4c699a813451 559 data[0] = 0x3e; // Set address to ManufacturerAccessControl
RobMeades 2:4c699a813451 560 data[1] = 0x12; // First byte of GAUGE_STOP sub-command (0x12)
RobMeades 2:4c699a813451 561 data[2] = 0x00; // Second byte of GAUGE_STOP sub-command (0x00) (register address will auto-increment)
RobMeades 2:4c699a813451 562 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
RobMeades 2:4c699a813451 563 // Wait for GA bit of CONTROL_STATUS (bit 0) to become 0 and,
RobMeades 2:4c699a813451 564 // if AccumulatedCapacity was on, wait for G_DONE
RobMeades 2:4c699a813451 565 // (bit 6 in CONTROL_STATUS) to be set
RobMeades 2:4c699a813451 566 data[0] = 0;
RobMeades 2:4c699a813451 567 if (gpI2c->write(gAddress, &(data[0]), 1) == 0) {
RobMeades 2:4c699a813451 568 for (int x = 0; (x < GAUGE_COMPLETE_WAIT_MS / 10) && !success; x++) {
RobMeades 2:4c699a813451 569 if (getTwoBytes(0, &controlStatus)) {
RobMeades 2:4c699a813451 570 if ((controlStatus & 0x01) == 0) {
RobMeades 2:4c699a813451 571 if (accumulatedCapacityOn) {
RobMeades 2:4c699a813451 572 if (((controlStatus >> 6) & 0x01) == 0x01) {
RobMeades 2:4c699a813451 573 success = true;
RobMeades 2:4c699a813451 574 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 575 printf("BatteryGaugeBq35100 (I2C 0x%02x): AccumulatedCapacity data written to non-volatile memory.\r\n", gAddress >> 1);
RobMeades 2:4c699a813451 576 #endif
RobMeades 2:4c699a813451 577 } else {
RobMeades 2:4c699a813451 578 wait_ms(10);
RobMeades 2:4c699a813451 579 }
RobMeades 2:4c699a813451 580 } else {
RobMeades 2:4c699a813451 581 success = true;
RobMeades 2:4c699a813451 582 }
RobMeades 2:4c699a813451 583 } else {
RobMeades 2:4c699a813451 584 wait_ms(10);
RobMeades 2:4c699a813451 585 }
RobMeades 2:4c699a813451 586 } else {
RobMeades 2:4c699a813451 587 wait_ms(10);
RobMeades 2:4c699a813451 588 }
RobMeades 2:4c699a813451 589 }
RobMeades 2:4c699a813451 590 }
RobMeades 2:4c699a813451 591 }
RobMeades 2:4c699a813451 592 gpI2c->unlock();
RobMeades 2:4c699a813451 593 }
RobMeades 2:4c699a813451 594 } else {
RobMeades 2:4c699a813451 595 success = true;
RobMeades 2:4c699a813451 596 }
RobMeades 2:4c699a813451 597
RobMeades 2:4c699a813451 598 if (pGaugeEnable) {
RobMeades 2:4c699a813451 599 *pGaugeEnable = 0;
RobMeades 2:4c699a813451 600 }
RobMeades 1:ee7cc8d75283 601 }
RobMeades 1:ee7cc8d75283 602
RobMeades 1:ee7cc8d75283 603 return success;
RobMeades 1:ee7cc8d75283 604 }
RobMeades 1:ee7cc8d75283 605
RobMeades 1:ee7cc8d75283 606 // Determine whether battery gauging is enabled.
RobMeades 1:ee7cc8d75283 607 bool BatteryGaugeBq35100::isGaugeEnabled(void)
RobMeades 1:ee7cc8d75283 608 {
RobMeades 2:4c699a813451 609 bool gaugeEnabled = false;
RobMeades 2:4c699a813451 610 char data[1];
RobMeades 2:4c699a813451 611 uint16_t controlStatus;
RobMeades 2:4c699a813451 612
RobMeades 1:ee7cc8d75283 613 if (gReady) {
RobMeades 2:4c699a813451 614 // Check the GA bit (bit 0) in CONTROL_STATUS
RobMeades 2:4c699a813451 615 data[0] = 0;
RobMeades 2:4c699a813451 616 if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) &&
RobMeades 2:4c699a813451 617 getTwoBytes(0, &controlStatus)) {
RobMeades 2:4c699a813451 618 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 619 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x as CONTROL_STATUS.\n", gAddress >> 1, controlStatus);
RobMeades 2:4c699a813451 620 #endif
RobMeades 2:4c699a813451 621 if ((controlStatus & 0x01) == 0x01) {
RobMeades 2:4c699a813451 622 gaugeEnabled = true;
RobMeades 2:4c699a813451 623 }
RobMeades 2:4c699a813451 624 }
RobMeades 1:ee7cc8d75283 625 }
RobMeades 1:ee7cc8d75283 626
RobMeades 2:4c699a813451 627 return gaugeEnabled;
RobMeades 1:ee7cc8d75283 628 }
RobMeades 1:ee7cc8d75283 629
RobMeades 1:ee7cc8d75283 630 // Set the designed capacity of the cell.
RobMeades 1:ee7cc8d75283 631 bool BatteryGaugeBq35100::setDesignCapacity(uint32_t capacityMAh)
RobMeades 1:ee7cc8d75283 632 {
RobMeades 1:ee7cc8d75283 633 bool success = false;
RobMeades 1:ee7cc8d75283 634 char data[2];
RobMeades 1:ee7cc8d75283 635
RobMeades 1:ee7cc8d75283 636 if (gReady) {
RobMeades 1:ee7cc8d75283 637 gpI2c->lock();
RobMeades 1:ee7cc8d75283 638
RobMeades 1:ee7cc8d75283 639 data[0] = capacityMAh >> 8; // Upper byte of design capacity
RobMeades 1:ee7cc8d75283 640 data[1] = capacityMAh; // Lower byte of design capacity
RobMeades 1:ee7cc8d75283 641
RobMeades 1:ee7cc8d75283 642 // Write to the "Cell Design Capacity mAh" address in data flash
RobMeades 2:4c699a813451 643 if (writeExtendedData(0x41fe, &(data[0]), sizeof(data))) {
RobMeades 1:ee7cc8d75283 644 success = true;
RobMeades 1:ee7cc8d75283 645
RobMeades 1:ee7cc8d75283 646 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 647 printf("BatteryGaugeBq35100 (I2C 0x%02x): designed cell capacity set to %d mAh.\n", gAddress >> 1,
RobMeades 1:ee7cc8d75283 648 (unsigned int) capacityMAh);
RobMeades 1:ee7cc8d75283 649 #endif
RobMeades 1:ee7cc8d75283 650 }
RobMeades 1:ee7cc8d75283 651
RobMeades 1:ee7cc8d75283 652 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 653 }
RobMeades 1:ee7cc8d75283 654
RobMeades 1:ee7cc8d75283 655 return success;
RobMeades 1:ee7cc8d75283 656 }
RobMeades 1:ee7cc8d75283 657
RobMeades 1:ee7cc8d75283 658 // Get the designed capacity of the cell.
RobMeades 1:ee7cc8d75283 659 bool BatteryGaugeBq35100::getDesignCapacity(uint32_t *pCapacityMAh)
RobMeades 1:ee7cc8d75283 660 {
RobMeades 1:ee7cc8d75283 661 bool success = false;
RobMeades 1:ee7cc8d75283 662 uint16_t data;
RobMeades 1:ee7cc8d75283 663
RobMeades 1:ee7cc8d75283 664 if (gReady) {
RobMeades 1:ee7cc8d75283 665 gpI2c->lock();
RobMeades 1:ee7cc8d75283 666
RobMeades 1:ee7cc8d75283 667 // Read from the DesignCapacity address
RobMeades 1:ee7cc8d75283 668 if (getTwoBytes (0x3c, &data)) {
RobMeades 1:ee7cc8d75283 669 success = true;
RobMeades 1:ee7cc8d75283 670
RobMeades 1:ee7cc8d75283 671 // The answer is in mAh
RobMeades 1:ee7cc8d75283 672 if (pCapacityMAh) {
RobMeades 1:ee7cc8d75283 673 *pCapacityMAh = data;
RobMeades 1:ee7cc8d75283 674 }
RobMeades 1:ee7cc8d75283 675
RobMeades 1:ee7cc8d75283 676 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 677 printf("BatteryGaugeBq35100 (I2C 0x%02x): designed cell capacity is %d mAh.\n", gAddress >> 1, data);
RobMeades 1:ee7cc8d75283 678 #endif
RobMeades 1:ee7cc8d75283 679 }
RobMeades 1:ee7cc8d75283 680
RobMeades 1:ee7cc8d75283 681 }
RobMeades 1:ee7cc8d75283 682
RobMeades 1:ee7cc8d75283 683 return success;
RobMeades 1:ee7cc8d75283 684 }
RobMeades 1:ee7cc8d75283 685
RobMeades 1:ee7cc8d75283 686 // Get the temperature of the chip.
RobMeades 1:ee7cc8d75283 687 bool BatteryGaugeBq35100::getTemperature(int32_t *pTemperatureC)
RobMeades 1:ee7cc8d75283 688 {
RobMeades 1:ee7cc8d75283 689 bool success = false;
RobMeades 1:ee7cc8d75283 690 int32_t temperatureC = 0;
RobMeades 1:ee7cc8d75283 691 uint16_t data;
RobMeades 1:ee7cc8d75283 692
RobMeades 2:4c699a813451 693 if (gReady && makeAdcReading()) {
RobMeades 1:ee7cc8d75283 694 gpI2c->lock();
RobMeades 1:ee7cc8d75283 695 // Read from the temperature register address
RobMeades 1:ee7cc8d75283 696 if (getTwoBytes (0x06, &data)) {
RobMeades 1:ee7cc8d75283 697 success = true;
RobMeades 1:ee7cc8d75283 698
RobMeades 1:ee7cc8d75283 699 // The answer is in units of 0.1 K, so convert to C
RobMeades 1:ee7cc8d75283 700 temperatureC = ((int32_t) data / 10) - 273;
RobMeades 1:ee7cc8d75283 701
RobMeades 1:ee7cc8d75283 702 if (pTemperatureC) {
RobMeades 1:ee7cc8d75283 703 *pTemperatureC = temperatureC;
RobMeades 1:ee7cc8d75283 704 }
RobMeades 1:ee7cc8d75283 705
RobMeades 1:ee7cc8d75283 706 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 707 printf("BatteryGaugeBq35100 (I2C 0x%02x): chip temperature %.1f K, so %d C.\n", gAddress >> 1, ((float) data) / 10, (int) temperatureC);
RobMeades 1:ee7cc8d75283 708 #endif
RobMeades 1:ee7cc8d75283 709 }
RobMeades 1:ee7cc8d75283 710
RobMeades 1:ee7cc8d75283 711 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 712 }
RobMeades 1:ee7cc8d75283 713
RobMeades 1:ee7cc8d75283 714 return success;
RobMeades 1:ee7cc8d75283 715 }
RobMeades 1:ee7cc8d75283 716
RobMeades 1:ee7cc8d75283 717 // Get the voltage of the battery.
RobMeades 1:ee7cc8d75283 718 bool BatteryGaugeBq35100::getVoltage(int32_t *pVoltageMV)
RobMeades 1:ee7cc8d75283 719 {
RobMeades 1:ee7cc8d75283 720 bool success = false;
RobMeades 1:ee7cc8d75283 721 uint16_t data = 0;
RobMeades 1:ee7cc8d75283 722
RobMeades 2:4c699a813451 723 if (gReady && makeAdcReading()) {
RobMeades 1:ee7cc8d75283 724 gpI2c->lock();
RobMeades 1:ee7cc8d75283 725 // Read from the voltage register address
RobMeades 1:ee7cc8d75283 726 if (getTwoBytes (0x08, &data)) {
RobMeades 1:ee7cc8d75283 727 success = true;
RobMeades 1:ee7cc8d75283 728
RobMeades 1:ee7cc8d75283 729 // The answer is in mV
RobMeades 1:ee7cc8d75283 730 if (pVoltageMV) {
RobMeades 1:ee7cc8d75283 731 *pVoltageMV = (int32_t) data;
RobMeades 1:ee7cc8d75283 732 }
RobMeades 1:ee7cc8d75283 733
RobMeades 1:ee7cc8d75283 734 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 735 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery voltage %.3f V.\n", gAddress >> 1, ((float) data) / 1000);
RobMeades 1:ee7cc8d75283 736 #endif
RobMeades 1:ee7cc8d75283 737 }
RobMeades 1:ee7cc8d75283 738
RobMeades 1:ee7cc8d75283 739 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 740 }
RobMeades 1:ee7cc8d75283 741
RobMeades 1:ee7cc8d75283 742 return success;
RobMeades 1:ee7cc8d75283 743 }
RobMeades 1:ee7cc8d75283 744
RobMeades 1:ee7cc8d75283 745 // Get the current flowing from the battery.
RobMeades 1:ee7cc8d75283 746 bool BatteryGaugeBq35100::getCurrent(int32_t *pCurrentMA)
RobMeades 1:ee7cc8d75283 747 {
RobMeades 1:ee7cc8d75283 748 bool success = false;
RobMeades 1:ee7cc8d75283 749 int32_t currentMA = 0;
RobMeades 2:4c699a813451 750 uint16_t data = 0;
RobMeades 1:ee7cc8d75283 751
RobMeades 2:4c699a813451 752 if (gReady && makeAdcReading()) {
RobMeades 1:ee7cc8d75283 753 gpI2c->lock();
RobMeades 1:ee7cc8d75283 754 // Read from the average current register address
RobMeades 1:ee7cc8d75283 755 if (getTwoBytes (0x0c, &data)) {
RobMeades 1:ee7cc8d75283 756 success = true;
RobMeades 1:ee7cc8d75283 757
RobMeades 1:ee7cc8d75283 758 if (pCurrentMA) {
RobMeades 1:ee7cc8d75283 759 *pCurrentMA = currentMA;
RobMeades 1:ee7cc8d75283 760 }
RobMeades 1:ee7cc8d75283 761
RobMeades 1:ee7cc8d75283 762 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 763 printf("BatteryGaugeBq35100 (I2C 0x%02x): current %d mA.\n", gAddress >> 1, (int) currentMA);
RobMeades 1:ee7cc8d75283 764 #endif
RobMeades 1:ee7cc8d75283 765 }
RobMeades 1:ee7cc8d75283 766
RobMeades 1:ee7cc8d75283 767 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 768 }
RobMeades 1:ee7cc8d75283 769
RobMeades 1:ee7cc8d75283 770 return success;
RobMeades 1:ee7cc8d75283 771 }
RobMeades 1:ee7cc8d75283 772
RobMeades 1:ee7cc8d75283 773 // Get the battery capacity used.
RobMeades 1:ee7cc8d75283 774 bool BatteryGaugeBq35100::getUsedCapacity(uint32_t *pCapacityUAh)
RobMeades 1:ee7cc8d75283 775 {
RobMeades 1:ee7cc8d75283 776 bool success = false;
RobMeades 1:ee7cc8d75283 777 char bytes[5];
RobMeades 1:ee7cc8d75283 778 uint32_t data;
RobMeades 1:ee7cc8d75283 779
RobMeades 2:4c699a813451 780 if (gReady && makeAdcReading()) {
RobMeades 1:ee7cc8d75283 781 gpI2c->lock();
RobMeades 1:ee7cc8d75283 782 // Read four bytes from the AccummulatedCapacity register address
RobMeades 1:ee7cc8d75283 783
RobMeades 1:ee7cc8d75283 784 // Send a command to read from registerAddress
RobMeades 1:ee7cc8d75283 785 bytes[0] = 0x02;
RobMeades 1:ee7cc8d75283 786 bytes[1] = 0;
RobMeades 1:ee7cc8d75283 787 bytes[2] = 0;
RobMeades 1:ee7cc8d75283 788 bytes[3] = 0;
RobMeades 1:ee7cc8d75283 789 bytes[4] = 0;
RobMeades 1:ee7cc8d75283 790
RobMeades 1:ee7cc8d75283 791 if ((gpI2c->write(gAddress, &(bytes[0]), 1) == 0) &&
RobMeades 1:ee7cc8d75283 792 (gpI2c->read(gAddress, &(bytes[1]), 4) == 0)) {
RobMeades 1:ee7cc8d75283 793 success = true;
RobMeades 1:ee7cc8d75283 794 data = (((uint32_t) bytes[4]) << 24) + (((uint32_t) bytes[3]) << 16) + (((uint32_t) bytes[2]) << 8) + bytes[1];
RobMeades 1:ee7cc8d75283 795
RobMeades 1:ee7cc8d75283 796 // The answer is in uAh
RobMeades 1:ee7cc8d75283 797 if (pCapacityUAh) {
RobMeades 1:ee7cc8d75283 798 *pCapacityUAh = data;
RobMeades 1:ee7cc8d75283 799 }
RobMeades 1:ee7cc8d75283 800
RobMeades 1:ee7cc8d75283 801 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 802 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity used %u uAh.\n", gAddress >> 1, (unsigned int) data);
RobMeades 1:ee7cc8d75283 803 #endif
RobMeades 1:ee7cc8d75283 804 }
RobMeades 1:ee7cc8d75283 805
RobMeades 1:ee7cc8d75283 806 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 807 }
RobMeades 1:ee7cc8d75283 808
RobMeades 1:ee7cc8d75283 809 return success;
RobMeades 1:ee7cc8d75283 810 }
RobMeades 1:ee7cc8d75283 811
RobMeades 1:ee7cc8d75283 812 // Get the battery capacity remaining.
RobMeades 1:ee7cc8d75283 813 bool BatteryGaugeBq35100::getRemainingCapacity(uint32_t *pCapacityUAh)
RobMeades 1:ee7cc8d75283 814 {
RobMeades 1:ee7cc8d75283 815 bool success = false;
RobMeades 1:ee7cc8d75283 816 uint32_t designCapacityUAh;
RobMeades 1:ee7cc8d75283 817 uint32_t usedCapacityUAh;
RobMeades 1:ee7cc8d75283 818
RobMeades 1:ee7cc8d75283 819 // First, get the designed capacity
RobMeades 1:ee7cc8d75283 820 if (getDesignCapacity(&designCapacityUAh)) {
RobMeades 1:ee7cc8d75283 821 designCapacityUAh *= 1000;
RobMeades 1:ee7cc8d75283 822 // Then get the used capacity
RobMeades 1:ee7cc8d75283 823 if (getUsedCapacity(&usedCapacityUAh)) {
RobMeades 1:ee7cc8d75283 824 success = true;
RobMeades 1:ee7cc8d75283 825 // Limit the result
RobMeades 1:ee7cc8d75283 826 if (usedCapacityUAh > designCapacityUAh) {
RobMeades 1:ee7cc8d75283 827 usedCapacityUAh = designCapacityUAh;
RobMeades 1:ee7cc8d75283 828 }
RobMeades 1:ee7cc8d75283 829
RobMeades 1:ee7cc8d75283 830 // The answer is in uAh
RobMeades 1:ee7cc8d75283 831 if (pCapacityUAh) {
RobMeades 1:ee7cc8d75283 832 *pCapacityUAh = designCapacityUAh - usedCapacityUAh;
RobMeades 1:ee7cc8d75283 833 }
RobMeades 1:ee7cc8d75283 834
RobMeades 1:ee7cc8d75283 835 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 836 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity remaining %u uAh (from a designed capacity of %d uAh).\n", gAddress >> 1,
RobMeades 1:ee7cc8d75283 837 (unsigned int) (designCapacityUAh - usedCapacityUAh), (unsigned int) designCapacityUAh);
RobMeades 1:ee7cc8d75283 838 #endif
RobMeades 1:ee7cc8d75283 839 }
RobMeades 1:ee7cc8d75283 840 }
RobMeades 1:ee7cc8d75283 841
RobMeades 1:ee7cc8d75283 842 return success;
RobMeades 1:ee7cc8d75283 843 }
RobMeades 1:ee7cc8d75283 844
RobMeades 1:ee7cc8d75283 845 // Get the percentage capacity remaining.
RobMeades 1:ee7cc8d75283 846 bool BatteryGaugeBq35100::getRemainingPercentage(int32_t *pBatteryPercentage)
RobMeades 1:ee7cc8d75283 847 {
RobMeades 1:ee7cc8d75283 848 bool success = false;
RobMeades 1:ee7cc8d75283 849 uint32_t designCapacityUAh;
RobMeades 1:ee7cc8d75283 850 uint32_t usedCapacityUAh;
RobMeades 1:ee7cc8d75283 851 int32_t batteryPercentage;
RobMeades 1:ee7cc8d75283 852
RobMeades 2:4c699a813451 853 // First, get the designed capacity (which is actually in mAh)
RobMeades 1:ee7cc8d75283 854 if (getDesignCapacity(&designCapacityUAh)) {
RobMeades 2:4c699a813451 855 // Convert to uAh
RobMeades 1:ee7cc8d75283 856 designCapacityUAh *= 1000;
RobMeades 1:ee7cc8d75283 857 // Then get the used capacity
RobMeades 1:ee7cc8d75283 858 if (getUsedCapacity(&usedCapacityUAh)) {
RobMeades 1:ee7cc8d75283 859 success = true;
RobMeades 1:ee7cc8d75283 860 // Limit the result
RobMeades 1:ee7cc8d75283 861 if (usedCapacityUAh > designCapacityUAh) {
RobMeades 1:ee7cc8d75283 862 usedCapacityUAh = designCapacityUAh;
RobMeades 1:ee7cc8d75283 863 }
RobMeades 1:ee7cc8d75283 864 batteryPercentage = (uint64_t) (designCapacityUAh - usedCapacityUAh) * 100 / designCapacityUAh;
RobMeades 1:ee7cc8d75283 865
RobMeades 1:ee7cc8d75283 866 if (pBatteryPercentage) {
RobMeades 1:ee7cc8d75283 867 *pBatteryPercentage = batteryPercentage;
RobMeades 1:ee7cc8d75283 868 }
RobMeades 1:ee7cc8d75283 869
RobMeades 1:ee7cc8d75283 870 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 871 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity remaining %d%%.\n", gAddress >> 1,
RobMeades 1:ee7cc8d75283 872 (unsigned int) batteryPercentage);
RobMeades 1:ee7cc8d75283 873 #endif
RobMeades 1:ee7cc8d75283 874 }
RobMeades 1:ee7cc8d75283 875 }
RobMeades 1:ee7cc8d75283 876
RobMeades 1:ee7cc8d75283 877 return success;
RobMeades 1:ee7cc8d75283 878 }
RobMeades 1:ee7cc8d75283 879
RobMeades 2:4c699a813451 880 // Indicate that a new battery has been inserted.
RobMeades 2:4c699a813451 881 bool BatteryGaugeBq35100::newBattery(uint32_t capacityMAh)
RobMeades 2:4c699a813451 882 {
RobMeades 2:4c699a813451 883 bool success = false;
RobMeades 2:4c699a813451 884 char data[3];
RobMeades 2:4c699a813451 885
RobMeades 2:4c699a813451 886 if (gReady) {
RobMeades 2:4c699a813451 887 if (setDesignCapacity(capacityMAh)) {
RobMeades 2:4c699a813451 888 gpI2c->lock();
RobMeades 2:4c699a813451 889 // Send a control command to indicate NEW_BATTERY
RobMeades 2:4c699a813451 890 data[0] = 0x3e; // Set address to ManufacturerAccessControl
RobMeades 2:4c699a813451 891 data[1] = 0x13; // First byte of NEW_BATTERY sub-command (0x13)
RobMeades 2:4c699a813451 892 data[2] = 0xA6; // Second byte of NEW_BATTERY sub-command (0xA6) (register address will auto-increment)
RobMeades 2:4c699a813451 893 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
RobMeades 2:4c699a813451 894 success = true;
RobMeades 2:4c699a813451 895 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 896 printf("BatteryGaugeBq35100 (I2C 0x%02x): new battery set.\n", gAddress >> 1);
RobMeades 2:4c699a813451 897 #endif
RobMeades 2:4c699a813451 898 }
RobMeades 2:4c699a813451 899
RobMeades 2:4c699a813451 900 gpI2c->unlock();
RobMeades 2:4c699a813451 901 }
RobMeades 2:4c699a813451 902 }
RobMeades 2:4c699a813451 903
RobMeades 2:4c699a813451 904 return success;
RobMeades 2:4c699a813451 905 }
RobMeades 2:4c699a813451 906
RobMeades 2:4c699a813451 907 // Read configuration data.
RobMeades 2:4c699a813451 908 bool BatteryGaugeBq35100::advancedGetConfig(int32_t address, char * pData, int32_t length)
RobMeades 2:4c699a813451 909 {
RobMeades 2:4c699a813451 910 bool success = false;
RobMeades 2:4c699a813451 911
RobMeades 2:4c699a813451 912 if (gReady) {
RobMeades 2:4c699a813451 913 gpI2c->lock();
RobMeades 2:4c699a813451 914
RobMeades 2:4c699a813451 915 success = readExtendedData(address, pData, length);
RobMeades 2:4c699a813451 916
RobMeades 2:4c699a813451 917 gpI2c->unlock();
RobMeades 2:4c699a813451 918 }
RobMeades 2:4c699a813451 919
RobMeades 2:4c699a813451 920 return success;
RobMeades 2:4c699a813451 921 }
RobMeades 2:4c699a813451 922
RobMeades 2:4c699a813451 923 // Write configuration data.
RobMeades 2:4c699a813451 924 bool BatteryGaugeBq35100::advancedSetConfig(int32_t address, const char * pData, int32_t length)
RobMeades 2:4c699a813451 925 {
RobMeades 2:4c699a813451 926 bool success = false;
RobMeades 2:4c699a813451 927
RobMeades 2:4c699a813451 928 if (gReady) {
RobMeades 2:4c699a813451 929 gpI2c->lock();
RobMeades 2:4c699a813451 930
RobMeades 2:4c699a813451 931 success = writeExtendedData(address, pData, length);
RobMeades 2:4c699a813451 932
RobMeades 2:4c699a813451 933 gpI2c->unlock();
RobMeades 2:4c699a813451 934 }
RobMeades 2:4c699a813451 935
RobMeades 2:4c699a813451 936 return success;
RobMeades 2:4c699a813451 937 }
RobMeades 2:4c699a813451 938
RobMeades 2:4c699a813451 939 // Send a control word.
RobMeades 2:4c699a813451 940 bool BatteryGaugeBq35100::advancedSendControlWord(uint16_t controlWord, uint16_t *pDataReturned)
RobMeades 2:4c699a813451 941 {
RobMeades 2:4c699a813451 942 bool success = false;
RobMeades 2:4c699a813451 943 char data[3];
RobMeades 2:4c699a813451 944
RobMeades 2:4c699a813451 945 if (gReady) {
RobMeades 2:4c699a813451 946 gpI2c->lock();
RobMeades 2:4c699a813451 947
RobMeades 2:4c699a813451 948 // Send the control command
RobMeades 2:4c699a813451 949 data[0] = 0x3e; // Set address to ManufacturerAccessControl
RobMeades 2:4c699a813451 950 data[1] = (char) controlWord; // First byte of controlWord
RobMeades 2:4c699a813451 951 data[2] = (char) (controlWord >> 8); // Second byte of controlWord
RobMeades 2:4c699a813451 952 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
RobMeades 2:4c699a813451 953 // Read the two bytes returned if requested
RobMeades 2:4c699a813451 954 if (pDataReturned != NULL) {
RobMeades 2:4c699a813451 955 if (getTwoBytes(0x40, pDataReturned)) { // Read from MACData
RobMeades 2:4c699a813451 956 success = true;
RobMeades 2:4c699a813451 957 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 958 printf("BatteryGaugeBq35100 (I2C 0x%02x): sent control word 0x%04x, read back 0x%04x.\n", gAddress >> 1, controlWord, *pDataReturned);
RobMeades 2:4c699a813451 959 #endif
RobMeades 2:4c699a813451 960 }
RobMeades 2:4c699a813451 961 } else {
RobMeades 2:4c699a813451 962 success = true;
RobMeades 2:4c699a813451 963 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 964 printf("BatteryGaugeBq35100 (I2C 0x%02x): sent control word 0x%04x.\n", gAddress >> 1, controlWord);
RobMeades 2:4c699a813451 965 #endif
RobMeades 2:4c699a813451 966 }
RobMeades 2:4c699a813451 967 }
RobMeades 2:4c699a813451 968
RobMeades 2:4c699a813451 969 gpI2c->unlock();
RobMeades 2:4c699a813451 970 }
RobMeades 2:4c699a813451 971
RobMeades 2:4c699a813451 972 return success;
RobMeades 2:4c699a813451 973 }
RobMeades 2:4c699a813451 974
RobMeades 2:4c699a813451 975 // Read two bytes starting at a given address on the chip.
RobMeades 2:4c699a813451 976 bool BatteryGaugeBq35100::advancedGet(uint8_t address, uint16_t *pDataReturned)
RobMeades 2:4c699a813451 977 {
RobMeades 2:4c699a813451 978 bool success = false;
RobMeades 2:4c699a813451 979 uint16_t value = 0;
RobMeades 2:4c699a813451 980
RobMeades 2:4c699a813451 981 if (gReady) {
RobMeades 2:4c699a813451 982 // Make sure there's a recent reading, as most
RobMeades 2:4c699a813451 983 // of these commands involve the chip having done one
RobMeades 2:4c699a813451 984 if (makeAdcReading()) {
RobMeades 2:4c699a813451 985 gpI2c->lock();
RobMeades 2:4c699a813451 986 // Read the data
RobMeades 2:4c699a813451 987 if (getTwoBytes(address, &value)) {
RobMeades 2:4c699a813451 988 success = true;
RobMeades 2:4c699a813451 989 #ifdef DEBUG_BQ35100
RobMeades 2:4c699a813451 990 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x from addresses 0x%02x and 0x%02x.\n", gAddress >> 1, value, address, address + 1);
RobMeades 2:4c699a813451 991 #endif
RobMeades 2:4c699a813451 992 if (pDataReturned != NULL) {
RobMeades 2:4c699a813451 993 *pDataReturned = value;
RobMeades 2:4c699a813451 994 }
RobMeades 2:4c699a813451 995 }
RobMeades 2:4c699a813451 996 gpI2c->unlock();
RobMeades 2:4c699a813451 997 }
RobMeades 2:4c699a813451 998 }
RobMeades 2:4c699a813451 999
RobMeades 2:4c699a813451 1000 return success;
RobMeades 2:4c699a813451 1001 }
RobMeades 2:4c699a813451 1002
RobMeades 1:ee7cc8d75283 1003 // Get the security mode of the chip.
RobMeades 1:ee7cc8d75283 1004 BatteryGaugeBq35100::SecurityMode BatteryGaugeBq35100::advancedGetSecurityMode(void)
RobMeades 1:ee7cc8d75283 1005 {
RobMeades 1:ee7cc8d75283 1006 SecurityMode securityMode = SECURITY_MODE_UNKNOWN;
RobMeades 1:ee7cc8d75283 1007
RobMeades 1:ee7cc8d75283 1008 if (gReady) {
RobMeades 1:ee7cc8d75283 1009 gpI2c->lock();
RobMeades 1:ee7cc8d75283 1010
RobMeades 2:4c699a813451 1011 securityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 1012
RobMeades 1:ee7cc8d75283 1013 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 1014 }
RobMeades 1:ee7cc8d75283 1015
RobMeades 1:ee7cc8d75283 1016 return securityMode;
RobMeades 1:ee7cc8d75283 1017 }
RobMeades 1:ee7cc8d75283 1018
RobMeades 1:ee7cc8d75283 1019 // Set the security mode of the chip.
RobMeades 1:ee7cc8d75283 1020 bool BatteryGaugeBq35100::advancedSetSecurityMode(SecurityMode securityMode)
RobMeades 1:ee7cc8d75283 1021 {
RobMeades 1:ee7cc8d75283 1022 bool success = false;
RobMeades 1:ee7cc8d75283 1023
RobMeades 1:ee7cc8d75283 1024 if (gReady) {
RobMeades 1:ee7cc8d75283 1025 gpI2c->lock();
RobMeades 1:ee7cc8d75283 1026
RobMeades 1:ee7cc8d75283 1027 success = setSecurityMode(securityMode);
RobMeades 1:ee7cc8d75283 1028
RobMeades 1:ee7cc8d75283 1029 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 1030 }
RobMeades 1:ee7cc8d75283 1031
RobMeades 1:ee7cc8d75283 1032 return success;
RobMeades 1:ee7cc8d75283 1033 }
RobMeades 1:ee7cc8d75283 1034
RobMeades 1:ee7cc8d75283 1035 // Do a hard reset of the chip.
RobMeades 1:ee7cc8d75283 1036 bool BatteryGaugeBq35100::advancedReset(void)
RobMeades 1:ee7cc8d75283 1037 {
RobMeades 1:ee7cc8d75283 1038 bool success = false;
RobMeades 1:ee7cc8d75283 1039 SecurityMode securityMode;
RobMeades 1:ee7cc8d75283 1040 char data[3];
RobMeades 1:ee7cc8d75283 1041
RobMeades 2:4c699a813451 1042 if (gReady) {
RobMeades 1:ee7cc8d75283 1043 gpI2c->lock();
RobMeades 1:ee7cc8d75283 1044
RobMeades 1:ee7cc8d75283 1045 securityMode = getSecurityMode(); // Must be inside lock()
RobMeades 1:ee7cc8d75283 1046 // Handle unsealing, as this command only works when unsealed
RobMeades 1:ee7cc8d75283 1047 if (setSecurityMode(SECURITY_MODE_UNSEALED)) {
RobMeades 1:ee7cc8d75283 1048 // Send a RESET sub-command
RobMeades 2:4c699a813451 1049 data[0] = 0x3e; // Set address to ManufacturerAccessControl
RobMeades 1:ee7cc8d75283 1050 data[1] = 0x41; // First byte of RESET sub-command (0x41)
RobMeades 1:ee7cc8d75283 1051 data[2] = 0x00; // Second byte of RESET sub-command (0x00) (register address will auto-increment)
RobMeades 1:ee7cc8d75283 1052
RobMeades 1:ee7cc8d75283 1053 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
RobMeades 1:ee7cc8d75283 1054 success = true;
RobMeades 1:ee7cc8d75283 1055 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 1056 printf("BatteryGaugeBq35100 (I2C 0x%02x): chip hard reset.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 1057 #endif
RobMeades 1:ee7cc8d75283 1058 }
RobMeades 1:ee7cc8d75283 1059
RobMeades 1:ee7cc8d75283 1060 // Set the security mode back to what it was
RobMeades 1:ee7cc8d75283 1061 if (!setSecurityMode(securityMode)) {
RobMeades 1:ee7cc8d75283 1062 success = false;
RobMeades 1:ee7cc8d75283 1063 }
RobMeades 1:ee7cc8d75283 1064 }
RobMeades 1:ee7cc8d75283 1065
RobMeades 1:ee7cc8d75283 1066 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 1067 }
RobMeades 1:ee7cc8d75283 1068
RobMeades 1:ee7cc8d75283 1069 return success;
RobMeades 1:ee7cc8d75283 1070 }
RobMeades 1:ee7cc8d75283 1071
RobMeades 0:cec745c014b7 1072 /* End Of File */