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:
Thu Nov 09 22:55:13 2017 +0000
Revision:
1:ee7cc8d75283
Parent:
0:cec745c014b7
Child:
2:4c699a813451
Lots of functionality, having figured out that a reduced I2C clock rate seems to be required and how the seal/unseal functionality and data flash checksumming works.

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 1:ee7cc8d75283 23 #define DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 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 many loops to wait for a configuration update to be permitted.
RobMeades 1:ee7cc8d75283 38 * Experience suggests that the limit really does need to be this large. */
RobMeades 1:ee7cc8d75283 39 #define CONFIG_UPDATE_LOOPS 200
RobMeades 1:ee7cc8d75283 40
RobMeades 1:ee7cc8d75283 41 /** How long to delay when running around the config update loop. */
RobMeades 1:ee7cc8d75283 42 #define CONFIG_UPDATE_LOOP_DELAY_MS 100
RobMeades 1:ee7cc8d75283 43
RobMeades 1:ee7cc8d75283 44 /** How long to wait for each loop while device is initialising. */
RobMeades 1:ee7cc8d75283 45 #define INIT_LOOP_WAIT_MS 100
RobMeades 1:ee7cc8d75283 46
RobMeades 1:ee7cc8d75283 47 /** The maximum number of init loops to wait for. */
RobMeades 1:ee7cc8d75283 48 #define INIT_LOOP_COUNT 10
RobMeades 1:ee7cc8d75283 49
RobMeades 1:ee7cc8d75283 50 /** How long to wait for a security mode change to succeed. */
RobMeades 1:ee7cc8d75283 51 #define SET_SECURITY_MODE_RETRY_SECONDS 5
RobMeades 1:ee7cc8d75283 52
RobMeades 0:cec745c014b7 53 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 54 // PRIVATE VARIABLES
RobMeades 0:cec745c014b7 55 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 56
RobMeades 0:cec745c014b7 57 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 58 // GENERIC PRIVATE FUNCTIONS
RobMeades 0:cec745c014b7 59 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 60
RobMeades 0:cec745c014b7 61 // Read two bytes from an address.
RobMeades 0:cec745c014b7 62 // Note: gpI2c should be locked before this is called.
RobMeades 0:cec745c014b7 63 bool BatteryGaugeBq35100::getTwoBytes (uint8_t registerAddress, uint16_t *pBytes)
RobMeades 0:cec745c014b7 64 {
RobMeades 0:cec745c014b7 65 bool success = false;
RobMeades 0:cec745c014b7 66 char data[3];
RobMeades 0:cec745c014b7 67
RobMeades 0:cec745c014b7 68 if (gpI2c != NULL) {
RobMeades 0:cec745c014b7 69 data[0] = registerAddress;
RobMeades 0:cec745c014b7 70 data[1] = 0;
RobMeades 0:cec745c014b7 71 data[2] = 0;
RobMeades 0:cec745c014b7 72
RobMeades 1:ee7cc8d75283 73 // Send a command to read from registerAddress
RobMeades 1:ee7cc8d75283 74 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
RobMeades 0:cec745c014b7 75 (gpI2c->read(gAddress, &(data[1]), 2) == 0)) {
RobMeades 0:cec745c014b7 76 success = true;
RobMeades 0:cec745c014b7 77 if (pBytes) {
RobMeades 0:cec745c014b7 78 *pBytes = (((uint16_t) data[2]) << 8) + data[1];
RobMeades 0:cec745c014b7 79 }
RobMeades 0:cec745c014b7 80 }
RobMeades 0:cec745c014b7 81 }
RobMeades 0:cec745c014b7 82
RobMeades 0:cec745c014b7 83 return success;
RobMeades 0:cec745c014b7 84 }
RobMeades 0:cec745c014b7 85
RobMeades 1:ee7cc8d75283 86 // Compute the checksum over an address plus the block of data.
RobMeades 1:ee7cc8d75283 87 uint8_t BatteryGaugeBq35100::computeChecksum (const char * pData, int32_t length)
RobMeades 1:ee7cc8d75283 88 {
RobMeades 1:ee7cc8d75283 89 uint8_t checkSum = 0;
RobMeades 1:ee7cc8d75283 90 uint8_t x = 0;
RobMeades 1:ee7cc8d75283 91
RobMeades 1:ee7cc8d75283 92 if (pData != NULL) {
RobMeades 1:ee7cc8d75283 93 #ifdef DEBUG_BQ35100_BLOCK_DATA
RobMeades 1:ee7cc8d75283 94 printf ("BatteryGaugeBq35100 (I2C 0x%02x): computing check sum on data block.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 95 printf (" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
RobMeades 1:ee7cc8d75283 96 #endif
RobMeades 1:ee7cc8d75283 97 for (x = 1; x <= length; x++) {
RobMeades 1:ee7cc8d75283 98 checkSum += *pData;
RobMeades 1:ee7cc8d75283 99
RobMeades 1:ee7cc8d75283 100 #ifdef DEBUG_BQ35100_BLOCK_DATA
RobMeades 1:ee7cc8d75283 101 if (x % 16 == 8) {
RobMeades 1:ee7cc8d75283 102 printf ("%02x ", *pData);
RobMeades 1:ee7cc8d75283 103 } else if (x % 16 == 0) {
RobMeades 1:ee7cc8d75283 104 printf ("%02x\n", *pData);
RobMeades 1:ee7cc8d75283 105 } else {
RobMeades 1:ee7cc8d75283 106 printf ("%02x-", *pData);
RobMeades 1:ee7cc8d75283 107 }
RobMeades 1:ee7cc8d75283 108 #endif
RobMeades 1:ee7cc8d75283 109 pData++;
RobMeades 1:ee7cc8d75283 110 }
RobMeades 1:ee7cc8d75283 111
RobMeades 1:ee7cc8d75283 112 checkSum = 0xff - checkSum;
RobMeades 1:ee7cc8d75283 113 }
RobMeades 1:ee7cc8d75283 114
RobMeades 1:ee7cc8d75283 115 #ifdef DEBUG_BQ35100_BLOCK_DATA
RobMeades 1:ee7cc8d75283 116 if (x % 16 != 1) {
RobMeades 1:ee7cc8d75283 117 printf("\n");
RobMeades 1:ee7cc8d75283 118 }
RobMeades 1:ee7cc8d75283 119
RobMeades 1:ee7cc8d75283 120 printf ("BatteryGaugeBq35100 (I2C 0x%02x): check sum is 0x%02x.\n", gAddress >> 1, checkSum);
RobMeades 1:ee7cc8d75283 121 #endif
RobMeades 1:ee7cc8d75283 122
RobMeades 1:ee7cc8d75283 123 return checkSum;
RobMeades 1:ee7cc8d75283 124 }
RobMeades 1:ee7cc8d75283 125
RobMeades 1:ee7cc8d75283 126 // Read data of a given length from a given address.
RobMeades 1:ee7cc8d75283 127 // Note: gpI2c should be locked before this is called.
RobMeades 1:ee7cc8d75283 128 bool BatteryGaugeBq35100::readExtendedData (int32_t address, int32_t length, char * pData)
RobMeades 1:ee7cc8d75283 129 {
RobMeades 1:ee7cc8d75283 130 int32_t lengthRead;
RobMeades 1:ee7cc8d75283 131 bool success = false;
RobMeades 1:ee7cc8d75283 132 SecurityMode securityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 133 char block[32 + 2 + 2]; // 32 bytes of data, 2 bytes of address,
RobMeades 1:ee7cc8d75283 134 // 1 byte of MACDataSum and 1 byte of MACDataLen
RobMeades 1:ee7cc8d75283 135 char data[3];
RobMeades 1:ee7cc8d75283 136
RobMeades 1:ee7cc8d75283 137 // Handle security mode
RobMeades 1:ee7cc8d75283 138 if (setSecurityMode(SECURITY_MODE_UNSEALED)) {
RobMeades 1:ee7cc8d75283 139 if ((gpI2c != NULL) && (length <= 32) && (address >= 0x4000) && (address < 0x4400) && (pData != NULL)) {
RobMeades 1:ee7cc8d75283 140 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 141 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 142 #endif
RobMeades 1:ee7cc8d75283 143 // Enable Block Data Control (0x61)
RobMeades 1:ee7cc8d75283 144 data[0] = 0x61;
RobMeades 1:ee7cc8d75283 145 data[1] = 0;
RobMeades 1:ee7cc8d75283 146
RobMeades 1:ee7cc8d75283 147 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
RobMeades 1:ee7cc8d75283 148 // Write address to ManufacturerAccessControl (0x3e)
RobMeades 1:ee7cc8d75283 149 data[0] = 0x3e;
RobMeades 1:ee7cc8d75283 150 data[1] = (char) address;
RobMeades 1:ee7cc8d75283 151 data[2] = (char) (address >> 8);
RobMeades 1:ee7cc8d75283 152
RobMeades 1:ee7cc8d75283 153 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
RobMeades 1:ee7cc8d75283 154 // Read the address from ManufacturerAccessControl (0x3e then 0x3f),
RobMeades 1:ee7cc8d75283 155 // data from MACData (0x40 to 0x5f), checksum from MACDataSum (0x60)
RobMeades 1:ee7cc8d75283 156 // and length from MACDataLen (0x61)
RobMeades 1:ee7cc8d75283 157 if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
RobMeades 1:ee7cc8d75283 158 (gpI2c->read(gAddress, &(block[0]), sizeof (block)) == 0)) {
RobMeades 1:ee7cc8d75283 159 // Check that the address matches
RobMeades 1:ee7cc8d75283 160 if ((block[0] == (char) address) && (block[1] == (char) (address >> 8))) {
RobMeades 1:ee7cc8d75283 161 // Check that the checksum matches (-2 on MACDataLen as it includes MACDataSum and itself)
RobMeades 1:ee7cc8d75283 162 if (block[34] == computeChecksum (&(block[0]), block[35] - 2)) {
RobMeades 1:ee7cc8d75283 163 // All is good, copy the data to the user
RobMeades 1:ee7cc8d75283 164 lengthRead = block[35] - 4; // -4 rather than -2 to remove the two bytes of address as well
RobMeades 1:ee7cc8d75283 165 if (lengthRead > length) {
RobMeades 1:ee7cc8d75283 166 lengthRead = length;
RobMeades 1:ee7cc8d75283 167 }
RobMeades 1:ee7cc8d75283 168 memcpy(pData, &(block[2]), lengthRead);
RobMeades 1:ee7cc8d75283 169 success = true;
RobMeades 1:ee7cc8d75283 170 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 171 printf("BatteryGaugeBq35100 (I2C 0x%02x): %d byte(s) read successfully.\n", gAddress >> 1, (int) lengthRead);
RobMeades 1:ee7cc8d75283 172 #endif
RobMeades 1:ee7cc8d75283 173 } else {
RobMeades 1:ee7cc8d75283 174 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 175 printf("BatteryGaugeBq35100 (I2C 0x%02x): checksum didn't match (0x%02x expected).\n", gAddress >> 1, block[34]);
RobMeades 1:ee7cc8d75283 176 #endif
RobMeades 1:ee7cc8d75283 177 }
RobMeades 1:ee7cc8d75283 178 } else {
RobMeades 1:ee7cc8d75283 179 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 180 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 181 #endif
RobMeades 1:ee7cc8d75283 182 }
RobMeades 1:ee7cc8d75283 183 } else {
RobMeades 1:ee7cc8d75283 184 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 185 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to read %d bytes from ManufacturerAccessControl.\n", gAddress >> 1, sizeof (block));
RobMeades 1:ee7cc8d75283 186 #endif
RobMeades 1:ee7cc8d75283 187 }
RobMeades 1:ee7cc8d75283 188 } else {
RobMeades 1:ee7cc8d75283 189 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 190 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write %d bytes to ManufacturerAccessControl.\r", gAddress >> 1, 3);
RobMeades 1:ee7cc8d75283 191 #endif
RobMeades 1:ee7cc8d75283 192 }
RobMeades 1:ee7cc8d75283 193 } else {
RobMeades 1:ee7cc8d75283 194 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 195 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set Block Data Control.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 196 #endif
RobMeades 1:ee7cc8d75283 197 }
RobMeades 1:ee7cc8d75283 198 } else {
RobMeades 1:ee7cc8d75283 199 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 200 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set the security mode of the chip.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 201 #endif
RobMeades 1:ee7cc8d75283 202 }
RobMeades 1:ee7cc8d75283 203 }
RobMeades 1:ee7cc8d75283 204
RobMeades 1:ee7cc8d75283 205 // Put the security mode back to what it was
RobMeades 1:ee7cc8d75283 206 if (!setSecurityMode(securityMode)) {
RobMeades 1:ee7cc8d75283 207 success = false;
RobMeades 1:ee7cc8d75283 208 }
RobMeades 1:ee7cc8d75283 209
RobMeades 1:ee7cc8d75283 210 return success;
RobMeades 1:ee7cc8d75283 211 }
RobMeades 1:ee7cc8d75283 212
RobMeades 1:ee7cc8d75283 213 // Write data of a given length to a given address.
RobMeades 1:ee7cc8d75283 214 // Note: gpI2c should be locked before this is called.
RobMeades 1:ee7cc8d75283 215 bool BatteryGaugeBq35100::writeExtendedData(int32_t address, int32_t length, const char * pData)
RobMeades 1:ee7cc8d75283 216 {
RobMeades 1:ee7cc8d75283 217 bool success = false;
RobMeades 1:ee7cc8d75283 218 SecurityMode securityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 219 char data[3 + 32];
RobMeades 1:ee7cc8d75283 220
RobMeades 1:ee7cc8d75283 221 if ((gpI2c != NULL) && (length <= 32) && (address >= 0x4000) && (address < 0x4400) && (pData != NULL)) {
RobMeades 1:ee7cc8d75283 222 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 223 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 224 #endif
RobMeades 1:ee7cc8d75283 225 // Handle security mode
RobMeades 1:ee7cc8d75283 226 if (setSecurityMode(SECURITY_MODE_UNSEALED)) {
RobMeades 1:ee7cc8d75283 227 // Enable Block Data Control (0x61)
RobMeades 1:ee7cc8d75283 228 data[0] = 0x61;
RobMeades 1:ee7cc8d75283 229 data[1] = 0;
RobMeades 1:ee7cc8d75283 230
RobMeades 1:ee7cc8d75283 231 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
RobMeades 1:ee7cc8d75283 232 // Start write at ManufacturerAccessControl (0x3e)
RobMeades 1:ee7cc8d75283 233 data[0] = 0x3e;
RobMeades 1:ee7cc8d75283 234 // Next two bytes are the address we will write to
RobMeades 1:ee7cc8d75283 235 data[1] = (char) address;
RobMeades 1:ee7cc8d75283 236 data[2] = (char) (address >> 8);
RobMeades 1:ee7cc8d75283 237 // Remaining bytes are the data bytes we wish to write
RobMeades 1:ee7cc8d75283 238 memcpy (&(data[3]), pData, length);
RobMeades 1:ee7cc8d75283 239
RobMeades 1:ee7cc8d75283 240 if (gpI2c->write(gAddress, &(data[0]), 3 + length) == 0) {
RobMeades 1:ee7cc8d75283 241 // Compute the checksum and write it to MACDataSum (0x60)
RobMeades 1:ee7cc8d75283 242 data[1] = computeChecksum (&(data[1]), length + 2);
RobMeades 1:ee7cc8d75283 243 data[0] = 0x60;
RobMeades 1:ee7cc8d75283 244
RobMeades 1:ee7cc8d75283 245 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
RobMeades 1:ee7cc8d75283 246 // Write 4 + length to MACDataLen (0x61)
RobMeades 1:ee7cc8d75283 247 data[1] = length + 4;
RobMeades 1:ee7cc8d75283 248 data[0] = 0x61;
RobMeades 1:ee7cc8d75283 249
RobMeades 1:ee7cc8d75283 250 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
RobMeades 1:ee7cc8d75283 251 // TODO check for successful write
RobMeades 1:ee7cc8d75283 252 success = true;
RobMeades 1:ee7cc8d75283 253 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 254 printf("BatteryGaugeBq35100 (I2C 0x%02x): write successful.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 255 #endif
RobMeades 1:ee7cc8d75283 256 } else {
RobMeades 1:ee7cc8d75283 257 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 258 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to read write to MACDataLen.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 259 #endif
RobMeades 1:ee7cc8d75283 260 }
RobMeades 1:ee7cc8d75283 261 } else {
RobMeades 1:ee7cc8d75283 262 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 263 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write to MACDataSum.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 264 #endif
RobMeades 1:ee7cc8d75283 265 }
RobMeades 1:ee7cc8d75283 266 } else {
RobMeades 1:ee7cc8d75283 267 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 268 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write %d bytes to ManufacturerAccessControl.\r", gAddress >> 1, (int) length + 2);
RobMeades 1:ee7cc8d75283 269 #endif
RobMeades 1:ee7cc8d75283 270 }
RobMeades 1:ee7cc8d75283 271 } else {
RobMeades 1:ee7cc8d75283 272 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 273 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set Block Data Control.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 274 #endif
RobMeades 1:ee7cc8d75283 275 }
RobMeades 1:ee7cc8d75283 276 } else {
RobMeades 1:ee7cc8d75283 277 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 278 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set the security mode of the chip.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 279 #endif
RobMeades 1:ee7cc8d75283 280 }
RobMeades 1:ee7cc8d75283 281 }
RobMeades 1:ee7cc8d75283 282
RobMeades 1:ee7cc8d75283 283 // Put the security mode back to what it was
RobMeades 1:ee7cc8d75283 284 if (!setSecurityMode(securityMode)) {
RobMeades 1:ee7cc8d75283 285 success = false;
RobMeades 1:ee7cc8d75283 286 }
RobMeades 1:ee7cc8d75283 287
RobMeades 1:ee7cc8d75283 288 return success;
RobMeades 1:ee7cc8d75283 289 }
RobMeades 1:ee7cc8d75283 290
RobMeades 1:ee7cc8d75283 291 // Get the security mode of the chip.
RobMeades 1:ee7cc8d75283 292 // Note: gpI2c should be locked before this is called.
RobMeades 1:ee7cc8d75283 293 BatteryGaugeBq35100::SecurityMode BatteryGaugeBq35100::getSecurityMode(void)
RobMeades 1:ee7cc8d75283 294 {
RobMeades 1:ee7cc8d75283 295 SecurityMode securityMode = SECURITY_MODE_UNKNOWN;
RobMeades 1:ee7cc8d75283 296 char data[1];
RobMeades 1:ee7cc8d75283 297 uint16_t controlStatus;
RobMeades 1:ee7cc8d75283 298
RobMeades 1:ee7cc8d75283 299 data[0] = 0; // Set address to first register for Control
RobMeades 1:ee7cc8d75283 300
RobMeades 1:ee7cc8d75283 301 // Send a control command to read the control status register
RobMeades 1:ee7cc8d75283 302 if (gpI2c->write(gAddress, &(data[0]), 1) == 0) {
RobMeades 1:ee7cc8d75283 303 if (getTwoBytes(0, &controlStatus)) {
RobMeades 1:ee7cc8d75283 304 // Bits 13 and 14 of the high byte represent the security status,
RobMeades 1:ee7cc8d75283 305 // 01 = full access
RobMeades 1:ee7cc8d75283 306 // 10 = unsealed access
RobMeades 1:ee7cc8d75283 307 // 11 = sealed access
RobMeades 1:ee7cc8d75283 308 securityMode = (SecurityMode) ((controlStatus >> 13) & 0x03);
RobMeades 1:ee7cc8d75283 309 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 310 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode is 0x%02x (control status 0x%04x).\r\n", gAddress >> 1, securityMode, controlStatus);
RobMeades 1:ee7cc8d75283 311 #endif
RobMeades 1:ee7cc8d75283 312 }
RobMeades 1:ee7cc8d75283 313 }
RobMeades 1:ee7cc8d75283 314
RobMeades 1:ee7cc8d75283 315 return securityMode;
RobMeades 1:ee7cc8d75283 316 }
RobMeades 1:ee7cc8d75283 317
RobMeades 1:ee7cc8d75283 318 // Set the security mode of the chip.
RobMeades 1:ee7cc8d75283 319 // Note: gpI2c should be locked before this is called.
RobMeades 1:ee7cc8d75283 320 bool BatteryGaugeBq35100::setSecurityMode(SecurityMode securityMode)
RobMeades 1:ee7cc8d75283 321 {
RobMeades 1:ee7cc8d75283 322 bool success = false;
RobMeades 1:ee7cc8d75283 323 char data[3];
RobMeades 1:ee7cc8d75283 324 SecurityMode currentSecurityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 325
RobMeades 1:ee7cc8d75283 326 if (securityMode != SECURITY_MODE_UNKNOWN) {
RobMeades 1:ee7cc8d75283 327 if (securityMode != currentSecurityMode) {
RobMeades 1:ee7cc8d75283 328 // For reasons that aren't clear, the BQ35100 sometimes refuses
RobMeades 1:ee7cc8d75283 329 // to change security mode if a previous security mode change
RobMeades 1:ee7cc8d75283 330 // happend only a few seconds ago, hence the retry here
RobMeades 1:ee7cc8d75283 331 for (int32_t x = 0; (x < SET_SECURITY_MODE_RETRY_SECONDS) && !success; x++) {
RobMeades 1:ee7cc8d75283 332 data[0] = 0; // Set address to first register for Control)
RobMeades 1:ee7cc8d75283 333 switch (securityMode) {
RobMeades 1:ee7cc8d75283 334 case SECURITY_MODE_SEALED:
RobMeades 1:ee7cc8d75283 335 // Just seal the chip
RobMeades 1:ee7cc8d75283 336 data[1] = 0x20; // First byte of SEALED sub-command (0x20)
RobMeades 1:ee7cc8d75283 337 data[2] = 0x00; // Second byte of SEALED sub-command (0x00) (register address will auto-increment)
RobMeades 1:ee7cc8d75283 338 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 339 break;
RobMeades 1:ee7cc8d75283 340 case SECURITY_MODE_FULL_ACCESS:
RobMeades 1:ee7cc8d75283 341 // Send the full access code with endianness conversion
RobMeades 1:ee7cc8d75283 342 // in TWO writes
RobMeades 1:ee7cc8d75283 343 data[2] = (char) (gFullAccessCodes >> 24);
RobMeades 1:ee7cc8d75283 344 data[1] = (char) (gFullAccessCodes >> 16);
RobMeades 1:ee7cc8d75283 345 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 346 data[2] = (char) (gFullAccessCodes >> 8);
RobMeades 1:ee7cc8d75283 347 data[1] = (char) gFullAccessCodes;
RobMeades 1:ee7cc8d75283 348 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 349 break;
RobMeades 1:ee7cc8d75283 350 case SECURITY_MODE_UNSEALED:
RobMeades 1:ee7cc8d75283 351 data[2] = (char) (gSealCodes >> 24);
RobMeades 1:ee7cc8d75283 352 data[1] = (char) (gSealCodes >> 16);
RobMeades 1:ee7cc8d75283 353 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 354 data[2] = (char) (gSealCodes >> 8);
RobMeades 1:ee7cc8d75283 355 data[1] = (char) gSealCodes;
RobMeades 1:ee7cc8d75283 356 gpI2c->write(gAddress, &(data[0]), 3);
RobMeades 1:ee7cc8d75283 357 break;
RobMeades 1:ee7cc8d75283 358 case SECURITY_MODE_UNKNOWN:
RobMeades 1:ee7cc8d75283 359 default:
RobMeades 1:ee7cc8d75283 360 MBED_ASSERT(false);
RobMeades 1:ee7cc8d75283 361 break;
RobMeades 1:ee7cc8d75283 362 }
RobMeades 1:ee7cc8d75283 363
RobMeades 1:ee7cc8d75283 364 currentSecurityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 365 if (currentSecurityMode == securityMode) {
RobMeades 1:ee7cc8d75283 366 success = true;
RobMeades 1:ee7cc8d75283 367 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 368 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode is now 0x%02x.\n", gAddress >> 1, currentSecurityMode);
RobMeades 1:ee7cc8d75283 369 #endif
RobMeades 1:ee7cc8d75283 370 } else {
RobMeades 1:ee7cc8d75283 371 wait_ms(1000);
RobMeades 1:ee7cc8d75283 372 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 373 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 374 #endif
RobMeades 1:ee7cc8d75283 375 }
RobMeades 1:ee7cc8d75283 376 }
RobMeades 1:ee7cc8d75283 377 } else {
RobMeades 1:ee7cc8d75283 378 success = true;
RobMeades 1:ee7cc8d75283 379 }
RobMeades 1:ee7cc8d75283 380 }
RobMeades 1:ee7cc8d75283 381
RobMeades 1:ee7cc8d75283 382 return success;
RobMeades 1:ee7cc8d75283 383 }
RobMeades 1:ee7cc8d75283 384
RobMeades 1:ee7cc8d75283 385 // Make sure that the device is awake and has taken a reading.
RobMeades 1:ee7cc8d75283 386 // Note: the function does its own locking of gpI2C so that it isn't
RobMeades 1:ee7cc8d75283 387 // locked for the entire time we wait for ADC readings to complete.
RobMeades 1:ee7cc8d75283 388 bool BatteryGaugeBq35100::makeAdcReading(void)
RobMeades 1:ee7cc8d75283 389 {
RobMeades 1:ee7cc8d75283 390 bool success = false;
RobMeades 1:ee7cc8d75283 391 uint16_t controlStatus;
RobMeades 1:ee7cc8d75283 392 char data[1];
RobMeades 1:ee7cc8d75283 393
RobMeades 1:ee7cc8d75283 394 // Wait for INITCOMP to be set
RobMeades 1:ee7cc8d75283 395 data[0] = 0; // Set address to first register for Control
RobMeades 1:ee7cc8d75283 396
RobMeades 1:ee7cc8d75283 397 gpI2c->lock();
RobMeades 1:ee7cc8d75283 398 // Raise the pin
RobMeades 1:ee7cc8d75283 399 *pGaugeEnable = 1;
RobMeades 1:ee7cc8d75283 400 wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS);
RobMeades 1:ee7cc8d75283 401 for (int x = 0; !success && (x < INIT_LOOP_COUNT); x++) {
RobMeades 1:ee7cc8d75283 402 if (gpI2c->write(gAddress, &(data[0]), 1) == 0) {
RobMeades 1:ee7cc8d75283 403 if (getTwoBytes(0, &controlStatus)) {
RobMeades 1:ee7cc8d75283 404 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 405 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x as CONTROL_STATUS.\n", gAddress >> 1, controlStatus);
RobMeades 1:ee7cc8d75283 406 #endif
RobMeades 1:ee7cc8d75283 407 // Bit 7 is INITCOMP
RobMeades 1:ee7cc8d75283 408 if (((controlStatus >> 7) & 0x01) == 0x01) {
RobMeades 1:ee7cc8d75283 409 success = true;
RobMeades 1:ee7cc8d75283 410 }
RobMeades 1:ee7cc8d75283 411 }
RobMeades 1:ee7cc8d75283 412 wait_ms (INIT_LOOP_WAIT_MS);
RobMeades 1:ee7cc8d75283 413 }
RobMeades 1:ee7cc8d75283 414 }
RobMeades 1:ee7cc8d75283 415 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 416
RobMeades 1:ee7cc8d75283 417 return success;
RobMeades 1:ee7cc8d75283 418 }
RobMeades 1:ee7cc8d75283 419
RobMeades 0:cec745c014b7 420 //----------------------------------------------------------------
RobMeades 0:cec745c014b7 421 // PUBLIC FUNCTIONS
RobMeades 0:cec745c014b7 422 // ----------------------------------------------------------------
RobMeades 0:cec745c014b7 423
RobMeades 0:cec745c014b7 424 // Constructor.
RobMeades 0:cec745c014b7 425 BatteryGaugeBq35100::BatteryGaugeBq35100(void)
RobMeades 0:cec745c014b7 426 {
RobMeades 0:cec745c014b7 427 gpI2c = NULL;
RobMeades 1:ee7cc8d75283 428 pGaugeEnable = NULL;
RobMeades 0:cec745c014b7 429 gReady = false;
RobMeades 1:ee7cc8d75283 430 gSealCodes = 0;
RobMeades 1:ee7cc8d75283 431 gFullAccessCodes = 0;
RobMeades 0:cec745c014b7 432 gGaugeOn = false;
RobMeades 0:cec745c014b7 433 }
RobMeades 0:cec745c014b7 434
RobMeades 0:cec745c014b7 435 // Destructor.
RobMeades 0:cec745c014b7 436 BatteryGaugeBq35100::~BatteryGaugeBq35100(void)
RobMeades 0:cec745c014b7 437 {
RobMeades 1:ee7cc8d75283 438 if (pGaugeEnable) {
RobMeades 1:ee7cc8d75283 439 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 440 delete pGaugeEnable;
RobMeades 1:ee7cc8d75283 441 }
RobMeades 0:cec745c014b7 442 }
RobMeades 0:cec745c014b7 443
RobMeades 0:cec745c014b7 444 // Initialise ourselves.
RobMeades 1:ee7cc8d75283 445 bool BatteryGaugeBq35100::init(I2C * pI2c, PinName gaugeEnable, uint8_t address, uint32_t sealCodes)
RobMeades 0:cec745c014b7 446 {
RobMeades 0:cec745c014b7 447 uint16_t answer;
RobMeades 0:cec745c014b7 448 char data[4];
RobMeades 0:cec745c014b7 449
RobMeades 0:cec745c014b7 450 gpI2c = pI2c;
RobMeades 0:cec745c014b7 451 gAddress = address << 1;
RobMeades 1:ee7cc8d75283 452 gSealCodes = sealCodes;
RobMeades 1:ee7cc8d75283 453
RobMeades 1:ee7cc8d75283 454 pGaugeEnable = new DigitalOut(gaugeEnable, 1);
RobMeades 1:ee7cc8d75283 455 wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS);
RobMeades 0:cec745c014b7 456
RobMeades 0:cec745c014b7 457 if (gpI2c != NULL) {
RobMeades 0:cec745c014b7 458 gpI2c->lock();
RobMeades 1:ee7cc8d75283 459 gpI2c->frequency(I2C_CLOCK_FREQUENCY);
RobMeades 0:cec745c014b7 460
RobMeades 1:ee7cc8d75283 461 // Send a control command to read the device type
RobMeades 1:ee7cc8d75283 462 data[0] = 0x3e; // Set address to ManufacturerAccessControl
RobMeades 1:ee7cc8d75283 463 data[1] = 0x03; // First byte of HW_VERSION sub-command (0x03)
RobMeades 1:ee7cc8d75283 464 data[2] = 0x00; // Second byte of HW_VERSION sub-command (0x00) (register address will auto-increment)
RobMeades 0:cec745c014b7 465
RobMeades 1:ee7cc8d75283 466 if ((gpI2c->write(gAddress, &(data[0]), 3) == 0) &&
RobMeades 1:ee7cc8d75283 467 getTwoBytes(0x40, &answer)) { // Read from MACData address
RobMeades 1:ee7cc8d75283 468 if (answer == 0x00a8) {
RobMeades 1:ee7cc8d75283 469 // Read the full access codes, in case we need them
RobMeades 1:ee7cc8d75283 470 if (readExtendedData(0x41d0, sizeof (data), &(data[0]))) {
RobMeades 1:ee7cc8d75283 471 // The four bytes are the full access codes
RobMeades 1:ee7cc8d75283 472 gFullAccessCodes = ((uint32_t) data[0] << 24) + ((uint32_t) data[1] << 16) + ((uint32_t) data[2] << 8) + data[3];
RobMeades 0:cec745c014b7 473 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 474 printf("BatteryGaugeBq35100 (I2C 0x%02x): full access code is 0x%08x.\n", gAddress >> 1,
RobMeades 1:ee7cc8d75283 475 (unsigned int) gFullAccessCodes);
RobMeades 0:cec745c014b7 476 #endif
RobMeades 1:ee7cc8d75283 477 gReady = true;
RobMeades 1:ee7cc8d75283 478 }
RobMeades 0:cec745c014b7 479 }
RobMeades 1:ee7cc8d75283 480
RobMeades 1:ee7cc8d75283 481 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 482 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x as HW_VERSION, expected 0x00a8.\n", gAddress >> 1, answer);
RobMeades 1:ee7cc8d75283 483 #endif
RobMeades 0:cec745c014b7 484 }
RobMeades 1:ee7cc8d75283 485
RobMeades 1:ee7cc8d75283 486 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 487 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 488 }
RobMeades 1:ee7cc8d75283 489
RobMeades 0:cec745c014b7 490 gpI2c->unlock();
RobMeades 0:cec745c014b7 491 }
RobMeades 0:cec745c014b7 492
RobMeades 0:cec745c014b7 493 #ifdef DEBUG_BQ35100
RobMeades 0:cec745c014b7 494 if (gReady) {
RobMeades 1:ee7cc8d75283 495 printf("BatteryGaugeBq35100 (I2C 0x%02x): handler initialised.\n", gAddress >> 1);
RobMeades 0:cec745c014b7 496 } else {
RobMeades 1:ee7cc8d75283 497 printf("BatteryGaugeBq35100 (I2C 0x%02x): init NOT successful.\n", gAddress >> 1);
RobMeades 0:cec745c014b7 498 }
RobMeades 0:cec745c014b7 499 #endif
RobMeades 0:cec745c014b7 500
RobMeades 0:cec745c014b7 501 return gReady;
RobMeades 0:cec745c014b7 502 }
RobMeades 0:cec745c014b7 503
RobMeades 1:ee7cc8d75283 504 // Switch on the battery capacity monitor.
RobMeades 1:ee7cc8d75283 505 bool BatteryGaugeBq35100::enableGauge(void)
RobMeades 1:ee7cc8d75283 506 {
RobMeades 1:ee7cc8d75283 507 bool success = false;
RobMeades 1:ee7cc8d75283 508
RobMeades 1:ee7cc8d75283 509 if (gReady) {
RobMeades 1:ee7cc8d75283 510 *pGaugeEnable = 1;
RobMeades 1:ee7cc8d75283 511 wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS);
RobMeades 1:ee7cc8d75283 512 success = true;
RobMeades 1:ee7cc8d75283 513 }
RobMeades 1:ee7cc8d75283 514
RobMeades 1:ee7cc8d75283 515 return success;
RobMeades 1:ee7cc8d75283 516 }
RobMeades 1:ee7cc8d75283 517
RobMeades 1:ee7cc8d75283 518 // Switch off the battery capacity monitor.
RobMeades 1:ee7cc8d75283 519 bool BatteryGaugeBq35100::disableGauge(void)
RobMeades 1:ee7cc8d75283 520 {
RobMeades 1:ee7cc8d75283 521 bool success = false;
RobMeades 1:ee7cc8d75283 522
RobMeades 1:ee7cc8d75283 523 if (gReady) {
RobMeades 1:ee7cc8d75283 524 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 525 success = true;
RobMeades 1:ee7cc8d75283 526 }
RobMeades 1:ee7cc8d75283 527
RobMeades 1:ee7cc8d75283 528 return success;
RobMeades 1:ee7cc8d75283 529 }
RobMeades 1:ee7cc8d75283 530
RobMeades 1:ee7cc8d75283 531 // Determine whether battery gauging is enabled.
RobMeades 1:ee7cc8d75283 532 bool BatteryGaugeBq35100::isGaugeEnabled(void)
RobMeades 1:ee7cc8d75283 533 {
RobMeades 1:ee7cc8d75283 534 bool isEnabled = false;
RobMeades 1:ee7cc8d75283 535
RobMeades 1:ee7cc8d75283 536 if (gReady) {
RobMeades 1:ee7cc8d75283 537 isEnabled = true;
RobMeades 1:ee7cc8d75283 538 }
RobMeades 1:ee7cc8d75283 539
RobMeades 1:ee7cc8d75283 540 return isEnabled;
RobMeades 1:ee7cc8d75283 541 }
RobMeades 1:ee7cc8d75283 542
RobMeades 1:ee7cc8d75283 543 // Set the designed capacity of the cell.
RobMeades 1:ee7cc8d75283 544 bool BatteryGaugeBq35100::setDesignCapacity(uint32_t capacityMAh)
RobMeades 1:ee7cc8d75283 545 {
RobMeades 1:ee7cc8d75283 546 bool success = false;
RobMeades 1:ee7cc8d75283 547 char data[2];
RobMeades 1:ee7cc8d75283 548
RobMeades 1:ee7cc8d75283 549 if (gReady) {
RobMeades 1:ee7cc8d75283 550 gpI2c->lock();
RobMeades 1:ee7cc8d75283 551
RobMeades 1:ee7cc8d75283 552 data[0] = capacityMAh >> 8; // Upper byte of design capacity
RobMeades 1:ee7cc8d75283 553 data[1] = capacityMAh; // Lower byte of design capacity
RobMeades 1:ee7cc8d75283 554
RobMeades 1:ee7cc8d75283 555 // Write to the "Cell Design Capacity mAh" address in data flash
RobMeades 1:ee7cc8d75283 556 if (writeExtendedData(0x41fe, sizeof(data), &(data[0]))) {
RobMeades 1:ee7cc8d75283 557 success = true;
RobMeades 1:ee7cc8d75283 558
RobMeades 1:ee7cc8d75283 559 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 560 printf("BatteryGaugeBq35100 (I2C 0x%02x): designed cell capacity set to %d mAh.\n", gAddress >> 1,
RobMeades 1:ee7cc8d75283 561 (unsigned int) capacityMAh);
RobMeades 1:ee7cc8d75283 562 #endif
RobMeades 1:ee7cc8d75283 563 }
RobMeades 1:ee7cc8d75283 564
RobMeades 1:ee7cc8d75283 565 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 566 }
RobMeades 1:ee7cc8d75283 567
RobMeades 1:ee7cc8d75283 568 return success;
RobMeades 1:ee7cc8d75283 569 }
RobMeades 1:ee7cc8d75283 570
RobMeades 1:ee7cc8d75283 571 // Get the designed capacity of the cell.
RobMeades 1:ee7cc8d75283 572 bool BatteryGaugeBq35100::getDesignCapacity(uint32_t *pCapacityMAh)
RobMeades 1:ee7cc8d75283 573 {
RobMeades 1:ee7cc8d75283 574 bool success = false;
RobMeades 1:ee7cc8d75283 575 uint16_t data;
RobMeades 1:ee7cc8d75283 576
RobMeades 1:ee7cc8d75283 577 if (gReady) {
RobMeades 1:ee7cc8d75283 578 gpI2c->lock();
RobMeades 1:ee7cc8d75283 579
RobMeades 1:ee7cc8d75283 580 // Read from the DesignCapacity address
RobMeades 1:ee7cc8d75283 581 if (getTwoBytes (0x3c, &data)) {
RobMeades 1:ee7cc8d75283 582 success = true;
RobMeades 1:ee7cc8d75283 583
RobMeades 1:ee7cc8d75283 584 // The answer is in mAh
RobMeades 1:ee7cc8d75283 585 if (pCapacityMAh) {
RobMeades 1:ee7cc8d75283 586 *pCapacityMAh = data;
RobMeades 1:ee7cc8d75283 587 }
RobMeades 1:ee7cc8d75283 588
RobMeades 1:ee7cc8d75283 589 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 590 printf("BatteryGaugeBq35100 (I2C 0x%02x): designed cell capacity is %d mAh.\n", gAddress >> 1, data);
RobMeades 1:ee7cc8d75283 591 #endif
RobMeades 1:ee7cc8d75283 592 }
RobMeades 1:ee7cc8d75283 593
RobMeades 1:ee7cc8d75283 594 }
RobMeades 1:ee7cc8d75283 595
RobMeades 1:ee7cc8d75283 596 return success;
RobMeades 1:ee7cc8d75283 597 }
RobMeades 1:ee7cc8d75283 598
RobMeades 1:ee7cc8d75283 599 // Get the temperature of the chip.
RobMeades 1:ee7cc8d75283 600 bool BatteryGaugeBq35100::getTemperature(int32_t *pTemperatureC)
RobMeades 1:ee7cc8d75283 601 {
RobMeades 1:ee7cc8d75283 602 bool success = false;
RobMeades 1:ee7cc8d75283 603 int32_t temperatureC = 0;
RobMeades 1:ee7cc8d75283 604 uint16_t data;
RobMeades 1:ee7cc8d75283 605
RobMeades 1:ee7cc8d75283 606 if (gReady && (gGaugeOn || makeAdcReading())) {
RobMeades 1:ee7cc8d75283 607 gpI2c->lock();
RobMeades 1:ee7cc8d75283 608 // Read from the temperature register address
RobMeades 1:ee7cc8d75283 609 if (getTwoBytes (0x06, &data)) {
RobMeades 1:ee7cc8d75283 610 success = true;
RobMeades 1:ee7cc8d75283 611
RobMeades 1:ee7cc8d75283 612 // The answer is in units of 0.1 K, so convert to C
RobMeades 1:ee7cc8d75283 613 temperatureC = ((int32_t) data / 10) - 273;
RobMeades 1:ee7cc8d75283 614
RobMeades 1:ee7cc8d75283 615 if (pTemperatureC) {
RobMeades 1:ee7cc8d75283 616 *pTemperatureC = temperatureC;
RobMeades 1:ee7cc8d75283 617 }
RobMeades 1:ee7cc8d75283 618
RobMeades 1:ee7cc8d75283 619 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 620 printf("BatteryGaugeBq35100 (I2C 0x%02x): chip temperature %.1f K, so %d C.\n", gAddress >> 1, ((float) data) / 10, (int) temperatureC);
RobMeades 1:ee7cc8d75283 621 #endif
RobMeades 1:ee7cc8d75283 622 }
RobMeades 1:ee7cc8d75283 623
RobMeades 1:ee7cc8d75283 624 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 625 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 626 }
RobMeades 1:ee7cc8d75283 627
RobMeades 1:ee7cc8d75283 628 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 629 }
RobMeades 1:ee7cc8d75283 630
RobMeades 1:ee7cc8d75283 631 return success;
RobMeades 1:ee7cc8d75283 632 }
RobMeades 1:ee7cc8d75283 633
RobMeades 1:ee7cc8d75283 634 // Get the voltage of the battery.
RobMeades 1:ee7cc8d75283 635 bool BatteryGaugeBq35100::getVoltage(int32_t *pVoltageMV)
RobMeades 1:ee7cc8d75283 636 {
RobMeades 1:ee7cc8d75283 637 bool success = false;
RobMeades 1:ee7cc8d75283 638 uint16_t data = 0;
RobMeades 1:ee7cc8d75283 639
RobMeades 1:ee7cc8d75283 640 if (gReady && (gGaugeOn || makeAdcReading())) {
RobMeades 1:ee7cc8d75283 641 gpI2c->lock();
RobMeades 1:ee7cc8d75283 642 // Read from the voltage register address
RobMeades 1:ee7cc8d75283 643 if (getTwoBytes (0x08, &data)) {
RobMeades 1:ee7cc8d75283 644 success = true;
RobMeades 1:ee7cc8d75283 645
RobMeades 1:ee7cc8d75283 646 // The answer is in mV
RobMeades 1:ee7cc8d75283 647 if (pVoltageMV) {
RobMeades 1:ee7cc8d75283 648 *pVoltageMV = (int32_t) data;
RobMeades 1:ee7cc8d75283 649 }
RobMeades 1:ee7cc8d75283 650
RobMeades 1:ee7cc8d75283 651 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 652 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery voltage %.3f V.\n", gAddress >> 1, ((float) data) / 1000);
RobMeades 1:ee7cc8d75283 653 #endif
RobMeades 1:ee7cc8d75283 654 }
RobMeades 1:ee7cc8d75283 655
RobMeades 1:ee7cc8d75283 656 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 657 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 658 }
RobMeades 1:ee7cc8d75283 659
RobMeades 1:ee7cc8d75283 660 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 661 }
RobMeades 1:ee7cc8d75283 662
RobMeades 1:ee7cc8d75283 663 return success;
RobMeades 1:ee7cc8d75283 664 }
RobMeades 1:ee7cc8d75283 665
RobMeades 1:ee7cc8d75283 666 // Get the current flowing from the battery.
RobMeades 1:ee7cc8d75283 667 bool BatteryGaugeBq35100::getCurrent(int32_t *pCurrentMA)
RobMeades 1:ee7cc8d75283 668 {
RobMeades 1:ee7cc8d75283 669 bool success = false;
RobMeades 1:ee7cc8d75283 670 int32_t currentMA = 0;
RobMeades 1:ee7cc8d75283 671 uint16_t data;
RobMeades 1:ee7cc8d75283 672
RobMeades 1:ee7cc8d75283 673 if (gReady && (gGaugeOn || makeAdcReading())) {
RobMeades 1:ee7cc8d75283 674 gpI2c->lock();
RobMeades 1:ee7cc8d75283 675 // Read from the average current register address
RobMeades 1:ee7cc8d75283 676 if (getTwoBytes (0x0c, &data)) {
RobMeades 1:ee7cc8d75283 677 success = true;
RobMeades 1:ee7cc8d75283 678
RobMeades 1:ee7cc8d75283 679 if (pCurrentMA) {
RobMeades 1:ee7cc8d75283 680 *pCurrentMA = currentMA;
RobMeades 1:ee7cc8d75283 681 }
RobMeades 1:ee7cc8d75283 682
RobMeades 1:ee7cc8d75283 683 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 684 printf("BatteryGaugeBq35100 (I2C 0x%02x): current %d mA.\n", gAddress >> 1, (int) currentMA);
RobMeades 1:ee7cc8d75283 685 #endif
RobMeades 1:ee7cc8d75283 686 }
RobMeades 1:ee7cc8d75283 687
RobMeades 1:ee7cc8d75283 688 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 689 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 690 }
RobMeades 1:ee7cc8d75283 691
RobMeades 1:ee7cc8d75283 692 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 693 }
RobMeades 1:ee7cc8d75283 694
RobMeades 1:ee7cc8d75283 695 return success;
RobMeades 1:ee7cc8d75283 696 }
RobMeades 1:ee7cc8d75283 697
RobMeades 1:ee7cc8d75283 698 // Get the battery capacity used.
RobMeades 1:ee7cc8d75283 699 bool BatteryGaugeBq35100::getUsedCapacity(uint32_t *pCapacityUAh)
RobMeades 1:ee7cc8d75283 700 {
RobMeades 1:ee7cc8d75283 701 bool success = false;
RobMeades 1:ee7cc8d75283 702 char bytes[5];
RobMeades 1:ee7cc8d75283 703 uint32_t data;
RobMeades 1:ee7cc8d75283 704
RobMeades 1:ee7cc8d75283 705 if (gReady && (gGaugeOn || makeAdcReading())) {
RobMeades 1:ee7cc8d75283 706 gpI2c->lock();
RobMeades 1:ee7cc8d75283 707 // Read four bytes from the AccummulatedCapacity register address
RobMeades 1:ee7cc8d75283 708
RobMeades 1:ee7cc8d75283 709 // Send a command to read from registerAddress
RobMeades 1:ee7cc8d75283 710 bytes[0] = 0x02;
RobMeades 1:ee7cc8d75283 711 bytes[1] = 0;
RobMeades 1:ee7cc8d75283 712 bytes[2] = 0;
RobMeades 1:ee7cc8d75283 713 bytes[3] = 0;
RobMeades 1:ee7cc8d75283 714 bytes[4] = 0;
RobMeades 1:ee7cc8d75283 715
RobMeades 1:ee7cc8d75283 716 if ((gpI2c->write(gAddress, &(bytes[0]), 1) == 0) &&
RobMeades 1:ee7cc8d75283 717 (gpI2c->read(gAddress, &(bytes[1]), 4) == 0)) {
RobMeades 1:ee7cc8d75283 718 success = true;
RobMeades 1:ee7cc8d75283 719 data = (((uint32_t) bytes[4]) << 24) + (((uint32_t) bytes[3]) << 16) + (((uint32_t) bytes[2]) << 8) + bytes[1];
RobMeades 1:ee7cc8d75283 720
RobMeades 1:ee7cc8d75283 721 // The answer is in uAh
RobMeades 1:ee7cc8d75283 722 if (pCapacityUAh) {
RobMeades 1:ee7cc8d75283 723 *pCapacityUAh = data;
RobMeades 1:ee7cc8d75283 724 }
RobMeades 1:ee7cc8d75283 725
RobMeades 1:ee7cc8d75283 726 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 727 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity used %u uAh.\n", gAddress >> 1, (unsigned int) data);
RobMeades 1:ee7cc8d75283 728 #endif
RobMeades 1:ee7cc8d75283 729 }
RobMeades 1:ee7cc8d75283 730
RobMeades 1:ee7cc8d75283 731 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 732 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 733 }
RobMeades 1:ee7cc8d75283 734
RobMeades 1:ee7cc8d75283 735 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 736 }
RobMeades 1:ee7cc8d75283 737
RobMeades 1:ee7cc8d75283 738 return success;
RobMeades 1:ee7cc8d75283 739 }
RobMeades 1:ee7cc8d75283 740
RobMeades 1:ee7cc8d75283 741 // Get the battery capacity remaining.
RobMeades 1:ee7cc8d75283 742 bool BatteryGaugeBq35100::getRemainingCapacity(uint32_t *pCapacityUAh)
RobMeades 1:ee7cc8d75283 743 {
RobMeades 1:ee7cc8d75283 744 bool success = false;
RobMeades 1:ee7cc8d75283 745 uint32_t designCapacityUAh;
RobMeades 1:ee7cc8d75283 746 uint32_t usedCapacityUAh;
RobMeades 1:ee7cc8d75283 747
RobMeades 1:ee7cc8d75283 748 // First, get the designed capacity
RobMeades 1:ee7cc8d75283 749 if (getDesignCapacity(&designCapacityUAh)) {
RobMeades 1:ee7cc8d75283 750 designCapacityUAh *= 1000;
RobMeades 1:ee7cc8d75283 751 // Then get the used capacity
RobMeades 1:ee7cc8d75283 752 if (getUsedCapacity(&usedCapacityUAh)) {
RobMeades 1:ee7cc8d75283 753 success = true;
RobMeades 1:ee7cc8d75283 754 // Limit the result
RobMeades 1:ee7cc8d75283 755 if (usedCapacityUAh > designCapacityUAh) {
RobMeades 1:ee7cc8d75283 756 usedCapacityUAh = designCapacityUAh;
RobMeades 1:ee7cc8d75283 757 }
RobMeades 1:ee7cc8d75283 758
RobMeades 1:ee7cc8d75283 759 // The answer is in uAh
RobMeades 1:ee7cc8d75283 760 if (pCapacityUAh) {
RobMeades 1:ee7cc8d75283 761 *pCapacityUAh = designCapacityUAh - usedCapacityUAh;
RobMeades 1:ee7cc8d75283 762 }
RobMeades 1:ee7cc8d75283 763
RobMeades 1:ee7cc8d75283 764 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 765 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity remaining %u uAh (from a designed capacity of %d uAh).\n", gAddress >> 1,
RobMeades 1:ee7cc8d75283 766 (unsigned int) (designCapacityUAh - usedCapacityUAh), (unsigned int) designCapacityUAh);
RobMeades 1:ee7cc8d75283 767 #endif
RobMeades 1:ee7cc8d75283 768 }
RobMeades 1:ee7cc8d75283 769 }
RobMeades 1:ee7cc8d75283 770
RobMeades 1:ee7cc8d75283 771 return success;
RobMeades 1:ee7cc8d75283 772 }
RobMeades 1:ee7cc8d75283 773
RobMeades 1:ee7cc8d75283 774 // Get the percentage capacity remaining.
RobMeades 1:ee7cc8d75283 775 bool BatteryGaugeBq35100::getRemainingPercentage(int32_t *pBatteryPercentage)
RobMeades 1:ee7cc8d75283 776 {
RobMeades 1:ee7cc8d75283 777 bool success = false;
RobMeades 1:ee7cc8d75283 778 uint32_t designCapacityUAh;
RobMeades 1:ee7cc8d75283 779 uint32_t usedCapacityUAh;
RobMeades 1:ee7cc8d75283 780 int32_t batteryPercentage;
RobMeades 1:ee7cc8d75283 781
RobMeades 1:ee7cc8d75283 782 // First, get the designed capacity
RobMeades 1:ee7cc8d75283 783 if (getDesignCapacity(&designCapacityUAh)) {
RobMeades 1:ee7cc8d75283 784 designCapacityUAh *= 1000;
RobMeades 1:ee7cc8d75283 785 // Then get the used capacity
RobMeades 1:ee7cc8d75283 786 if (getUsedCapacity(&usedCapacityUAh)) {
RobMeades 1:ee7cc8d75283 787 success = true;
RobMeades 1:ee7cc8d75283 788 // Limit the result
RobMeades 1:ee7cc8d75283 789 if (usedCapacityUAh > designCapacityUAh) {
RobMeades 1:ee7cc8d75283 790 usedCapacityUAh = designCapacityUAh;
RobMeades 1:ee7cc8d75283 791 }
RobMeades 1:ee7cc8d75283 792 batteryPercentage = (uint64_t) (designCapacityUAh - usedCapacityUAh) * 100 / designCapacityUAh;
RobMeades 1:ee7cc8d75283 793
RobMeades 1:ee7cc8d75283 794 if (pBatteryPercentage) {
RobMeades 1:ee7cc8d75283 795 *pBatteryPercentage = batteryPercentage;
RobMeades 1:ee7cc8d75283 796 }
RobMeades 1:ee7cc8d75283 797
RobMeades 1:ee7cc8d75283 798 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 799 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity remaining %d%%.\n", gAddress >> 1,
RobMeades 1:ee7cc8d75283 800 (unsigned int) batteryPercentage);
RobMeades 1:ee7cc8d75283 801 #endif
RobMeades 1:ee7cc8d75283 802 }
RobMeades 1:ee7cc8d75283 803 }
RobMeades 1:ee7cc8d75283 804
RobMeades 1:ee7cc8d75283 805 return success;
RobMeades 1:ee7cc8d75283 806 }
RobMeades 1:ee7cc8d75283 807
RobMeades 1:ee7cc8d75283 808 // Get the security mode of the chip.
RobMeades 1:ee7cc8d75283 809 BatteryGaugeBq35100::SecurityMode BatteryGaugeBq35100::advancedGetSecurityMode(void)
RobMeades 1:ee7cc8d75283 810 {
RobMeades 1:ee7cc8d75283 811 SecurityMode securityMode = SECURITY_MODE_UNKNOWN;
RobMeades 1:ee7cc8d75283 812
RobMeades 1:ee7cc8d75283 813 if (gReady) {
RobMeades 1:ee7cc8d75283 814 gpI2c->lock();
RobMeades 1:ee7cc8d75283 815
RobMeades 1:ee7cc8d75283 816 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 817 *pGaugeEnable = 1;
RobMeades 1:ee7cc8d75283 818 wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS);
RobMeades 1:ee7cc8d75283 819 }
RobMeades 1:ee7cc8d75283 820
RobMeades 1:ee7cc8d75283 821 securityMode = getSecurityMode();
RobMeades 1:ee7cc8d75283 822
RobMeades 1:ee7cc8d75283 823 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 824 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 825 }
RobMeades 1:ee7cc8d75283 826
RobMeades 1:ee7cc8d75283 827 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 828 }
RobMeades 1:ee7cc8d75283 829
RobMeades 1:ee7cc8d75283 830 return securityMode;
RobMeades 1:ee7cc8d75283 831 }
RobMeades 1:ee7cc8d75283 832
RobMeades 1:ee7cc8d75283 833 // Set the security mode of the chip.
RobMeades 1:ee7cc8d75283 834 bool BatteryGaugeBq35100::advancedSetSecurityMode(SecurityMode securityMode)
RobMeades 1:ee7cc8d75283 835 {
RobMeades 1:ee7cc8d75283 836 bool success = false;
RobMeades 1:ee7cc8d75283 837
RobMeades 1:ee7cc8d75283 838 if (gReady) {
RobMeades 1:ee7cc8d75283 839 gpI2c->lock();
RobMeades 1:ee7cc8d75283 840
RobMeades 1:ee7cc8d75283 841 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 842 *pGaugeEnable = 1;
RobMeades 1:ee7cc8d75283 843 wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS);
RobMeades 1:ee7cc8d75283 844 }
RobMeades 1:ee7cc8d75283 845
RobMeades 1:ee7cc8d75283 846 success = setSecurityMode(securityMode);
RobMeades 1:ee7cc8d75283 847
RobMeades 1:ee7cc8d75283 848 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 849 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 850 }
RobMeades 1:ee7cc8d75283 851
RobMeades 1:ee7cc8d75283 852 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 853 }
RobMeades 1:ee7cc8d75283 854
RobMeades 1:ee7cc8d75283 855 return success;
RobMeades 1:ee7cc8d75283 856 }
RobMeades 1:ee7cc8d75283 857
RobMeades 1:ee7cc8d75283 858 // Do a hard reset of the chip.
RobMeades 1:ee7cc8d75283 859 bool BatteryGaugeBq35100::advancedReset(void)
RobMeades 1:ee7cc8d75283 860 {
RobMeades 1:ee7cc8d75283 861 bool success = false;
RobMeades 1:ee7cc8d75283 862 SecurityMode securityMode;
RobMeades 1:ee7cc8d75283 863 char data[3];
RobMeades 1:ee7cc8d75283 864
RobMeades 1:ee7cc8d75283 865 if (gReady && (gpI2c != NULL)) {
RobMeades 1:ee7cc8d75283 866 gpI2c->lock();
RobMeades 1:ee7cc8d75283 867
RobMeades 1:ee7cc8d75283 868 securityMode = getSecurityMode(); // Must be inside lock()
RobMeades 1:ee7cc8d75283 869 // Handle unsealing, as this command only works when unsealed
RobMeades 1:ee7cc8d75283 870 if (setSecurityMode(SECURITY_MODE_UNSEALED)) {
RobMeades 1:ee7cc8d75283 871 // Send a RESET sub-command
RobMeades 1:ee7cc8d75283 872 data[0] = 0x3e; // Set address to first register for ManufacturerAccessControl
RobMeades 1:ee7cc8d75283 873 data[1] = 0x41; // First byte of RESET sub-command (0x41)
RobMeades 1:ee7cc8d75283 874 data[2] = 0x00; // Second byte of RESET sub-command (0x00) (register address will auto-increment)
RobMeades 1:ee7cc8d75283 875
RobMeades 1:ee7cc8d75283 876 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
RobMeades 1:ee7cc8d75283 877 success = true;
RobMeades 1:ee7cc8d75283 878 #ifdef DEBUG_BQ35100
RobMeades 1:ee7cc8d75283 879 printf("BatteryGaugeBq35100 (I2C 0x%02x): chip hard reset.\n", gAddress >> 1);
RobMeades 1:ee7cc8d75283 880 #endif
RobMeades 1:ee7cc8d75283 881 }
RobMeades 1:ee7cc8d75283 882
RobMeades 1:ee7cc8d75283 883 // Set the security mode back to what it was
RobMeades 1:ee7cc8d75283 884 if (!setSecurityMode(securityMode)) {
RobMeades 1:ee7cc8d75283 885 success = false;
RobMeades 1:ee7cc8d75283 886 }
RobMeades 1:ee7cc8d75283 887 }
RobMeades 1:ee7cc8d75283 888
RobMeades 1:ee7cc8d75283 889 if (!gGaugeOn) {
RobMeades 1:ee7cc8d75283 890 *pGaugeEnable = 0;
RobMeades 1:ee7cc8d75283 891 }
RobMeades 1:ee7cc8d75283 892
RobMeades 1:ee7cc8d75283 893 gpI2c->unlock();
RobMeades 1:ee7cc8d75283 894 }
RobMeades 1:ee7cc8d75283 895
RobMeades 1:ee7cc8d75283 896 return success;
RobMeades 1:ee7cc8d75283 897 }
RobMeades 1:ee7cc8d75283 898
RobMeades 0:cec745c014b7 899 /* End Of File */