This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

bq27421-G1 threshold

Other Parts Discussed in Thread: BQ27421-G1

Hi

Iam using bq27421-G1 fuel guage in one of our project.

Please help me on the below queries

1. Need to increase the set threshold (default  10%) to another value. I have found that its belong to the Data memory section

    How to change the threshold ?

2. My Environment is non-os based.Is there any sample bare metal driver available for bq27421-G1 ??

   

Thanks

  • 1: The easiest way to do this is to readsubclass 49 (discharge), change the unsigned byte value in offset 0 from 10 to your preferred value, calculate the check sum and then write the subclass to the gauge. See 3.1 in http://www.ti.com/lit/ug/sluuac5b/sluuac5b.pdf or you can use the attached example code.

    2: An OS independent C code example how to read/write registers and data memory is attached.

    #example code bq27421 - absolutely no warranties implied
    
    #define GAUGE_DEVICE_ADDRESS 0xAA
    
    #define SET_CFGUPDATE 	0x0013
    #define SOFT_RESET 		0x0042
    #define RESET			0x0041
    #define SET_HIBERNATE	0x0011
    
    #define CMD_TEMP		0x02
    #define CMD_VOLT		0x04
    #define CMD_FLAGS 		0x06
    #define CMD_RM			0x0C
    #define CMD_FCC			0x0E
    #define CMD_SOC			0x1C
    #define CMD_SOH			0x20
    
    #define CMD_DATA_CLASS 	0x3E
    #define CMD_DATA_BLOCK 	0x3F
    #define CMD_BLOCK_DATA	0x40
    #define CMD_CHECK_SUM 	0x60
    
    #define DC_STATE	0x52
    #define DC_STATE_LENGTH	41
    
    #define CFGUPD 	0x0010
    #define ITPOR	0x0020
    
    
    // nI2C = handle to your I2C driver (if required)
    // nRegister = gauge register
    // pData = pointer to data block which will hold the data from the gauge
    // nLength = length
    int i2c_read(int nI2C, unsigned char nRegister, unsigned char *pData, unsigned char nLength)
    {
    	// implement your I2C read function here. Make sure you follow the timing requirements from the datasheet
    }
    
    // nI2C = handle to your I2C driver (if required)
    // nRegister = gauge register
    // pData = pointer to data block which holds the data for the gauge
    // nLength = length
    int i2c_write(int nI2C, unsigned char nRegister, unsigned char *pData, unsigned char nLength)
    {
    	// implement your I2C write function here. Make sure you follow the timing requirements from the datasheet 
    }
    
    // issue a control command (nSubCmd = sub command) to the gauge
    unsigned int gauge_control(int nI2C, unsigned int nSubCmd)
    {
    	unsigned int nResult = 0;
    
    	char pData[2];
    
    	pData[0] = nSubCmd & 0xFF;
    	pData[1] = (nSubCmd >> 8) & 0xFF;
    	
    	i2c_write(nI2C, 0x00, pData, 2); // issue control and sub command
    
    	i2c_read(nI2C, 0x00, pData, 2); // read data
    
    	nResult = (pData[1] << 8) | pData[0];
    
    	return nResult; 
    }
    
    // read 2 bytes from the gauge (nCmd = command)
    unsigned int gauge_cmd_read(int nI2C, unsigned char nCmd)
    {
    	unsigned char pData[2];
    
    	i2c_read(nI2C, nCmd, pData, 2);
    
    	return (pData[1] << 8) | pData[0];
    } 
    
    // write 2 bytes to the gauge (nCmd = command, nData = 16 bit parameter)
    unsigned int gauge_cmd_write(int nI2C, unsigned char nCmd, unsigned int nData)
    {
    	unsigned char pData[2];
    
    	pData[0] = nData & 0xFF;
    	pData[1] = (nData >> 8) & 0xFF;
    
    	i2c_write(nI2C, nCmd, pData, 2);
    
    	return (pData[1] << 8) | pData[0];
    } 
    
    #define MAX_ATTEMPTS 5
    // exit CFG_UPDATE mode with one of the supported exit commands (e.g. SOFT_RESET)
    int gauge_exit(int nI2C, unsigned int nCmd)
    {
    	unsigned int nFlags;
    	int nAttempts = 0;
    	gauge_control(nI2C, nCmd);
    
    	do
    	{
    		nFlags = gauge_cmd_read(nI2C, CMD_FLAGS);
    		if (nFlags & CFGUPD) usleep(500000);
    	} while ((nFlags & CFGUPD) && (nAttempts++ < MAX_ATTEMPTS));
    
    	return (nAttempts < MAX_ATTEMPTS);
    }
    
    // enter CFG_UPDATE mode
    int gauge_cfg_update(int nI2C)
    {
    	unsigned int nFlags;
    	int nAttempts = 0;
    	gauge_control(nI2C, SET_CFGUPDATE);
    
    	do
    	{
    		nFlags = gauge_cmd_read(nI2C, CMD_FLAGS);
    		if (!(nFlags & CFGUPD)) usleep(500000);
    	} while (!(nFlags & CFGUPD) && (nAttempts++ < MAX_ATTEMPTS));
    
    	return (nAttempts < MAX_ATTEMPTS);
    }
    
    // read a data class.
    // nDataClass = data class number
    // pData = raw data (for the whole data class)
    // nLength = length of the whole data class
    int gauge_read_data_class(int nI2C, unsigned char nDataClass, unsigned char *pData, unsigned char nLength)
    {
    	unsigned char nRemainder = nLength;
    	unsigned int nOffset = 0;
    	unsigned char nDataBlock = 0x00;
    	unsigned int nData;
    
    	if (nLength < 1) return 0;
    
    	do
    	{
    
    		nLength = nRemainder;
    		if (nLength > 32)
    		{
    			nRemainder = nLength - 32;
    			nLength = 32;
    		}
    		else nRemainder = 0;
    
    		nData = (nDataBlock << 8) | nDataClass;
    		gauge_cmd_write(nI2C, CMD_DATA_CLASS, nData);
    
    		i2c_read(nI2C, CMD_BLOCK_DATA, pData, nLength);
    
    		pData += nLength;
    		nDataBlock++;
    	} while (nRemainder > 0);
    
    	return nLength;
    }
    
    unsigned char check_sum(unsigned char *pData, unsigned char nLength)
    {
    	unsigned char nSum = 0x00;
    	unsigned char n;
    
    	for (n = 0; n < nLength; n++)
    		nSum += pData[n];
    
    	nSum = 0xFF - nSum;
    
    	return nSum;
    }
    
    // write a data class.
    // nDataClass = data class number
    // pData = raw data (for the whole data class)
    // nLength = length of the whole data class
    int gauge_write_data_class(int nI2C, unsigned char nDataClass, unsigned char *pData, unsigned char nLength)
    {
    	unsigned char nRemainder = nLength;
    	unsigned int nOffset = 0;
    	unsigned char pCheckSum[2] = {0x00, 0x00};
    	unsigned int nData;
    	unsigned char nDataBlock = 0x00;
    
    	if (nLength < 1) return 0;
    
    	do
    	{
    		nLength = nRemainder;
    		if (nLength > 32)
    		{
    			nRemainder = nLength - 32;
    			nLength = 32;
    		}
    		else nRemainder = 0;
    
    		nData = (nDataBlock << 8) | nDataClass;
    		gauge_cmd_write(nI2C, CMD_DATA_CLASS, nData);
    
    		i2c_write(nI2C, CMD_BLOCK_DATA, pData, nLength);
    		pCheckSum[0] = check_sum(pData, nLength);
    		i2c_write(nI2C, CMD_CHECK_SUM, pCheckSum, 1);
    
    		usleep(10000);
    
    		gauge_cmd_write(nI2C, CMD_DATA_CLASS, nData);
    		i2c_read(nI2C, CMD_CHECK_SUM, pCheckSum + 1, 1);
    		if (pCheckSum[0] != pCheckSum[1])
    			printf("gauge_write_data_class(): CheckSum mismatch 0x%02X vs. 0x%02X\n\r", pCheckSum[0], pCheckSum[1]);
    
    		pData += nLength;
    		nDataBlock++;
    	} while (nRemainder > 0);
    
    	return nLength;
    }
    
    void print_data(unsigned char *pData, unsigned int nLength)
    {
    	unsigned int n;
    
    	for (n = 0; n < nLength; n++)
    	{
    		printf("%02X ", pData[n]);
    		if (!((n + 1) % 16)) printf("\n\r");
    	}
    
    	printf("\n\r");
    }
    
    /*
    Example configuration:
    
    	#define MAX_ATTEMPTS	5
    
    	#define DESIGN_CAPACITY		3210										//[mAh]
    	#define NOMINAL_VOLTAGE		3.7											//[V]
    	#define DESIGN_ENERGY		(DESIGN_CAPACITY * NOMINAL_VOLTAGE)			//[mWh]
    	#define TERMINATE_VOLTAGE	3000										//[mV]
    	#define TAPER_CURRENT		115											//[mA]
    	#define TAPER_RATE			(DESIGN_CAPACITY / (0.1 * TAPER_CURRENT))	//[0.1h]			
    
    	// open your I2C communications channel and store a handle in nI2C (if required)
    
    	unsigned char pData[DC_STATE_LENGTH];
    	unsigned int nFlags;
    	int nAttempts = 0;
    
    	gauge_control(nI2C, SOFT_RESET);
    	do
    	{
    		nFlags = gauge_cmd_read(nI2C, CMD_FLAGS);
    		if (nFlags & ITPOR) usleep(500000); //usleep sleeps for n microseconds. 
    	} while ((nFlags & ITPOR) && (nAttempts++ < MAX_ATTEMPTS));
    
    	//read data class DC_STATE:
    	gauge_read_data_class(nI2C, DC_STATE, pData, DC_STATE_LENGTH);
    	printf("Data Class 'State' (0x52):\n\r");
    	print_data(pData, DC_STATE_LENGTH); 
    	
    	// this was for bq2742x - change offsets for your gauge
    	pData[10] = (DESIGN_CAPACITY & 0xFF00) >> 8;
    	pData[11] = DESIGN_CAPACITY & 0xFF;
    	
    	pData[12] = (DESIGN_ENERGY & 0xFF00) >> 8;
    	pData[13] = DESIGN_ENERGY & 0xFF;
    	
    	pData[16] = (TERMINATE_VOLTAGE & 0xFF00) >> 8;
    	pData[17] = TERMINATE_VOLTAGE & 0xFF;
    	
    	pData[27] = (TAPER_RATE & 0xFF00) >> 8;
    	pData[28] = TAPER_RATE & 0xFF;
    
    	//write data class DC_STATE:
    	gauge_cfg_update(nI2C);
    	gauge_write_data_class(nI2C, DC_STATE, pData, DC_STATE_LENGTH);
    	gauge_exit(nI2C, SOFT_RESET);
    	
    	//read several gauge registers
    	nResult = gauge_cmd_read(nI2C, CMD_TEMP);
    	printf("TEMPERATURE = 0x%04X\n\r", nResult);
    
    	nResult = gauge_cmd_read(nI2C, CMD_VOLT);
    	printf("VOLTAGE = 0x%04X\n\r", nResult);
    
    	nResult = gauge_cmd_read(nI2C, CMD_SOC);
    	printf("SOC = 0x%04X\n\r", nResult);
    
    */