Slua 801
Slua 801
Dominik Hartl
ABSTRACT
Battery gauges have a rich set of parameters which enable compatibility with a wide range of battery types
and applications. Programming these parameters requires access to data memory, which together with
examples of how to read gauging results, is explained in this application note.
Contents
1 Gauge Commands........................................................................................................... 2
2 Gauge Configuration ........................................................................................................ 2
3 Accessing the Gauge From a Host Controller ........................................................................... 2
3.1 Abstract End-System Dependent APIs .......................................................................... 2
3.2 Configuration ........................................................................................................ 3
3.3 Gauge Standard Commands ...................................................................................... 4
3.4 Gauge Sub Commands ............................................................................................ 4
3.5 Gauge Data Memory Access ...................................................................................... 4
4 Data Memory ................................................................................................................. 5
4.1 Subclasses and Data Blocks ...................................................................................... 5
4.2 Addressing Data Memory .......................................................................................... 6
4.3 ROM Gauge vs FLASH Gauge ................................................................................... 7
5 FlashStream® File Format .................................................................................................. 8
Appendix A Source Code ........................................................................................................ 9
List of Tables
1 Data Type Examples ........................................................................................................ 5
1 Gauge Commands
The host controller communicates with the gauge through gauge commands.
A gauge command is the equivalent to a register. For example, reading the state of charge is
accomplished through the StateOfCharge() gauge command, which has the command codes 0x1C and
0x1D. So if the interface is I2C, reading from device register 0x1C and 0x1D returns the current state of
charge of the battery as calculated by the gauge.
The TRM for the gauge lists the available gauge commands. The commands are organized in two groups:
• Standard commands (which allow access to common gauging information).
– Standard command Control() is used to execute various functions (sub commands).
• Extended commands (which mainly support access to the of the gauge's proprietary configuration
parameters in data memory).
2 Gauge Configuration
Battery gauges have a rich set of parameters which enable compatibility with a wide range of battery types
and applications. Some gauges require very little configuration, while others require a significant number
of parameters to adjust performance for a specific battery and system.
All gauges store configuration in data memory using an indirect access method. Data memory is
organized in subclasses and subclasses are organized in data blocks, which are a sequence of bytes.
Each data block contains various parameters at specific offsets, lengths and data types.
Configuring the gauge means setting specific parameters, which is accomplished by writing the applicable
bytes within a data block of a subclass within the data memory of the gauge.
TI provides a software tool, bqStudio, which allows easy access to all parameters through a GUI. After
creating and validating the configuration with bqStudio, the configuration can be exported in a
FlashStream® file. See Section 5 for information about the format of this file.
These three function prototypes are not specific to the underlying interface (I2C, SMBUS, or HDQ).
However, the implementation is specific to the interface. See Section A.3 for an example using the Linux®
user space I2C interface.
[nRegister] in the nomenclature of a TI gauge is the equivalent to a command.
[pHandle] is a (void) pointer to a data structure which identifies the communications interface. This pointer
can be NULL if there is a non-ambiguous single communications interface or it can point to data which
identifies the communications interface. The example code does not access this pointer – it is intended as
a handle only.
3.2 Configuration
Configuration of the gauge is supported by the following APIs.
If the host uC supports a file system, the FlashStream file from bqStudio can be stored on this file system,
and the host uC can open the content and provide it to this function as a zero-terminated string of
characters.
If the host uC does not support a file system, the content of the FlashStream file can be copied into a
constant zero-terminated C-string (for example, in a header file which is then compiled into the firmware
image).
Example (Linux):
struct stat st;
char *pFileBuffer;
int nFSFile;
void *pI2C;
stat(FLASH_STREAM_FILE, &st);
if ((nFSFile = open(FLASH_STREAM_FILE, O_RDONLY)) <0) exit(1);
pFileBuffer = malloc(st.st_size);
if (!pFileBuffer) exit(1);
read(nFSFile, pFileBuffer, st.st_size);
close(nFSFile);
Examples:
int nVoltage = gauge_cmd_read(pI2C, CMD_VOLTAGE); //voltage in [mV]
int nSOC = gauge_cmd_read(pI2C, CMD_STATE_OF_CHARGE); //SOC in [%]
gauge_cmd_write(pI2C, CMD_AT_RATE, nAtRate); // set load value
Examples:
gauge_control(pI2C, SUBCMD_ RESET); // reset the gauge
int nFWVersion = gauge_control(pI2C, SUBCMD_FW_VERSION); // read FW version
int nChemID = gauge_control(pI2C, SUBCMD_CHEMID); // read ChemID
Example: change design capacity and design energy for the bq27421.
To change parameters, first identify the data class (also called subclass) from the TRM. In this example,
the two parameters reside in the data class State at offset 10 (design capacity) and offset 12 (design
energy). Read the whole data class into a byte buffer with a size equal to integer multiples of 32. The size
must be greater or equal of the largest offset (plus the data type length) within the data class. This
information is in the TRM. In this example, the largest offset in data class State is 39 with a data type
length of two bytes (data type = I2) so the whole data class size is 2 × 32 = 64. Change the parameter in
the byte buffer followed by writing the whole data class:
char pData[DC_STATE_LENGTH]; //DC_STATE_LENGTH = 64
gauge_read_data_class(pI2C, DC_STATE, pData, DC_STATE_LENGTH);
4 Data Memory
Data memory stores the configuration of the gauge. There are two basic types of gauges: flash and ROM
(some ROM gauges have one time programmable (OTP) memory).
Writing data memory of flash gauges stores the configuration in persistent memory so even if the gauge is
reset or power cycled, it keeps the configuration. Flash gauge data memory can be written without
changing the operating mode of the gauge.
ROM gauges contain default configuration (including ChemID) in read only memory. During gauge boot
up, the default configuration is copied automatically from ROM to data memory RAM. Updating gauge
configuration for a ROM gauge means changing the content of the data memory in RAM. Because this is
volatile memory, its contents are lost after a power cycle or reset. ROM gauge data memory in RAM
require a change of operating mode of the gauge (configuration update mode).
Some ROM gauges have OTP memory which the user can program during production. The gauge copies
the contents of the OTP memory to data memory RAM during gauge boot.
TI provides production tools (bqStudio and SmartFlash) to program flash or OTP memory during
production. After the gauge configuration is completed during development using bqStudio and a gauge
EVM, bqStudio generates a Golden Image with the gauge configuration. TI production tools use this
Golden Image file to program flash or OTP memory.
Some gauges have additional data types. See the TRM of a particular gauge for more information.
To change a configuration parameter, follow these steps:
1. Locate the parameter in the gauge TRM.
2. Copy the subclass data for this parameter into a local byte buffer using the gauge data memory access
function gauge_read_data_class (see Section 3.5).
3. Change the data in the local buffer (use the offset and data type information from the TRM for this
parameter).
4. For ROM gauges only, enable configuration update mode with the function gauge_cfg_update.
5. Write the local buffer to the subclass using the function gauge_write_data_class.
6. For ROM gauges only, exit configuration update mode with the function gauge_exit.
Example:
The bq27421 has a subclass State (subclass ID: 81) which holds parameters associated with the state of
the gauge and the cell, among them:
• Design capacity (offset: 10, length: 2 bytes, data type = I2), units = mAh
• Avg I Last Run (offset: 35, length: 2 bytes, data type = I2), units = mA
Design capacity is in data block #0 for subclass 81, so to write this parameter the two bytes at offset 10
must be changed (I2 → signed 2-byte integer).
If design capacity is 1500 mAh, the two bytes at offset 10, data block #0 are:
1500 decimal = 0x05DC → write 0x05 to offset 10 and 0xDC to offset 11.
Integer parameters are stored in big endian format within a data block. Avg I Last Run is at offset 35 in
subclass State (data type I2). This parameter is within data block #1 because it exceeds the length of data
block #0 (32 bytes). To read these parameters, combine the two bytes starting at offset 3 (35 – 32) in data
block #1, and interpret the result as a signed integer.
For example, if the byte at offset 3 is 0x01 and the byte at offset 4 is 0xF4, the 2-byte signed integer is
0x1F4, which is 500 decimal so the average current during the last discharge was 500 mA.
The check sum is the sum of all 32 data bytes within the current data block, truncated to 8-bits and
complemented. Example code to calculate the check sum follows:
pData = a pointer to the data that was changed in the data block.
nLength = length of the data block.
unsigned char check_sum(unsigned char *pData, unsigned char nLength)
{
unsigned char nSum = 0x00;
unsigned char n;
Example:
Write design capacity for the bq27421 is in subclass state (81 decimal = 0x51), offset 10 decimal = 0x0A
(in data block 0 = 0x00), 1500 mAh = 0x05DC. This example uses the abstract API from Section 3.1 to
read from and write to the gauge.
1. Write subclass (0x51) and block number (0x00): gauge_write(pI2C, 0x3E, “\x51\x00”, 2);
2. Read data block into buffer: gauge_read(pI2C, 0x40, pBuffer, 32);
3. Write design capacity:
• pBuffer[0x0A] = 0x05;
• pBuffer[0x0B] = 0xDC;
4. Write buffer to data block: gauge_write(pI2C, 0x40, pBuffer, 32);
5. Calculate check sum: unsigned char nCheckSum = check_sum(pBuffer, 32);
6. Write check sum: gauge_write(pI2C, 0x60, &nCheckSum, 1);
7. Wait 10 ms.
8. Read check sum: gauge_read(pI2C, 0x60, &nVerifyCheckSum, 1);
9. Verify that check sum matches (nCheckSum == nVerifyCheckSum).
After one (or more) data classes have been written, the gauge must exit configuration update mode to
resume gauging.
// gauge_exit: exit Configuration Update mode
// pHandle = handle to communications adapter
// nCmd = exit command (e.g. SOFT_RESET or EXIT_RESIM)
// return value: error = 0
int gauge_exit(void *pHandle, unsigned int nCmd);
Source Code
A.1 gauge.c
//Battery Gauge Library
//V1.0
//© 2016 Texas Instruments Inc.
#include <string>
#include "gauge.h"
//gauge_read: read bytes from gauge (must be implemented for a specific system)
//pHandle: handle to communications adapater
//nRegister: first register (=standard command) to read from
//pData: pointer to a data buffer
//nLength: number of bytes
//return value: number of bytes read (0 if error)
extern int gauge_read(void *pHandle, unsigned char nRegister, unsigned char *pData, unsigned char
nLength);
//gauge_read: write bytes to gauge (must be implemented for a specific system)
//pHandle: handle to communications adapater
//nRegister: first register (=standard command) to write to
//pData: pointer to a data buffer
//nLength: number of bytes
//return value: number of bytes written (0 if error)
extern int gauge_write(void *pHandle, unsigned char nRegister, unsigned char *pData, unsigned
char nLength);
//gauge_address: set device address for gauge (must be implemented for a specific system; not
required for HDQ)
//pHandle: handle to communications adapater
//nAddress: device address (e.g. 0xAA)
extern void gauge_address(void *pHandle, unsigned char nAddress);
char pData[2];
return nResult;
}
do
{
nFlags = gauge_cmd_read(pHandle, CMD_FLAGS);
if (!(nFlags & CFGUPD)) usleep(500000);
} while (!(nFlags & CFGUPD) && (nAttempts++ < MAX_ATTEMPTS));
do
{
nFlags = gauge_cmd_read(pHandle, CMD_FLAGS);
if (nFlags & CFGUPD) usleep(500000);
} while ((nFlags & CFGUPD) && (nAttempts++ <MAX_ATTEMPTS));
do
{
nLength = nRemainder;
if (nLength > 32)
{
nRemainder = nLength - 32;
nLength = 32;
}
else nRemainder = 0;
pData += nLength;
nDataBlock++;
} while (nRemainder > 0);
return 0;
}
return nSum;
}
do
{
nLength = nRemainder;
if (nLength < 32)
{
nRemainder = nLength - 32;
nLength = 32;
}
else nRemainder = 0;
usleep(10000);
pData += nLength;
nDataBlock++;
} while (nRemainder > 0);
return 0;
}
m = 0;
for (n = 0; n < nLength; n++)
if (pFS[n] != ' ') pFS[m++] = pFS[n];
pEnd = pFS + m;
pEnd[0] = 0;
do
{
switch (*pFS)
{
case ';':
break;
case 'W':
case 'C':
bWriteCmd = *pFS == 'W';
pFS++;
if ((*pFS) != ':') return pFS;
pFS++;
n = 0;
while ((pEnd - pFS > 2) && (n < sizeof(pData) + 2) &&(*pFS != '\n'))
{
pBuf[0] = *(pFS++);
pBuf[1] = *(pFS++);
pBuf[2] = 0;
if (n == 0) gauge_address(pHandle, m);
if (n == 1) nRegister = m;
if (n > 1) pData[n - 2] = m;
n++;
}
if (bWriteCmd)
gauge_write(pHandle, nRegister, pData, nDataLength);
else
{
char pDataFromGauge[nDataLength];
case 'X':
pFS++;
if ((*pFS) != ':') return pFS;
pFS++;
n = 0;
while ((pFS != pEnd) && (*pFS != '\n') &&(n <sizeof(pBuf) - 1))
{
pBuf[n++] = *pFS;
pFS++;
}
pBuf[n] = 0;
n = atoi(pBuf);
usleep(n * 1000);
break;
default: return pFS;
}
while ((pFS != pEnd) && (*pFS != '\n')) pFS++; //skip to next line
if (pFS != pEnd) pFS++;
return pFS;
}
A.2 gauge.h
//Battery Gauge Library
//V1.0
//© 2016 Texas Instruments Inc.
#ifndef __GAUGE_H
#define __GAUGE_H
#include <stdbool.h>
#define SOFT_RESET 0x0042
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include "gauge.h"
typedef struct
{
int nI2C;
unsigned char nAddress;
} TI2C;
int gauge_read(void *pHandle, unsigned char nRegister, unsigned char *pData, unsigned char
nLength)
{
TI2C *pI2C = (TI2C *) pHandle;
int n;
pData[0] = nRegister;
n = write(pI2C->nI2C, pData, 1); // write register address
usleep(100);
return n;
}
int gauge_write(void *pHandle, unsigned char nRegister, unsigned char *pData, unsigned char
nLength)
{
TI2C *pI2C = (TI2C *) pHandle;
unsigned char pWriteData[nLength + 1];
int n;
usleep(100);
return n - 1;
}
printf(" ");
for (n = 0; n < nLength; n++)
{
printf("%02X ", pData[n]);
if (!((n + 1) % 16)) printf("\n\r ");
}
printf("\n\r");
}
int main()
{
TI2C i2c;
void *pHandle = (void *) & i2c;
int nSourceFile;
struct stat st;
long n;
int nSeconds;
unsigned int nResult;
char *pFileBuffer;
printf("gauge test\n\r");
gauge_address(pHandle, GAUGE_DEVICE_ADDRESS);
stat(SOURCE_FILE, &st);
printf(gauge_execute_fs(pHandle, pFileBuffer));
free(pFileBuffer);
close(i2c.nI2C);
printf("closed I2C bus\n\r");
return 0;
}
Texas Instruments Incorporated (‘TI”) technical, application or other design advice, services or information, including, but not limited to,
reference designs and materials relating to evaluation modules, (collectively, “TI Resources”) are intended to assist designers who are
developing applications that incorporate TI products; by downloading, accessing or using any particular TI Resource in any way, you
(individually or, if you are acting on behalf of a company, your company) agree to use it solely for this purpose and subject to the terms of
this Notice.
TI’s provision of TI Resources does not expand or otherwise alter TI’s applicable published warranties or warranty disclaimers for TI
products, and no additional obligations or liabilities arise from TI providing such TI Resources. TI reserves the right to make corrections,
enhancements, improvements and other changes to its TI Resources.
You understand and agree that you remain responsible for using your independent analysis, evaluation and judgment in designing your
applications and that you have full and exclusive responsibility to assure the safety of your applications and compliance of your applications
(and of all TI products used in or for your applications) with all applicable regulations, laws and other applicable requirements. You
represent that, with respect to your applications, you have all the necessary expertise to create and implement safeguards that (1)
anticipate dangerous consequences of failures, (2) monitor failures and their consequences, and (3) lessen the likelihood of failures that
might cause harm and take appropriate actions. You agree that prior to using or distributing any applications that include TI products, you
will thoroughly test such applications and the functionality of such TI products as used in such applications. TI has not conducted any
testing other than that specifically described in the published documentation for a particular TI Resource.
You are authorized to use, copy and modify any individual TI Resource only in connection with the development of applications that include
the TI product(s) identified in such TI Resource. NO OTHER LICENSE, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE TO
ANY OTHER TI INTELLECTUAL PROPERTY RIGHT, AND NO LICENSE TO ANY TECHNOLOGY OR INTELLECTUAL PROPERTY
RIGHT OF TI OR ANY THIRD PARTY IS GRANTED HEREIN, including but not limited to any patent right, copyright, mask work right, or
other intellectual property right relating to any combination, machine, or process in which TI products or services are used. Information
regarding or referencing third-party products or services does not constitute a license to use such products or services, or a warranty or
endorsement thereof. Use of TI Resources may require a license from a third party under the patents or other intellectual property of the
third party, or a license from TI under the patents or other intellectual property of TI.
TI RESOURCES ARE PROVIDED “AS IS” AND WITH ALL FAULTS. TI DISCLAIMS ALL OTHER WARRANTIES OR
REPRESENTATIONS, EXPRESS OR IMPLIED, REGARDING TI RESOURCES OR USE THEREOF, INCLUDING BUT NOT LIMITED TO
ACCURACY OR COMPLETENESS, TITLE, ANY EPIDEMIC FAILURE WARRANTY AND ANY IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF ANY THIRD PARTY INTELLECTUAL
PROPERTY RIGHTS.
TI SHALL NOT BE LIABLE FOR AND SHALL NOT DEFEND OR INDEMNIFY YOU AGAINST ANY CLAIM, INCLUDING BUT NOT
LIMITED TO ANY INFRINGEMENT CLAIM THAT RELATES TO OR IS BASED ON ANY COMBINATION OF PRODUCTS EVEN IF
DESCRIBED IN TI RESOURCES OR OTHERWISE. IN NO EVENT SHALL TI BE LIABLE FOR ANY ACTUAL, DIRECT, SPECIAL,
COLLATERAL, INDIRECT, PUNITIVE, INCIDENTAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES IN CONNECTION WITH OR
ARISING OUT OF TI RESOURCES OR USE THEREOF, AND REGARDLESS OF WHETHER TI HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
You agree to fully indemnify TI and its representatives against any damages, costs, losses, and/or liabilities arising out of your non-
compliance with the terms and provisions of this Notice.
This Notice applies to TI Resources. Additional terms apply to the use and purchase of certain types of materials, TI products and services.
These include; without limitation, TI’s standard terms for semiconductor products http://www.ti.com/sc/docs/stdterms.htm), evaluation
modules, and samples (http://www.ti.com/sc/docs/sampterms.htm).
Mailing Address: Texas Instruments, Post Office Box 655303, Dallas, Texas 75265
Copyright © 2017, Texas Instruments Incorporated