Part Number:BQ27441-G1
Tool/software: TI C/C++ Compiler
Dear Forum,
I am using a BQ27441 G1B, I have connected it to a microcontroller board (Tiva TM4C123G) using I2C. To initialize the BQ27441 we need to follow 14 steps indicated in the technical reference, sec - 3.1, pg 14, but, I'm still having trouble making these steps work. In step 8, I indicated the value of design capacity that we should expect for type G1B, but not for type G1A. In the code, we set this value to 0xAC to force the if operation, but during the code the read values do not match the one shown in the reference manual and so I can not read the main battery characteristics.
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_i2c.h"
#include "inc/uartstdio.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/i2c.h"
#include "driverlib/sysctl.h"
#include "driverlib/rom_map.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/uart.h"
#define BQ27441_ADDR 0x55
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
#define I2C_MODE Master
#define I2C0SDA
#define I2C0SCL
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
void InitI2C0(void);
void UART_Init();
void I2CSendString(uint32_t slave_addr, char array[]);
uint32_t I2CReceive(uint32_t slave_addr, uint8_t reg);
void bq27441_init();
int main(void)
{
SysCtlClockSet(
SYSCTL_USE_PLL // Use interpnal PLL (internal PLL will multiply frequency to reach 400 MHz according to datasheet)
| SYSCTL_XTAL_16MHZ // Configure PLL to use a source frequency of 16 MHz
| SYSCTL_SYSDIV_2_5 // Divide PLL output frequency by 5 to reach 80 MHz final frequency
| SYSCTL_OSC_MAIN // Tell microcontroller to use main (external) crystal oscillator
);
UART_Init();
SysCtlDelay(20000000);
while(1)
{
bq27441_init();
}
}
//initialize I2C module 0
void InitI2C0(void){
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
//reset module
SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
// Configure the pin muxing for I2C0 functions on port B2 and B3.
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
HWREG(I2C0_BASE + I2C_O_FIFOCTL) = 80008000;
}
void UART_Init()
{
//Baud Rate: 9600
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0);
GPIOPinConfigure(GPIO_PA1_U0TX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0));
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0));
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
UARTStdioConfig(0, 9600, SysCtlClockGet()/5);
}
void I2CSendString(uint32_t slave_addr, char array[])
{
I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, false);
I2CMasterDataPut(I2C0_BASE, array[0]);
//0x81, apenas para finalizar o array
if(array[1] == 0x81)
{
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
while(I2CMasterBusy(I2C0_BASE));
}
else
{
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
while(I2CMasterBusy(I2C0_BASE));
uint8_t i = 1;
while(array[i + 1] != 0x81)
{
I2CMasterDataPut(I2C0_BASE, array[i++]);
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
while(I2CMasterBusy(I2C0_BASE));
}
I2CMasterDataPut(I2C0_BASE, array[i]);
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
while(I2CMasterBusy(I2C0_BASE));
}
}
//read specified register on slave device
uint32_t I2CReceive(uint32_t slave_addr, uint8_t reg)
{
//specify that we are writing (a register address) to the
//slave device
I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, false);
//specify register to be read
I2CMasterDataPut(I2C0_BASE, reg);
//send control byte and register address byte to slave device
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
//wait for MCU to finish transaction
while(I2CMasterBusy(I2C0_BASE));
//specify that we are going to read from slave device
I2CMasterSlaveAddrSet(I2C0_BASE, slave_addr, true);
//send control byte and read from the register we
//specified
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
//wait for MCU to finish transaction
while(I2CMasterBusy(I2C0_BASE));
//return data pulled from the specified register
return I2CMasterDataGet(I2C0_BASE);
}
void bq27441_init()
{
uint8_t flag_out[10], block_data_checksum_data[10], data[100], design_capacity_data[10];
uint16_t design_capacity;
float voltage = 0.0, remaining_batt_cap = 0.0, full_charge_cap = 0.0, soc = 0.0, temp = 0.0, current = 0.0;
InitI2C0();
char writeData[3] = {0x00, 0x04, 0x81};
char unseal_data[4] = {0x00, 0x00, 0x80, 0x81};
char cfgupdate_data[4] = {0x00, 0x13, 0x00, 0x81};
char flag_data[2] = {0x06, 0x81};
char block_data_control[3] = {0x61, 0x00, 0x81};
char data_block_class[3] = {0x3E, 0x52, 0x81};
char data_block[3] = {0x3F, 0x00, 0x81};
char block_data_checksum[2] = {0x60, 0x81};
char design_capacity_loc[2] = { 0x4A,/* 0x4B,*/ 0x81};
char soft_reset[4] = {0x00, 0x42, 0x00, 0x81};
char seal_data[3] = {0x00, 0x20, 0x00, 0x81};
//Step 1
I2CSendString(BQ27441_ADDR, unseal_data);
I2CSendString(BQ27441_ADDR, unseal_data);
SysCtlDelay(133333);
UARTprintf("The gauge seems to be unsealed. \n");
//Step 2
I2CSendString(BQ27441_ADDR, cfgupdate_data);
SysCtlDelay(133333);
//Step 3
flag_out[0] = I2CReceive(BQ27441_ADDR, flag_data[0]);
UARTprintf("The _out is: %x \n", flag_out[0]);
if (CHECK_BIT(flag_out[0], 4)) {
UARTprintf("The gauge is ready to be configured \n");
//Step 4
I2CSendString(BQ27441_ADDR, block_data_control);
SysCtlDelay(133333);
//Step 5
I2CSendString(BQ27441_ADDR, data_block_class);
SysCtlDelay(133333);
//Step 6
I2CSendString(BQ27441_ADDR, data_block);
SysCtlDelay(133333);
//Step 7
block_data_checksum_data[0] = I2CReceive(BQ27441_ADDR, block_data_checksum[0]);
UARTprintf("The checksum_data: %x \n", block_data_checksum_data[0]);
if (block_data_checksum_data[0] == 0xAC) {
UARTprintf("The checksum is as expected. Config will proceed. \n");
//Step 8
design_capacity_data[0] = I2CReceive(BQ27441_ADDR, design_capacity_loc[0]);
UARTprintf("The design capacity data is: %d mAh \n", design_capacity_data[0]);
/*
design_capacity = design_capacity_data[0]*16*16 + design_capacity_data[1]; //two values?
SysCtlDelay(133333);
UARTprintf("The current design capacity is: %d mAh \n", design_capacity);
*/
//Step 12
I2CSendString(BQ27441_ADDR, soft_reset);
SysCtlDelay(1000);
//Step 13
flag_out[0] = I2CReceive(BQ27441_ADDR, flag_data[0]);
UARTprintf("The _out is: %x \n", flag_out[0]);
//Step 14
if(!CHECK_BIT(flag_out[0], 4)) {
UARTprintf("CFGUPDTE has been exited, configuration done. \n");
I2CSendString(BQ27441_ADDR, seal_data);
SysCtlDelay(5);
UARTprintf("Gauge has been sealed and is ready for operation \n");
}
}
}
while(true){
int t;
for (t=0;t<100;t++){
//Leitura dos registros do dispositivo
I2CSendString(BQ27441_ADDR, writeData);
I2CReceive(BQ27441_ADDR, data[t]);
}
}
voltage = data[4]*16*16 + data[3];
remaining_batt_cap = data[12]*16*16 + data[11];
full_charge_cap = data[14]*16*16 + data[13];
soc = (remaining_batt_cap/full_charge_cap)*100;
temp = (data[2]*16*16 + data[1])/10.0 - 273.0;
current = data[16]*16*16 + data[15];
UARTprintf("Voltage: %d mV\n", voltage);
UARTprintf("Current: %f mA\n", current);
UARTprintf("Remaining Battery Capacity: %f mAh\n", remaining_batt_cap);
UARTprintf("Full Charge Capacity: %f mAh\n", full_charge_cap);
UARTprintf("State of Charge: %f p.c. \n", soc);
UARTprintf("Temperature: %f Deg C\n", temp);
}