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.

BQ76952: STM32F103 I2C communication with BQ76952 is not stablished.

Part Number: BQ76952
Other Parts Discussed in Thread: BQSTUDIO, BQ34Z100-G1

Hello sir , for long time I am trying to communicate with BQ76952 with STM32F103 viz. I2C  while communication I also connect the oscilloscope to watch the SDL and SCL and I attached the image also , after setup of the same I always getting unwanted (out of my understanding) data (eg.cell reading ,temperature)  Like that.

7880 mV
7880 mV
7880 mV
7880 mV
10450 mV
10450 mV
10450 mV
10450 mV
10450 mV
10450 mV
7880 mV
7880 mV
7880 mV
7880 mV
 

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>© Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <stdio.h>
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define DEV_ADDR  0x10  // BQ769x2 address is 0x10 including R/W bit or 0x8 as 7-bit address
#define CRC_Mode 0  // 0 for disabled, 1 for enabled
#define MAX_BUFFER_SIZE     10
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;

TIM_HandleTypeDef htim1;

UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
uint8_t spiData [2];
uint8_t spiRxData [2];
uint8_t rxdata [2];
uint8_t busyData [2] = {0xFF, 0xFF};

uint8_t TX_2Byte [2] = {0x00, 0x00};
uint8_t TX_3Byte [3] = {0x00, 0x00, 0x00};
uint8_t TX_4Byte [4] = {0x00, 0x00, 0x00, 0x00};
uint8_t TX_Buffer [MAX_BUFFER_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

uint8_t RX_2Byte [2] = {0x00, 0x00};
uint8_t RX_3Byte [3] = {0x00, 0x00, 0x00};
uint8_t RX_4Byte [4] = {0x00, 0x00, 0x00, 0x00};
uint8_t RX_12Byte [12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t RX_Buffer [MAX_BUFFER_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned int RX_CRC_Check = 0;

// Variables for cell voltages, temperatures, CC2 current, Stack voltage, PACK Pin voltage, LD Pin voltage
uint16_t CellVoltage [16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
float Temperature [3] = {0,0,0};
float FET_Temperature = 0;
uint16_t Stack_Voltage = 0x00;
uint16_t LD_Voltage = 0x00;
uint16_t PACK_Voltage = 0x00;
uint16_t PACK_Current = 0x00;
uint16_t AlarmBits = 0x00;

uint8_t SafetyStatusA;  // Safety Status Register A
uint8_t SafetyStatusB;  // Safety Status Register B
uint8_t SafetyStatusC;  // Safety Status Register C
uint8_t PFStatusA;   // Permanent Fail Status Register A
uint8_t PFStatusB;   // Permanent Fail Status Register B
uint8_t PFStatusC;   // Permanent Fail Status Register C
uint8_t FET_Status;  // FET Status register contents See TRM Section 12.2.20  - Shows states of FETs

uint16_t CB_ActiveCells;  // Cell Balancing Active Cells
uint16_t DEVICE_NUMBER;

uint8_t	UV_Fault = 0;   // under-voltage fault state
uint8_t	OV_Fault = 0;   // over-voltage fault state
uint8_t	SCD_Fault = 0;  // short-circuit fault state
uint8_t	OCD_Fault = 0;  // over-current fault state
uint8_t LD_ON = 0;							// Load Detect status bit
uint8_t DCHG = 0;   // discharge FET state
uint8_t CHG = 0;   // charge FET state
uint8_t PCHG = 0;  // pre-charge FET state
uint8_t PDSG = 0;  // pre-discharge FET state

uint32_t AccumulatedCharge_Int;
uint32_t AccumulatedCharge_Frac;
uint32_t AccumulatedCharge_Time;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_TIM1_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void uprint(char * str)
{
	HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), 100);
}
/* USER CODE END 0 */
void delayUS(uint32_t us) {   // Sets the delay in microseconds.
	__HAL_TIM_SET_COUNTER(&htim1,0);  // set the counter value a 0
	while (__HAL_TIM_GET_COUNTER(&htim1) < us);  // wait for the counter to reach the us input in the parameter
}

void delay_ticks(uint32_t ticks)
{
    SysTick->LOAD = ticks;
    SysTick->VAL = 0;
    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
    // COUNTFLAG is a bit that is set to 1 when counter reaches 0.
    // It's automatically cleared when read.
    while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0);
    SysTick->CTRL = 0;
}

void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
    uint8_t copyIndex = 0;
    for (copyIndex = 0; copyIndex < count; copyIndex++)
    {
        dest[copyIndex] = source[copyIndex];
    }
}

unsigned char Checksum(unsigned char *ptr, unsigned char len)
	// Calculates the checksum when writing to a RAM register. The checksum is the inverse of the sum of the bytes.
{
	unsigned char i;
	unsigned char checksum = 0;

	for(i=0; i<len; i++)
		checksum += ptr[i];

	checksum = 0xff & ~checksum;

	return(checksum);
}



unsigned char CRC8(unsigned char *ptr, unsigned char len)
{
	unsigned char i;
	unsigned char crc=0;
	while(len--!=0)
	{
		for(i=0x80; i!=0; i/=2)
		{
			if((crc & 0x80) != 0)
			{
				crc *= 2;
				crc ^= 0x107;
			}
			else
				crc *= 2;

			if((*ptr & i)!=0)
				crc ^= 0x107;
		}
		ptr++;
	}
	return(crc);
}

void I2C_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
{
		#if CRC_Mode
		{
		uint8_t crc_count = 0;
		crc_count = count * 2;
		uint8_t crc1stByteBuffer [3] = {0x10, reg_addr, reg_data[0]};
		unsigned int j;
		unsigned int i;
		uint8_t temp_crc_buffer [3];

		TX_Buffer[0] = reg_data[0];
		TX_Buffer[1] = CRC8(crc1stByteBuffer,3);

		j = 2;
		for(i=1; i<count; i++)
		{
			TX_Buffer[j] = reg_data[i];
			j = j + 1;
			temp_crc_buffer[0] = reg_data[i];
			TX_Buffer[j] = CRC8(temp_crc_buffer,1);
			j = j + 1;
		}
		HAL_I2C_Mem_Write(&hi2c1, DEV_ADDR, reg_addr, 1, TX_Buffer, count, 1000);
		}
		#endif

		#if CRC_Mode < 1
			HAL_I2C_Mem_Write(&hi2c1, DEV_ADDR, reg_addr, 1, reg_data, count, 1000);
		#endif
}


int I2C_ReadReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
{
	unsigned int RX_CRC_Fail = 0;  // reset to 0. If in CRC Mode and CRC fails, this will be incremented.

	#if CRC_Mode
	{
		uint8_t crc_count = 0;
		uint8_t ReceiveBuffer [10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
		crc_count = count * 2;
		unsigned int j;
		unsigned int i;
		unsigned char CRCc = 0;
		uint8_t temp_crc_buffer [3];

		HAL_I2C_Mem_Read(&hi2c1, DEV_ADDR, reg_addr, 1, ReceiveBuffer, crc_count, 1000);
		uint8_t crc1stByteBuffer [4] = {0x10, reg_addr, 0x11, ReceiveBuffer[0]};
		CRCc = CRC8(crc1stByteBuffer,4);
		if (CRCc != ReceiveBuffer[1])
			RX_CRC_Fail += 1;

		RX_Buffer[0] = ReceiveBuffer[0];

		j = 2;
		for (i=1; i<count; i++)
		{
			RX_Buffer[i] = ReceiveBuffer[j];
			temp_crc_buffer[0] = ReceiveBuffer[j];
			j = j + 1;
			CRCc = CRC8(temp_crc_buffer,1);
			if (CRCc != ReceiveBuffer[j])
				RX_CRC_Fail += 1;
			j = j + 1;
		}
		CopyArray(RX_Buffer, reg_data, crc_count);
	}
	#endif

	#if CRC_Mode < 1
			HAL_I2C_Mem_Read(&hi2c1, DEV_ADDR, reg_addr, 1, reg_data, count, 1000);
	#endif

	  return 0;
}


void AFE_Reset() {
	// Reset command. Resets all registers to default values or the values programmed in OTP.
	TX_2Byte[0] = 0x12; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void AFE_Init() {
	// Configures all parameters in device RAM

	// Enter CONFIGUPDATE mode (Subcommand 0x0090) - It is required to be in CONFIG_UPDATE mode to program the device RAM settings
	// See TRM Section 7.6 for full description of CONFIG_UPDATE mode
	TX_2Byte[0] = 0x90; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);

	delayUS(2000);

	// After entering CONFIG_UPDATE mode, RAM registers can be programmed. When programming RAM, checksum and length must also be
	// programmed for the change to take effect. All of the RAM registers are described in detail in Chapter 13 of the BQ76952 TRM.
	// An easier way to find the descriptions is in the BQStudio Data Memory screen. When you move the mouse over the register name,
	// a full description of the register and the bits will pop up on the screen.
	// A summary of the Data Memory is also in Section 13.9 of the TRM.

	// 'Power Config' - Set DSLP_LDO  - 0x9234 = 0x2D82  (See TRM section 13.3.2)
	// Setting the DSLP_LDO bit allows the LDOs to remain active when the device goes into Deep Sleep mode
  TX_4Byte[0] = 0x34; TX_4Byte[1] = 0x92; TX_4Byte[2] = 0x82; TX_4Byte[3] = 0x2D;
  I2C_WriteReg(0x3E, TX_4Byte, 4);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_4Byte, 4); TX_2Byte[1] = 0x06;  // Checksum and Length
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// 'REG0 Config' - set REG0_EN bit to enable pre-regulator
	TX_3Byte[0] = 0x37; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x01;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// 'REG12 Config' - Enable REG1 with 3.3V output
	TX_3Byte[0] = 0x36; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x0D;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// 'VCell Mode' - Enable 16 cells - 0x9304 = 0x0000  (See TRM section 13.3.2.19)
	// 0x0000 sets the default value of 16 cells.
  TX_4Byte[0] = 0x04; TX_4Byte[1] = 0x93; TX_4Byte[2] = 0x00; TX_4Byte[3] = 0x00;
  I2C_WriteReg(0x3E, TX_4Byte, 4);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_4Byte, 4); TX_2Byte[1] = 0x06;  // Checksum and Length
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// 'Default Alarm Mask' - Enable FullScan and ADScan bits
	// 0xF882
  TX_4Byte[0] = 0x6D; TX_4Byte[1] = 0x92; TX_4Byte[2] = 0x82; TX_4Byte[3] = 0xF8;
  I2C_WriteReg(0x3E, TX_4Byte, 4);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_4Byte, 4); TX_2Byte[1] = 0x06;  // Checksum and Length
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Enable protections in 'Enabled Protections A' 0x9261 = 0xBC (See TRM section 13.3.3.2)
	// Enables SCD (short-circuit), OCD1 (over-current in discharge), OCC (over-current in charge),
	// COV (over-voltage), CUV (under-voltage)
	TX_3Byte[0] = 0x61; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0xFC;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Enable all protections in 'Enabled Protections B' 0x9262 = 0xF7 (See TRM section 13.3.3.3)
	// Enables OTF (over-temperature FET), OTINT (internal over-temperature), OTD (over-temperature in discharge),
	// OTC (over-temperature in charge), UTINT (internal under-temperature), UTD (under-temperature in discharge), UTC (under-temperature in charge)
	TX_3Byte[0] = 0x62; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0xF7;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Set TS1 to measure Cell Temperature - 0x92FD = 0x07   (See TRM Section 13.3.2.12)
	TX_3Byte[0] = 0xFD; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x07;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Set TS3 to measure FET Temperature - 0x92FF = 0x0F   (See TRM Section 13.3.2.14)
	TX_3Byte[0] = 0xFF; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x0F;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Set DFETOFF pin to control BOTH CHG and DSG FET - 0x92FB = 0x42 (set to 0x00 to disable)
	// See TRM section 13.3.2.10, Table 13-7
	TX_3Byte[0] = 0xFB; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x42;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Set up Alert Pin - 0x92FC = 0x2A  - See TRM Section 13.3.2.11, Table 13-8
	// This configures the Alert pin to drive high (REG1 voltage) when enabled.
	// Other options available include active-low, drive HiZ, drive using REG18 (1.8V), weak internal pull-up and pull-down
	TX_3Byte[0] = 0xFC; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x2A;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);


	// Set up Cell Balancing Configuration - 0x9335 = 0x03   -  Automated balancing while in Relax or Charge modes
	// See TRM Section 13.3.11. Chapter 10 of TRM describes Cell Balancing in detail
	// Also see "Cell Balancing with BQ76952, BQ76942 Battery Monitors" document on ti.com
	TX_3Byte[0] = 0x35; TX_3Byte[1] = 0x93; TX_3Byte[2] = 0x03;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Set up COV (over-voltage) Threshold - 0x9278 = 0x55 (4301 mV)
	// COV Threshold is this value multiplied by 50.6mV  See TRM section 13.6.2
	TX_3Byte[0] = 0x78; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x55;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Set up SCD Threshold - 0x9286 = 0x05 (100 mV = 100A across 1mOhm sense resistor)
	// See TRM section 13.6.7    0x05=100mV
	TX_3Byte[0] = 0x86; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x05;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Set up SCD Delay - 0x9287 = 0x03 (30 us)    See TRM section 13.6.7
	// Units of 15us
	TX_3Byte[0] = 0x87; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x03;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);

	// Set up SCDL Latch Limit to 1 to set SCD recovery only with load removal 0x9295 = 0x01
	// If this is not set, then SCD will recover based on time (SCD Recovery Time parameter).
	// See TRM section 13.6.11.1
	TX_3Byte[0] = 0x95; TX_3Byte[1] = 0x92; TX_3Byte[2] = 0x01;
  I2C_WriteReg(0x3E, TX_3Byte, 3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
	delayUS(1000);


	// Exit CONFIGUPDATE mode  - Subcommand 0x0092
	TX_2Byte[0] = 0x92; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
	delayUS(1000);
}

//  ********************************* FET Control Commands  ***************************************

void AFE_FET_ENABLE() {
	// Toggles the FET_EN bit in the Manufacturing Status register. So this command can be used to enable or disable the FETs.
	TX_2Byte[0] = 0x22; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void AFE_FET_Control(uint8_t FET_states) {  // Bit3 = PCHG_OFF, Bit 2 = CHG_OFF, Bit1 = PDSG_OFF, Bit 0 = DSG_OFF
	TX_3Byte[0] = 0x97; TX_3Byte[1] = 0x00; TX_3Byte[2] = FET_states;
	I2C_WriteReg(0x3E,TX_3Byte,3);
	delayUS(1000);
	TX_2Byte[0] = Checksum(TX_3Byte, 3); TX_2Byte[1] = 0x05;
  I2C_WriteReg(0x60, TX_2Byte, 2);
}

void DSG_PDSG_OFF() {
	// Disable discharge (and pre-discharge) FETs
	// Subcommand 0x0093  See TRM Table 5-8  (DSG_PDSG_OFF())
	TX_2Byte[0] = 0x93; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void CHG_PCHG_OFF() {
	// Disable charge (and pre-charge) FETs
	// Subcommand 0x0094  See TRM Table 5-8  (CHG_PCHG_OFF())
	TX_2Byte[0] = 0x94; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void AFE_ALL_FETS_OFF() {
	// Disable all FETs with command 0x0095  See TRM Table 5-8
	TX_2Byte[0] = 0x95; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void AFE_ALL_FETS_ON() {
	// All all FETs to be enabled with command 0x0096  See TRM Table 5-8
	TX_2Byte[0] = 0x96; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void AFE_BOTHOFF () {
	// Disables all FETs using the DFETOFF (BOTHOFF) pin
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);  // DFETOFF pin (BOTHOFF) set low
}

void AFE_RESET_BOTHOFF () {
	// Resets DFETOFF (BOTHOFF) pin
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);  // DFETOFF pin (BOTHOFF) set low
}

void AFE_ReadFETStatus() {
	// Read FET Status to see which FETs are enabled
	I2C_ReadReg(0x7F, RX_2Byte, 2);
  FET_Status = (RX_2Byte[1]*256 + RX_2Byte[0]);
	DCHG = 0x4 & RX_2Byte[0];   // discharge FET state
	CHG = 0x1 & RX_2Byte[0];   // charge FET state
	PCHG = 0x2 & RX_2Byte[0];  // pre-charge FET state
	PDSG = 0x8 & RX_2Byte[0];  // pre-discharge FET state
}



// ********************************* End of FET Control Commands *********************************


// ********************************* AFE Cell Balancing Commands   *****************************************

void CB_ACTIVE_CELLS() {
	// Check status of which cells are balancing
	TX_2Byte[0] = 0x83; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
	I2C_ReadReg(0x40, RX_2Byte, 2);
  CB_ActiveCells = (RX_2Byte[1]*256 + RX_2Byte[0]);
}


// ********************************* End of AFE Cell Balancing Commands   *****************************************


// ********************************* AFE Power Commands   *****************************************
void AFE_DeepSleep() {
	// Puts the device into DEEPSLEEP mode. See TRM section 7.4
	TX_2Byte[0] = 0x0F; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void AFE_ExitDeepSleep() {
	// Exits DEEPSLEEP mode. See TRM section 7.4
	TX_2Byte[0] = 0x0E; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void AFE_ShutdownCommand() {
	// Puts the device into SHUTDOWN mode. See TRM section 7.5
	TX_2Byte[0] = 0x10; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void AFE_ShutdownPin() {
	// Puts the device into SHUTDOWN mode using the RST_SHUT pin
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);  // Sets RST_SHUT pin
}

void AFE_ReleaseShutdownPin() {
	// Releases the RST_SHUT pin
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);  // Resets RST_SHUT pin
}

void AFE_SLEEP_ENABLE() { // SLEEP_ENABLE 0x0099
	// Allows the device to enter Sleep mode if current is below Sleep Current. See TRM section 7.3
	TX_2Byte[0] = 0x99; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

void AFE_SLEEP_DISABLE() { // SLEEP_DISABLE 0x009A
	// Takes the device out of sleep mode. See TRM section 7.3
	TX_2Byte[0] = 0x9A; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

// ********************************* End of AFE Power Commands   *****************************************


// ********************************* AFE Status and Fault Commands   *****************************************

uint16_t AFE_ReadAlarmStatus() {
	// Read this register to find out why the Alert pin was asserted. See section 6.6 of the TRM for full description.
	I2C_ReadReg(0x62, RX_2Byte, 2);
	return (RX_2Byte[1]*256 + RX_2Byte[0]);
}

void AFE_ReadSafetyStatus() {
	// Read Safety Status A/B/C and find which bits are set
	// This shows which primary protections have been triggered
	I2C_ReadReg(0x03, RX_2Byte, 2);
	SafetyStatusA = (RX_2Byte[1]*256 + RX_2Byte[0]);
	UV_Fault = 0x4 & RX_2Byte[0];
	OV_Fault = 0x8 & RX_2Byte[0];
	SCD_Fault = 0x8 & RX_2Byte[1];
	OCD_Fault = 0x2 & RX_2Byte[1];
	I2C_ReadReg(0x05, RX_2Byte, 2);
	SafetyStatusB = (RX_2Byte[1]*256 + RX_2Byte[0]);
	I2C_ReadReg(0x07, RX_2Byte, 2);
	SafetyStatusC = (RX_2Byte[1]*256 + RX_2Byte[0]);
}

void AFE_ReadPFStatus() {
	// Read Permanent Fail Status A/B/C and find which bits are set
	// This shows which permanent failures have been triggered
	I2C_ReadReg(0x0B, RX_2Byte, 2);
	PFStatusA = (RX_2Byte[1]*256 + RX_2Byte[0]);
	I2C_ReadReg(0x0D, RX_2Byte, 2);
	PFStatusB = (RX_2Byte[1]*256 + RX_2Byte[0]);
	I2C_ReadReg(0x0F, RX_2Byte, 2);
	PFStatusC = (RX_2Byte[1]*256 + RX_2Byte[0]);
}


void AFE_ControlStatus() {
	// Control status register - Bit0 - LD_ON (load detected)
	// See TRM Table 6-1
	I2C_ReadReg(0x00, RX_2Byte, 2);
  LD_ON = 0x1 & RX_2Byte[0];
}

void AFE_BatteryStatus() {
	// Battery status register - See TRM Table 6-2
	I2C_ReadReg(0x12, RX_2Byte, 2);
}

void AFE_ClearFaults() {
	TX_2Byte[0] = 0x00; TX_2Byte[1] = 0xF8;
	I2C_WriteReg(0x62,TX_2Byte,2);
}

void AFE_ClearScanBits() {
	TX_2Byte[0] = 0x82; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x62,TX_2Byte,2);
}

void AFE_PFReset() {
	TX_2Byte[0] = 0x29; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

uint16_t AFE_DeviceID() {
	// Read Device ID using Subcommand 0x0001
	TX_2Byte[0] = 0x01; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
	delayUS(500);
	I2C_ReadReg(0x40, RX_2Byte, 2);
	return (RX_2Byte[1]*256 + RX_2Byte[0]);
}
// ********************************* End of AFE Status and Fault Commands   *****************************************


// ********************************* AFE Measurement Commands   *****************************************

uint16_t AFE_ReadCellVoltage(uint8_t channel) {
	I2C_ReadReg(channel*2+0x12, RX_2Byte, 2);
	return (RX_2Byte[1]*256 + RX_2Byte[0]);     // cell voltage is reported in mV
}

uint16_t AFE_ReadStackVoltage() {
	I2C_ReadReg(0x34, RX_2Byte, 2);
	return 10 * (RX_2Byte[1]*256 + RX_2Byte[0]);  // voltage is reported in 0.01V units
}

uint16_t AFE_ReadPackVoltage() {
	I2C_ReadReg(0x36, RX_2Byte, 2);
	return 10 * (RX_2Byte[1]*256 + RX_2Byte[0]);  // voltage is reported in 0.01V units
}

uint16_t AFE_ReadLDVoltage() {
	I2C_ReadReg(0x38, RX_2Byte, 2);
	return 10 * (RX_2Byte[1]*256 + RX_2Byte[0]);  // voltage is reported in 0.01V units
}

uint16_t AFE_ReadCurrent() {
	I2C_ReadReg(0x3A, RX_2Byte, 2);
	return (RX_2Byte[1]*256 + RX_2Byte[0]);  // current is reported in mA
}



float AFE_ReadTemperature(uint8_t channel) {
	switch(channel)
	{
		case 0:
			I2C_ReadReg(0x70, RX_2Byte, 2);  // TS1 pin
			break;
		case 1:
			I2C_ReadReg(0x74, RX_2Byte, 2);  // TS3 pin, FET temperature
			break;
		default: break;
	}
	return (0.1 * (float)(RX_2Byte[1]*256 + RX_2Byte[0])) - 273.15;  // convert from 0.1K to Celcius
}


void AFE_ReadPassQ() {
	// Read Accumulated Charge and Time from DASTATUS6 (See TRM Table 4-6)
	TX_2Byte[0] = 0x76; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
	delayUS(1000);
	I2C_ReadReg(0x40, RX_12Byte, 12);
	AccumulatedCharge_Int = ((RX_12Byte[3]<<24) + (RX_12Byte[2]<<16) + (RX_12Byte[1]<<8) + RX_12Byte[0]);
	AccumulatedCharge_Frac = ((RX_12Byte[7]<<24) + (RX_12Byte[6]<<16) + (RX_12Byte[5]<<8) + RX_12Byte[4]);
	AccumulatedCharge_Time = ((RX_12Byte[11]<<24) + (RX_12Byte[10]<<16) + (RX_12Byte[9]<<8) + RX_12Byte[8]);
}

void AFE_ClearPassQ() {
	// Clear Accumulated Charge and Time, command 0x0082
	TX_2Byte[0] = 0x82; TX_2Byte[1] = 0x00;
	I2C_WriteReg(0x3E,TX_2Byte,2);
}

// *********************************
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint8_t	I2C_Return;
  /* USER CODE END 1 */
	volatile int i = 0;
	char uart_buf[50];
	int uart_buf_len;
  /* USER CODE END 1 */
	uint16_t CellVoltage1 =0;
  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_TIM1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start(&htim1);

  	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);  // RST_SHUT pin set low
  	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);  // DFETOFF pin (BOTHOFF) set low
      delayUS(10000);


  	AFE_Reset();
  	delayUS(60000);
  	AFE_Init();
  	delayUS(10000);
  	AFE_FET_ENABLE();
  	delayUS(10000);

  	AFE_SLEEP_DISABLE();

  	delayUS(60000); delayUS(60000); delayUS(60000); delayUS(60000);  //wait to start measurements after FETs close
  	CellVoltage[1] = AFE_ReadCellVoltage(1);
  	CellVoltage[5] = AFE_ReadCellVoltage(5);
  	CellVoltage[10] = AFE_ReadCellVoltage(10);
  	Stack_Voltage = AFE_ReadStackVoltage();
  	PACK_Voltage = AFE_ReadPackVoltage();
  	LD_Voltage = AFE_ReadLDVoltage();
  	PACK_Current = AFE_ReadCurrent();
  	Temperature[0] = AFE_ReadTemperature(0)m   ;
  	FET_Temperature = AFE_ReadTemperature(1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  CellVoltage1 =0;
    /* USER CODE END WHILE */
	  CellVoltage1 = AFE_ReadCellVoltage(1);
	  Stack_Voltage = AFE_ReadStackVoltage();
	//Debug code - prints the Cell1 Voltage to a terminal window
	uart_buf_len = sprintf(uart_buf, "%u mV\r\n", Temperature[1] );
	HAL_UART_Transmit(&huart1, (uint8_t *)uart_buf, uart_buf_len, 100);
	CellVoltage1 =0;
	CellVoltage[2] = AFE_ReadCellVoltage(2);

	CellVoltage[3] = AFE_ReadCellVoltage(3);
	CellVoltage[4] = AFE_ReadCellVoltage(4);
	CellVoltage[5] = AFE_ReadCellVoltage(5);
	CellVoltage[6] = AFE_ReadCellVoltage(6);
	CellVoltage[7] = AFE_ReadCellVoltage(7);
	CellVoltage[8] = AFE_ReadCellVoltage(8);
	CellVoltage[9] = AFE_ReadCellVoltage(9);
	CellVoltage[10] = AFE_ReadCellVoltage(10);
	//Stack_Voltage = AFE_ReadStackVoltage();
	PACK_Voltage = AFE_ReadPackVoltage();
	LD_Voltage = AFE_ReadLDVoltage();
	PACK_Current = AFE_ReadCurrent();
	Temperature[0] = AFE_ReadTemperature(2);
	FET_Temperature = AFE_ReadTemperature(1);

	AlarmBits = AFE_ReadAlarmStatus();
	//Debug code - prints the Cell1 Voltage to a terminal window
	// 		uart_buf_len = sprintf(uart_buf, "%u \r\n", AlarmBits);
	//	HAL_UART_Transmit(&huart1, (uint8_t *)uart_buf, uart_buf_len, 100);

	if (AlarmBits & 0x82) {
		AFE_ClearScanBits();
	}

	if (AlarmBits & 0xC000) {
		AFE_ReadSafetyStatus();
		AFE_ReadPFStatus();
		AFE_ClearFaults();
		AFE_PFReset();
	}
	CellVoltage1 =0;
	HAL_Delay(500);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL8;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{


	  /* USER CODE BEGIN I2C1_Init 0 */

	  /* USER CODE END I2C1_Init 0 */

	  /* USER CODE BEGIN I2C1_Init 1 */

	  /* USER CODE END I2C1_Init 1 */
	  hi2c1.Instance = I2C1;
	  hi2c1.Init.ClockSpeed = 400000;
	  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
	  hi2c1.Init.OwnAddress1 = 0;
	  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
	  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
	  hi2c1.Init.OwnAddress2 = 0;
	  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
	  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
	  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
	  {
	    Error_Handler();
	  }
	  /* USER CODE BEGIN I2C1_Init 2 */

	  /* USER CODE END I2C1_Init 2 */

}

/**
  * @brief TIM1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM1_Init(void)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 63;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 65535;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */

  /* USER CODE END TIM1_Init 2 */

}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);

  /*Configure GPIO pin : PC13 */
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */
void HAL_GPIO_EXTI_Callback ( uint16_t GPIO_Pin )
{
	if ( GPIO_Pin == GPIO_PIN_3 ) {
		HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_5 );
	}
	else {
		__NOP ();
	}
}
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

I am awating for you replay..

thanks.

  • Dear Arjun,

    I have a few quick questions:

    1. Can you send the full schematic of the PCB?

    2. For the photos of the signal, can you use an digital logic analyzer to view the signal so we can see what is being sent as well as whether an ACK bit is received.

    3. Is your device using CRC checks for transmission? The BQ7695202 by default has CRC enabled it that would change the signals you send and receive if your MCU isn't expecting the CRC to be there.

    Best,

    Asher Nederveld

  • THANK YOU FOR REPLAY SIR,

    1. Ok sir I will attached.

    2. No sir I do not have logic analyzer except oscilloscope.

    3. I was unware about that BQ7695202 by default has CRC enabled and in program I have disable the same. this may be the reason , I will try the same and  revert you back for same perspective.

    # sir now I able to the to read the all data but i can't able to write anything in BQ7xxx

    this is example i am doing in main function and trying to read the COV threshold voltage after write , but it is only showing me default data, there is no change in cov register

    /////////////////////////////////////////////////COV -THS-73///////////////////////////////////////////////////////////

    // Enter CONFIGUPDATE mode - Subcommand 0x0090
    TX_2Byte[0] = 0x90;
    TX_2Byte[1] = 0x00;
    I2C_WriteReg(0x3E,TX_2Byte,2);
    delayUS(2000);

    //0x9278 is address and  0x55 is data

    TX_3Byte[0] = 0x78;
    TX_3Byte[1] = 0x92;
    TX_3Byte[2] = 0x50;    
    I2C_WriteReg(0x3E, TX_3Byte, 3);
    delayUS(1000);

    //for checksum and length

    TX_2Byte[0] = Checksum(TX_3Byte, 3);
    TX_2Byte[1] = 0x05;
    I2C_WriteReg(0x60, TX_2Byte, 2);
    Read_cov_th = (RX_2Byte[1]*256 + RX_2Byte[0]);
    delayUS(1000);


    // Exit CONFIGUPDATE mode - Subcommand 0x0092
    TX_2Byte[0] = 0x92; TX_2Byte[1] = 0x00;
    I2C_WriteReg(0x3E,TX_2Byte,2);
    delayUS(1000);

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////

  • /////////////////////////////////////////////////COV -THS-73///////////////////////////////////////////////////////////
    TX_2Byte[0] = 0x90;
    TX_2Byte[1] = 0x00;
    I2C_WriteReg(0x3E,TX_2Byte,2);
    delayUS(2000);

    // 1. Write lower byte of address to 0x3E (0x78 in this example).
    // 2. Write upper byte of address to 0x3F (0x92 in this example).
    // 3. Write the data memory value in little endian format into the transfer buffer (0x40 to 0x5F). Note: up to 32
    // bytes of data memory can be written in one block write. In this example, write 0x7A to 0x40, write 0x30 to
    // 0x41.
    // 4. Write the checksum of data written (0x44 in this example) into 0x60, and the length of data (0x06 in this
    // example) into 0x61.

    TX_3Byte[0] = 0x78;
    TX_3Byte[1] = 0x92;
    TX_3Byte[2] = 0x10;
    I2C_WriteReg(0x3E, TX_3Byte, 3);
    delayUS(1000);
    TX_2Byte[0] = Checksum(TX_3Byte, 3);
    TX_2Byte[1] = 0x05;
    I2C_WriteReg(0x60, TX_2Byte, 2);
    delayUS(1000);

    // 5. The data can be verified by reading it back. Write the lower byte of address to 0x3E (0x80), write the upper
    // byte of address to 0x3F (0x91).
    // 6. Read the length of response from 0x61. The transfer buffer will be populated with a 32-byte block of data, so
    // length will be 36-bytes, or 0x24 for this example.
    // 7. Read buffer starting at 0x40 for the length of data. The new value for Calibration:Voltage:Cell 1 Gain is
    // seen in 0x40 (0x7A) and 0x41 (0x30).
    // 8. Read the checksum at 0x60 and verify it matches the data read for the full transfer buffer

    TX_2Byte[0] = 0x00;
    TX_2Byte[1] = 0x00;
    I2C_ReadReg(0x40, TX_2Byte, 2);
    CB_ActiveCells = (RX_2Byte[1]*256 + RX_2Byte[0]);
    delayUS(1000);


    // Exit CONFIGUPDATE mode - Subcommand 0x0092
    TX_2Byte[0] = 0x92; TX_2Byte[1] = 0x00;
    I2C_WriteReg(0x3E,TX_2Byte,2);
    delayUS(1000);

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////

  • #1 CB_ActiveCells using as variable

    #2 iIn comment section of code i have did some changes for my reff...

  • Dear Arjun,

    Can you confirm that your device is entering CONFIG_UPDATE mode by checking the 0x12 Battery Status()[CFGUPDATE] flag? In order to enter CONFIG_UPDATE mode, your device needs be in FULLACCESS mode. There is a chance your device is in SEALED or UNSEALED mode which allows reads but not writes. This can be verified by viewing 0x12 Battery Status()[SEC1, SEC0] and seeing if they are [0,1], meaning the device is in FULLACCESS. For more information on this setting, you can view section 8.1 in the TRM.

    Best,

    Asher Nederveld

  • HELLO SIR,

    I CHECKED THAT BIT Status()[SEC1, SEC0]  WHICH THAT ALREADY SET AS  [0,1] (WHICH IS 8 AND 9 BIT)  STILL I CANT ABLE TO ASSCESS THE  WRITE  OPERATION. 

    ONE THING MORE I WANT TO MENTION HERE IS THAT , AS SHOW HERE TO TWO CODE AVALIABLE IN TI SITE FOR THE SAME (OLDER AND NEW ONE ) BY NEW ONE I CANT ABLE TO READ ANY THING AND BY OLDER ONE , SAME WAS THE ISSUSE WITH THAT BUT ONE PLUS POINT WAS THAT ONLY I WAS ABLE TO RAED  THE "STACK VOLTAGE"  ONELY AND BY USING THE SAME FUNCTION AFTER SOME CHANGES (BECAUSE ITS WORKING FINE SO I USED THAT SAME FUNCTION TO READ THE OTHER DATA (EG.TEMP,CELL1-CELL16) )   

    I REALLY DON'T KNOW WHAT GOING ON AND I REQUESTED TO PLEASE IF YOU HAVE  PROVIDE ME SIMPLE CODE TO READ AND WRITE OPERATION EITHER THEN PLEASE GUIDE ME BY STEPS;

    THANKS.

  •    

    THIS OUTPUT RESULT , WHEN I DEBUGE WITH NEW(ATTACHED BELOW) CODE. BY THIS I CANT ABLE TO READ THE TS1 EVEN, 

    AND I RECHECK EVERY THING TWISE BUT NO RESULT I GOTTED,

    #include "main.h"
    #include <stdio.h>
    #include "BQ769x2Header.h"
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    
    /* USER CODE END Includes */
    
    /* Private typedef -----------------------------------------------------------*/
    /* USER CODE BEGIN PTD */
    #define DEV_ADDR  0x10  // BQ769x2 address is 0x10 including R/W bit or 0x8 as 7-bit address
    #define CRC_Mode 1  // 0 for disabled, 1 for enabled
    #define MAX_BUFFER_SIZE 10
    #define R 0 // Read; Used in DirectCommands and Subcommands functions
    #define W 1 // Write; Used in DirectCommands and Subcommands functions
    #define W2 2 // Write data with two bytes; Used in Subcommands function
    /* USER CODE END PTD */
    
    /* Private define ------------------------------------------------------------*/
    /* USER CODE BEGIN PD */
    /* USER CODE END PD */
    
    /* Private macro -------------------------------------------------------------*/
    /* USER CODE BEGIN PM */
    
    /* USER CODE END PM */
    
    /* Private variables ---------------------------------------------------------*/
    I2C_HandleTypeDef hi2c1;
    
    TIM_HandleTypeDef htim1;
    
    UART_HandleTypeDef huart1;
    
    /* USER CODE BEGIN PV */
    uint8_t RX_data [2] = {0x00, 0x00}; // used in several functions to store data read from BQ769x2
    uint8_t RX_32Byte [32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    	//used in Subcommands read function
    // Global Variables for cell voltages, temperatures, Stack voltage, PACK Pin voltage, LD Pin voltage, CC2 current
    uint16_t CellVoltage [16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    float Temperature [3] = {0,0,0};
    uint16_t Stack_Voltage = 0x00;
    uint16_t Pack_Voltage = 0x00;
    uint16_t LD_Voltage = 0x00;
    uint16_t Pack_Current = 0x00;
    
    uint16_t AlarmBits = 0x00;
    uint8_t value_SafetyStatusA;  // Safety Status Register A
    uint8_t value_SafetyStatusB;  // Safety Status Register B
    uint8_t value_SafetyStatusC;  // Safety Status Register C
    uint8_t value_PFStatusA;   // Permanent Fail Status Register A
    uint8_t value_PFStatusB;   // Permanent Fail Status Register B
    uint8_t value_PFStatusC;   // Permanent Fail Status Register C
    uint8_t FET_Status;  // FET Status register contents  - Shows states of FETs
    uint16_t CB_ActiveCells;  // Cell Balancing Active Cells
    
    uint8_t	UV_Fault = 0;   // under-voltage fault state
    uint8_t	OV_Fault = 0;   // over-voltage fault state
    uint8_t	SCD_Fault = 0;  // short-circuit fault state
    uint8_t	OCD_Fault = 0;  // over-current fault state
    uint8_t ProtectionsTriggered = 0; // Set to 1 if any protection triggers
    
    uint8_t LD_ON = 0;	// Load Detect status bit
    uint8_t DSG = 0;   // discharge FET state
    uint8_t CHG = 0;   // charge FET state
    uint8_t PCHG = 0;  // pre-charge FET state
    uint8_t PDSG = 0;  // pre-discharge FET state
    
    uint32_t AccumulatedCharge_Int; // in BQ769x2_READPASSQ func
    uint32_t AccumulatedCharge_Frac;// in BQ769x2_READPASSQ func
    uint32_t AccumulatedCharge_Time;// in BQ769x2_READPASSQ func
    /* USER CODE END PV */
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    static void MX_GPIO_Init(void);
    static void MX_I2C1_Init(void);
    static void MX_TIM1_Init(void);
    static void MX_USART1_UART_Init(void);
    /* USER CODE BEGIN PFP */
    
    /* USER CODE END PFP */
    
    
    void delayUS(uint32_t us) {   // Sets the delay in microseconds.
    	__HAL_TIM_SET_COUNTER(&htim1,0);  // set the counter value a 0
    	while (__HAL_TIM_GET_COUNTER(&htim1) < us);  // wait for the counter to reach the us input in the parameter
    }
    
    void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
    {
        uint8_t copyIndex = 0;
        for (copyIndex = 0; copyIndex < count; copyIndex++)
        {
            dest[copyIndex] = source[copyIndex];
        }
    }
    
    unsigned char Checksum(unsigned char *ptr, unsigned char len)
    // Calculates the checksum when writing to a RAM register. The checksum is the inverse of the sum of the bytes.
    {
    	unsigned char i;
    	unsigned char checksum = 0;
    
    	for(i=0; i<len; i++)
    		checksum += ptr[i];
    
    	checksum = 0xff & ~checksum;
    
    	return(checksum);
    }
    
    unsigned char CRC8(unsigned char *ptr, unsigned char len)
    //Calculates CRC8 for passed bytes. Used in i2c read and write functions
    {
    	unsigned char i;
    	unsigned char crc=0;
    	while(len--!=0)
    	{
    		for(i=0x80; i!=0; i/=2)
    		{
    			if((crc & 0x80) != 0)
    			{
    				crc *= 2;
    				crc ^= 0x107;
    			}
    			else
    				crc *= 2;
    
    			if((*ptr & i)!=0)
    				crc ^= 0x107;
    		}
    		ptr++;
    	}
    	return(crc);
    }
    
    void I2C_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
    {
    	uint8_t TX_Buffer [MAX_BUFFER_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    #if CRC_Mode
    	{
    		uint8_t crc_count = 0;
    		crc_count = count * 2;
    		uint8_t crc1stByteBuffer [3] = {0x10, reg_addr, reg_data[0]};
    		unsigned int j;
    		unsigned int i;
    		uint8_t temp_crc_buffer [3];
    
    		TX_Buffer[0] = reg_data[0];
    		TX_Buffer[1] = CRC8(crc1stByteBuffer,3);
    
    		j = 2;
    		for(i=1; i<count; i++)
    		{
    			TX_Buffer[j] = reg_data[i];
    			j = j + 1;
    			temp_crc_buffer[0] = reg_data[i];
    			TX_Buffer[j] = CRC8(temp_crc_buffer,1);
    			j = j + 1;
    		}
    		HAL_I2C_Mem_Write(&hi2c1, DEV_ADDR, reg_addr, 1, TX_Buffer, crc_count, 1000);
    	}
    #else
    	HAL_I2C_Mem_Write(&hi2c1, DEV_ADDR, reg_addr, 1, reg_data, count, 1000);
    #endif
    }
    
    int I2C_ReadReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
    {
    	unsigned int RX_CRC_Fail = 0;  // reset to 0. If in CRC Mode and CRC fails, this will be incremented.
    	uint8_t RX_Buffer [MAX_BUFFER_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    #if CRC_Mode
    	{
    		uint8_t crc_count = 0;
    		uint8_t ReceiveBuffer [10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    		crc_count = count * 2;
    		unsigned int j;
    		unsigned int i;
    		unsigned char CRCc = 0;
    		uint8_t temp_crc_buffer [3];
    
    		HAL_I2C_Mem_Read(&hi2c1, DEV_ADDR, reg_addr, 1, ReceiveBuffer, crc_count, 1000);
    		uint8_t crc1stByteBuffer [4] = {0x10, reg_addr, 0x11, ReceiveBuffer[0]};
    		CRCc = CRC8(crc1stByteBuffer,4);
    		if (CRCc != ReceiveBuffer[1])
    		{
    			RX_CRC_Fail += 1;
    		}
    		RX_Buffer[0] = ReceiveBuffer[0];
    
    		j = 2;
    		for (i=1; i<count; i++)
    		{
    			RX_Buffer[i] = ReceiveBuffer[j];
    			temp_crc_buffer[0] = ReceiveBuffer[j];
    			j = j + 1;
    			CRCc = CRC8(temp_crc_buffer,1);
    			if (CRCc != ReceiveBuffer[j])
    				RX_CRC_Fail += 1;
    			j = j + 1;
    		}
    		CopyArray(RX_Buffer, reg_data, crc_count);
    	}
    #else
    	HAL_I2C_Mem_Read(&hi2c1, DEV_ADDR, reg_addr, 1, reg_data, count, 1000);
    #endif
    	return 0;
    }
    
    void BQ769x2_SetRegister(uint16_t reg_addr, uint32_t reg_data, uint8_t datalen)
    {
    	uint8_t TX_Buffer[2] = {0x00, 0x00};
    	uint8_t TX_RegData[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    
    	//TX_RegData in little endian format
    	TX_RegData[0] = reg_addr & 0xff;
    	TX_RegData[1] = (reg_addr >> 8) & 0xff;
    	TX_RegData[2] = reg_data & 0xff; //1st byte of data
    
    	switch(datalen)
        {
    		case 1: //1 byte datalength
          		I2C_WriteReg(0x3E, TX_RegData, 3);
    			delayUS(2000);
    			TX_Buffer[0] = Checksum(TX_RegData, 3);
    			TX_Buffer[1] = 0x05; //combined length of register address and data
          		I2C_WriteReg(0x60, TX_Buffer, 2); // Write the checksum and length
    			delayUS(2000);
    			break;
    		case 2: //2 byte datalength
    			TX_RegData[3] = (reg_data >> 8) & 0xff;
    			I2C_WriteReg(0x3E, TX_RegData, 4);
    			delayUS(2000);
    			TX_Buffer[0] = Checksum(TX_RegData, 4);
    			TX_Buffer[1] = 0x06; //combined length of register address and data
          		I2C_WriteReg(0x60, TX_Buffer, 2); // Write the checksum and length
    			delayUS(2000);
    			break;
    		case 4: //4 byte datalength, Only used for CCGain and Capacity Gain
    			TX_RegData[3] = (reg_data >> 8) & 0xff;
    			TX_RegData[4] = (reg_data >> 16) & 0xff;
    			TX_RegData[5] = (reg_data >> 24) & 0xff;
    			I2C_WriteReg(0x3E, TX_RegData, 6);
    			delayUS(2000);
    			TX_Buffer[0] = Checksum(TX_RegData, 6);
    			TX_Buffer[1] = 0x08; //combined length of register address and data
          		I2C_WriteReg(0x60, TX_Buffer, 2); // Write the checksum and length
    			delayUS(2000);
    			break;
        }
    }
    
    void CommandSubcommands(uint16_t command) //For Command only Subcommands
    // See the TRM or the BQ76952 header file for a full list of Command-only subcommands
    {	//For DEEPSLEEP/SHUTDOWN subcommand you will need to call this function twice consecutively
    
    	uint8_t TX_Reg[2] = {0x00, 0x00};
    
    	//TX_Reg in little endian format
    	TX_Reg[0] = command & 0xff;
    	TX_Reg[1] = (command >> 8) & 0xff;
    
    	I2C_WriteReg(0x3E,TX_Reg,2);
    	delayUS(2000);
    }
    
    void Subcommands(uint16_t command, uint16_t data, uint8_t type)
    // See the TRM or the BQ76952 header file for a full list of Subcommands
    {
    	//security keys and Manu_data writes dont work with this function (reading these commands works)
    	//max readback size is 32 bytes i.e. DASTATUS, CUV/COV snapshot
    	uint8_t TX_Reg[4] = {0x00, 0x00, 0x00, 0x00};
    	uint8_t TX_Buffer[2] = {0x00, 0x00};
    
    	//TX_Reg in little endian format
    	TX_Reg[0] = command & 0xff;
    	TX_Reg[1] = (command >> 8) & 0xff;
    
    	if (type == R) {//read
    		I2C_WriteReg(0x3E,TX_Reg,2);
    		delayUS(2000);
    		I2C_ReadReg(0x40, RX_32Byte, 32); //RX_32Byte is a global variable
    	}
    	else if (type == W) {
    		//FET_Control, REG12_Control
    		TX_Reg[2] = data & 0xff;
    		I2C_WriteReg(0x3E,TX_Reg,3);
    		delayUS(1000);
    		TX_Buffer[0] = Checksum(TX_Reg, 3);
    		TX_Buffer[1] = 0x05; //combined length of registers address and data
    		I2C_WriteReg(0x60, TX_Buffer, 2);
    		delayUS(1000);
    	}
    	else if (type == W2){ //write data with 2 bytes
    		//CB_Active_Cells, CB_SET_LVL
    		TX_Reg[2] = data & 0xff;
    		TX_Reg[3] = (data >> 8) & 0xff;
    		I2C_WriteReg(0x3E,TX_Reg,4);
    		delayUS(1000);
    		TX_Buffer[0] = Checksum(TX_Reg, 4);
    		TX_Buffer[1] = 0x06; //combined length of registers address and data
    		I2C_WriteReg(0x60, TX_Buffer, 2);
    		delayUS(1000);
    	}
    }
    
    void DirectCommands(uint8_t command, uint16_t data, uint8_t type)
    // See the TRM or the BQ76952 header file for a full list of Direct Commands
    {	//type: R = read, W = write
    	uint8_t TX_data[2] = {0x00, 0x00};
    
    	//little endian format
    	TX_data[0] = data & 0xff;
    	TX_data[1] = (data >> 8) & 0xff;
    
    	if (type == R) {//Read
    		I2C_ReadReg(command, RX_data, 2); //RX_data is a global variable
    		delayUS(2000);
    	}
    	if (type == W) {//write
        //Control_status, alarm_status, alarm_enable all 2 bytes long
    		I2C_WriteReg(command,TX_data,2);
    		delayUS(2000);
    	}
    }
    
    void BQ769x2_Init() {
    	// Configures all parameters in device RAM
    
    	// Enter CONFIGUPDATE mode (Subcommand 0x0090) - It is required to be in CONFIG_UPDATE mode to program the device RAM settings
    	// See TRM for full description of CONFIG_UPDATE mode
    	CommandSubcommands(SET_CFGUPDATE);
    
    	// After entering CONFIG_UPDATE mode, RAM registers can be programmed. When programming RAM, checksum and length must also be
    	// programmed for the change to take effect. All of the RAM registers are described in detail in the BQ769x2 TRM.
    	// An easier way to find the descriptions is in the BQStudio Data Memory screen. When you move the mouse over the register name,
    	// a full description of the register and the bits will pop up on the screen.
    
    	// 'Power Config' - 0x9234 = 0x2D80
    	// Setting the DSLP_LDO bit allows the LDOs to remain active when the device goes into Deep Sleep mode
      	// Set wake speed bits to 00 for best performance
    	BQ769x2_SetRegister(PowerConfig, 0x2D80, 2);
    
    	// 'REG0 Config' - set REG0_EN bit to enable pre-regulator
    	BQ769x2_SetRegister(REG0Config, 0x01, 1);
    
    	// 'REG12 Config' - Enable REG1 with 3.3V output (0x0D for 3.3V, 0x0F for 5V)
    	BQ769x2_SetRegister(REG12Config, 0x0D, 1);
    
    	// Set DFETOFF pin to control BOTH CHG and DSG FET - 0x92FB = 0x42 (set to 0x00 to disable)
    	BQ769x2_SetRegister(DFETOFFPinConfig, 0x42, 1);
    
    	// Set up ALERT Pin - 0x92FC = 0x2A
    	// This configures the ALERT pin to drive high (REG1 voltage) when enabled.
    	// The ALERT pin can be used as an interrupt to the MCU when a protection has triggered or new measurements are available
    	BQ769x2_SetRegister(ALERTPinConfig, 0x2A, 1);
    
    	// Set TS1 to measure Cell Temperature - 0x92FD = 0x07
    	BQ769x2_SetRegister(TS1Config, 0x07, 1);
    
    	// Set TS3 to measure FET Temperature - 0x92FF = 0x0F
    	BQ769x2_SetRegister(TS3Config, 0x0F, 1);
    
    	// Set HDQ to measure Cell Temperature - 0x9300 = 0x07
    	BQ769x2_SetRegister(HDQPinConfig, 0x00, 1);  // No thermistor installed on EVM HDQ pin, so set to 0x00
    
    	// 'VCell Mode' - Enable 16 cells - 0x9304 = 0x0000; Writing 0x0000 sets the default of 16 cells
    	BQ769x2_SetRegister(VCellMode, 0x0000, 2);
    
    	// Enable protections in 'Enabled Protections A' 0x9261 = 0xBC
    	// Enables SCD (short-circuit), OCD1 (over-current in discharge), OCC (over-current in charge),
    	// COV (over-voltage), CUV (under-voltage)
    	BQ769x2_SetRegister(EnabledProtectionsA, 0xBC, 1);
    
    	// Enable all protections in 'Enabled Protections B' 0x9262 = 0xF7
    	// Enables OTF (over-temperature FET), OTINT (internal over-temperature), OTD (over-temperature in discharge),
    	// OTC (over-temperature in charge), UTINT (internal under-temperature), UTD (under-temperature in discharge), UTC (under-temperature in charge)
    	BQ769x2_SetRegister(EnabledProtectionsB, 0xF7, 1);
    
    	// 'Default Alarm Mask' - 0x..82 Enables the FullScan and ADScan bits, default value = 0xF800
    	BQ769x2_SetRegister(DefaultAlarmMask, 0xF882, 2);
    
    	// Set up Cell Balancing Configuration - 0x9335 = 0x03   -  Automated balancing while in Relax or Charge modes
    	// Also see "Cell Balancing with BQ769x2 Battery Monitors" document on ti.com
    	BQ769x2_SetRegister(BalancingConfiguration, 0x03, 1);
    
    	// Set up CUV (under-voltage) Threshold - 0x9275 = 0x31 (2479 mV)
    	// CUV Threshold is this value multiplied by 50.6mV
    	BQ769x2_SetRegister(CUVThreshold, 0x31, 1);
    
    	// Set up COV (over-voltage) Threshold - 0x9278 = 0x55 (4301 mV)
    	// COV Threshold is this value multiplied by 50.6mV
    	BQ769x2_SetRegister(COVThreshold, 0x55, 1);
    
    	// Set up OCC (over-current in charge) Threshold - 0x9280 = 0x05 (10 mV = 10A across 1mOhm sense resistor) Units in 2mV
    	BQ769x2_SetRegister(OCCThreshold, 0x05, 1);
    
    	// Set up OCD1 Threshold - 0x9282 = 0x0A (20 mV = 20A across 1mOhm sense resistor) units of 2mV
    	BQ769x2_SetRegister(OCD1Threshold, 0x0A, 1);
    
    	// Set up SCD Threshold - 0x9286 = 0x05 (100 mV = 100A across 1mOhm sense resistor)  0x05=100mV
    	BQ769x2_SetRegister(SCDThreshold, 0x05, 1);
    
    	// Set up SCD Delay - 0x9287 = 0x03 (30 us) Enabled with a delay of (value - 1) * 15 µs; min value of 1
    	BQ769x2_SetRegister(SCDDelay, 0x03, 1);
    
    	// Set up SCDL Latch Limit to 1 to set SCD recovery only with load removal 0x9295 = 0x01
    	// If this is not set, then SCD will recover based on time (SCD Recovery Time parameter).
    	BQ769x2_SetRegister(SCDLLatchLimit, 0x01, 1);
    
    	// Exit CONFIGUPDATE mode  - Subcommand 0x0092
    	CommandSubcommands(EXIT_CFGUPDATE);
    }
    
    //  ********************************* FET Control Commands  ***************************************
    
    void BQ769x2_BOTHOFF () {
    	// Disables all FETs using the DFETOFF (BOTHOFF) pin
    	// The DFETOFF pin on the BQ76952EVM should be connected to the MCU board to use this function
    //	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);  // DFETOFF pin (BOTHOFF) set high
    }
    
    void BQ769x2_RESET_BOTHOFF () {
    	// Resets DFETOFF (BOTHOFF) pin
    	// The DFETOFF pin on the BQ76952EVM should be connected to the MCU board to use this function
    	//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);  // DFETOFF pin (BOTHOFF) set low
    }
    
    void BQ769x2_ReadFETStatus() {
    	// Read FET Status to see which FETs are enabled
    	DirectCommands(FETStatus, 0x00, R);
    	FET_Status = (RX_data[1]*256 + RX_data[0]);
    	DSG = ((0x4 & RX_data[0])>>2);// discharge FET state
      	CHG = (0x1 & RX_data[0]);// charge FET state
      	PCHG = ((0x2 & RX_data[0])>>1);// pre-charge FET state
      	PDSG = ((0x8 & RX_data[0])>>3);// pre-discharge FET state
    }
    
    // ********************************* End of FET Control Commands *********************************
    
    // ********************************* BQ769x2 Power Commands   *****************************************
    
    void BQ769x2_ShutdownPin() {
    	// Puts the device into SHUTDOWN mode using the RST_SHUT pin
    	// The RST_SHUT pin on the BQ76952EVM should be connected to the MCU board to use this function
    	//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);  // Sets RST_SHUT pin
    }
    
    void BQ769x2_ReleaseShutdownPin() {
    	// Releases the RST_SHUT pin
    	// The RST_SHUT pin on the BQ76952EVM should be connected to the MCU board to use this function
    	//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);  // Resets RST_SHUT pin
    }
    
    // ********************************* End of BQ769x2 Power Commands   *****************************************
    
    
    // ********************************* BQ769x2 Status and Fault Commands   *****************************************
    
    
    
    void BQ769x2_ReadSafetyStatus() { //good example functions
    	// Read Safety Status A/B/C and find which bits are set
    	// This shows which primary protections have been triggered
    	DirectCommands(SafetyStatusA, 0x00, R);
    	value_SafetyStatusA = (RX_data[1]*256 + RX_data[0]);
    	//Example Fault Flags
    	UV_Fault = ((0x4 & RX_data[0])>>2);
    	OV_Fault = ((0x8 & RX_data[0])>>3);
    	SCD_Fault = ((0x8 & RX_data[1])>>3);
    	OCD_Fault = ((0x2 & RX_data[1])>>1);
    	DirectCommands(SafetyStatusB, 0x00, R);
    	value_SafetyStatusB = (RX_data[1]*256 + RX_data[0]);
    	DirectCommands(SafetyStatusC, 0x00, R);
    	value_SafetyStatusC = (RX_data[1]*256 + RX_data[0]);
    	if ((value_SafetyStatusA + value_SafetyStatusB + value_SafetyStatusC) > 1) {
    		ProtectionsTriggered = 1; }
    	else {
    		ProtectionsTriggered = 0; }
    }
    
    void BQ769x2_ReadPFStatus() {
    	// Read Permanent Fail Status A/B/C and find which bits are set
    	// This shows which permanent failures have been triggered
    	DirectCommands(PFStatusA, 0x00, R);
    	value_PFStatusA = (RX_data[1]*256 + RX_data[0]);
    	DirectCommands(PFStatusB, 0x00, R);
    	value_PFStatusB = (RX_data[1]*256 + RX_data[0]);
    	DirectCommands(PFStatusC, 0x00, R);
    	value_PFStatusC = (RX_data[1]*256 + RX_data[0]);
    }
    
    // ********************************* End of BQ769x2 Status and Fault Commands   *****************************************
    
    
    // ********************************* BQ769x2 Measurement Commands   *****************************************
    
    
    uint16_t BQ769x2_ReadVoltage(uint8_t command)
    // This function can be used to read a specific cell voltage or stack / pack / LD voltage
    {
    	//RX_data is global var
    	DirectCommands(command, 0x00, R);
    	if(command >= Cell1Voltage && command <= Cell16Voltage) {//Cells 1 through 16 (0x14 to 0x32)
    		return (RX_data[1]*256 + RX_data[0]); //voltage is reported in mV
    	}
    	else {//stack, Pack, LD
    		return 10 * (RX_data[1]*256 + RX_data[0]); //voltage is reported in 0.01V units
    	}
    
    }
    void BQ769x2_ReadAllVoltages()
    // Reads all cell voltages, Stack voltage, PACK pin voltage, and LD pin voltage
    {
      int cellvoltageholder = Cell1Voltage; //Cell1Voltage is 0x14
      for (int x = 0; x < 16; x++){//Reads all cell voltages
        CellVoltage[x] = BQ769x2_ReadVoltage(cellvoltageholder);
        cellvoltageholder = cellvoltageholder + 2;
      }
      Stack_Voltage = BQ769x2_ReadVoltage(StackVoltage);
      Pack_Voltage = BQ769x2_ReadVoltage(0x36);
      LD_Voltage = BQ769x2_ReadVoltage(LDPinVoltage);
    }
    
    uint16_t BQ769x2_ReadCurrent()
    // Reads PACK current
    {
    	DirectCommands(CC2Current, 0x00, R);
    	return (RX_data[1]*256 + RX_data[0]);  // current is reported in mA
    }
    
    float BQ769x2_ReadTemperature(uint8_t command)
    {
    	DirectCommands(command, 0x00, R);
    	//RX_data is a global var
    	return (0.1 * (float)(RX_data[1]*256 + RX_data[0])) - 273.15;  // converts from 0.1K to Celcius
    }
    
    void BQ769x2_ReadPassQ(){ // Read Accumulated Charge and Time from DASTATUS6
    	Subcommands(DASTATUS6, 0x00, R);
    	AccumulatedCharge_Int = ((RX_32Byte[3]<<24) + (RX_32Byte[2]<<16) + (RX_32Byte[1]<<8) + RX_32Byte[0]); //Bytes 0-3
    	AccumulatedCharge_Frac = ((RX_32Byte[7]<<24) + (RX_32Byte[6]<<16) + (RX_32Byte[5]<<8) + RX_32Byte[4]); //Bytes 4-7
    	AccumulatedCharge_Time = ((RX_32Byte[11]<<24) + (RX_32Byte[10]<<16) + (RX_32Byte[9]<<8) + RX_32Byte[8]); //Bytes 8-11
    }
    
    // ********************************* End of BQ769x2 Measurement Commands   *****************************************
    
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    
    /* USER CODE END 0 */
    
    /**
      * @brief  The application entry point.
      * @retval int
      */
    int main(void)
    {
      /* USER CODE BEGIN 1 */
        	volatile int i = 0;
    		char uart_buf[50];
    		int uart_buf_len;
      /* USER CODE END 1 */
    
      /* MCU Configuration--------------------------------------------------------*/
    
      /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
      HAL_Init();
    
      /* USER CODE BEGIN Init */
    
      /* USER CODE END Init */
    
      /* Configure the system clock */
      SystemClock_Config();
    
      /* USER CODE BEGIN SysInit */
    
      /* USER CODE END SysInit */
    
      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_I2C1_Init();
      MX_TIM1_Init();
      MX_USART1_UART_Init();
      /* USER CODE BEGIN 2 */
      HAL_TIM_Base_Start(&htim1);
      delayUS(10000);
    
      	CommandSubcommands(BQ769x2_RESET);  // Resets the BQ769x2 registers
      	delayUS(60000);
      	BQ769x2_Init();  // Configure all of the BQ769x2 register settings
      	delayUS(10000);
      	CommandSubcommands(FET_ENABLE); // Enable the CHG and DSG FETs
      	delayUS(10000);
      	 CommandSubcommands(SLEEP_DISABLE); // Sleep mode is enabled by default. For this example, Sleep is disabled to
      									   // demonstrate full-speed measurements in Normal mode.
    
      	delayUS(60000);
      	delayUS(60000);
      	delayUS(60000);
      	delayUS(60000);  //wait to start measurements after FETs close
    
    
    
    
    
    
    
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    
        /* USER CODE END WHILE */
    
    
    
    	  Temperature[0] = BQ769x2_ReadTemperature(TS1Temperature);
    			uart_buf_len = sprintf(uart_buf, "%f : mV\r\n", Temperature[0]);            //
    			HAL_UART_Transmit(&huart1, (uint8_t *)uart_buf, uart_buf_len, 100);      //
    		//	delayUS(100000);
    		//	AlarmBits =0X01;
    		if (AlarmBits & 0x80) {  // Check if FULLSCAN is complete. If set, new measurements are available
        		BQ769x2_ReadAllVoltages();
        		Pack_Current = BQ769x2_ReadCurrent();
        		Temperature[0] = BQ769x2_ReadTemperature(TS1Temperature);
        		Temperature[1] = BQ769x2_ReadTemperature(TS3Temperature);
    			DirectCommands(AlarmStatus, 0x0080, W);  // Clear the FULLSCAN bit
    		}
    
    		if (AlarmBits & 0xC000) {  // If Safety Status bits are showing in AlarmStatus register
    			BQ769x2_ReadSafetyStatus(); // Read the Safety Status registers to find which protections have triggered
    			if (ProtectionsTriggered & 1) {
    				//HAL_GPIO_WritePin(GPIOA, LD2_Pin, GPIO_PIN_SET); }// Turn on the LED to indicate Protection has triggered
    				DirectCommands(AlarmStatus, 0xF800, W); // Clear the Safety Status Alarm bits.
    			}
    		else
    		{
    			if (ProtectionsTriggered & 1) {
    				BQ769x2_ReadSafetyStatus();
    				if (!(ProtectionsTriggered & 1))
    				{
    					//HAL_GPIO_WritePin(GPIOA, LD2_Pin, GPIO_PIN_RESET);
    				}
    			} // Turn off the LED if Safety Status has cleared which means the protection condition is no longer present
    		}
    		delayUS(20000);  // repeat loop every 20 ms
        /* USER CODE BEGIN 3 */
      }
      /* USER CODE END 3 */
    }
    
    }
    /**
      * @brief System Clock Configuration
      * @retval None
      */
    void SystemClock_Config(void)
    {
      RCC_OscInitTypeDef RCC_OscInitStruct = {0};
      RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
      /** Initializes the RCC Oscillators according to the specified parameters
      * in the RCC_OscInitTypeDef structure.
      */
      RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
      RCC_OscInitStruct.HSIState = RCC_HSI_ON;
      RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
      RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
      if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
      {
        Error_Handler();
      }
      /** Initializes the CPU, AHB and APB buses clocks
      */
      RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
      RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
      RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
      RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
      RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
      if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
      {
        Error_Handler();
      }
    }
    
    /**
      * @brief I2C1 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_I2C1_Init(void)
    {
    
      /* USER CODE BEGIN I2C1_Init 0 */
    
      /* USER CODE END I2C1_Init 0 */
    
      /* USER CODE BEGIN I2C1_Init 1 */
    
      /* USER CODE END I2C1_Init 1 */
      hi2c1.Instance = I2C1;
      hi2c1.Init.ClockSpeed = 400000;
      hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
      hi2c1.Init.OwnAddress1 = 0;
      hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
      hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
      hi2c1.Init.OwnAddress2 = 0;
      hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
      hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_ENABLE;
      if (HAL_I2C_Init(&hi2c1) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN I2C1_Init 2 */
    
      /* USER CODE END I2C1_Init 2 */
    
    }
    
    /**
      * @brief TIM1 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_TIM1_Init(void)
    {
    
      /* USER CODE BEGIN TIM1_Init 0 */
    
      /* USER CODE END TIM1_Init 0 */
    
      TIM_ClockConfigTypeDef sClockSourceConfig = {0};
      TIM_MasterConfigTypeDef sMasterConfig = {0};
    
      /* USER CODE BEGIN TIM1_Init 1 */
    
      /* USER CODE END TIM1_Init 1 */
      htim1.Instance = TIM1;
      htim1.Init.Prescaler = 0;
      htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim1.Init.Period = 65535;
      htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim1.Init.RepetitionCounter = 0;
      htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
      {
        Error_Handler();
      }
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN TIM1_Init 2 */
    
      /* USER CODE END TIM1_Init 2 */
    
    }
    
    /**
      * @brief USART1 Initialization Function
      * @param None
      * @retval None
      */
    static void MX_USART1_UART_Init(void)
    {
    
      /* USER CODE BEGIN USART1_Init 0 */
    
      /* USER CODE END USART1_Init 0 */
    
      /* USER CODE BEGIN USART1_Init 1 */
    
      /* USER CODE END USART1_Init 1 */
      huart1.Instance = USART1;
      huart1.Init.BaudRate = 115200;
      huart1.Init.WordLength = UART_WORDLENGTH_8B;
      huart1.Init.StopBits = UART_STOPBITS_1;
      huart1.Init.Parity = UART_PARITY_NONE;
      huart1.Init.Mode = UART_MODE_TX_RX;
      huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
      huart1.Init.OverSampling = UART_OVERSAMPLING_16;
      if (HAL_UART_Init(&huart1) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN USART1_Init 2 */
    
      /* USER CODE END USART1_Init 2 */
    
    }
    
    /**
      * @brief GPIO Initialization Function
      * @param None
      * @retval None
      */
    static void MX_GPIO_Init(void)
    {
      GPIO_InitTypeDef GPIO_InitStruct = {0};
    
      /* GPIO Ports Clock Enable */
      __HAL_RCC_GPIOC_CLK_ENABLE();
      __HAL_RCC_GPIOA_CLK_ENABLE();
      __HAL_RCC_GPIOB_CLK_ENABLE();
    
      /*Configure GPIO pin Output Level */
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
    
      /*Configure GPIO pin : PC13 */
      GPIO_InitStruct.Pin = GPIO_PIN_13;
      GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
      HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    
    }
    
    /* USER CODE BEGIN 4 */
    
    /* USER CODE END 4 */
    
    /**
      * @brief  This function is executed in case of error occurrence.
      * @retval None
      */
    void Error_Handler(void)
    {
      /* USER CODE BEGIN Error_Handler_Debug */
      /* User can add his own implementation to report the HAL error return state */
      __disable_irq();
      while (1)
      {
      }
      /* USER CODE END Error_Handler_Debug */
    }
    
    #ifdef  USE_FULL_ASSERT
    /**
      * @brief  Reports the name of the source file and the source line number
      *         where the assert_param error has occurred.
      * @param  file: pointer to the source file name
      * @param  line: assert_param error line source number
      * @retval None
      */
    void assert_failed(uint8_t *file, uint32_t line)
    {
      /* USER CODE BEGIN 6 */
      /* User can add his own implementation to report the file name and line number,
         ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
      /* USER CODE END 6 */
    }
    #endif /* USE_FULL_ASSERT */
    
    /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
    

  • Dear Arjun,

    All microcontroller sample code for the BQ769x2 family can be found at this link: https://www.ti.com/lit/zip/sluc701. Further, TI does offer videos over how to program the BQ769x2 device family at this link: https://www.ti.com/video/6270522957001.

    When you mention the two sets of code on TI's website, are you talking about BQStudio or something else? If so, its worth noting that BQStudio was designed to be used with boards compatible with SMBUS. Can you share your schematic?

    Best,

    Asher Nederveld

  • HELLO SIR , 

    NO SIR THERE IS NO SEEN OF BQSTUDIO IN THIS CASE , I ATTACHED MY SCHEMATIC FOR YOUR REF..  ITS SEEMS LIKE THERE IS PROBLEM OF GROUNDING PLEASE LET ME CORRECT ,

    4743.Schematic (1).pdf

  • SORRY I HAVE ATTACHED THE WRONG SCHEMATIC..

    BELOW THE ACCTUAL ONE

    SS16_V2.0 14-06-2023 (6).pdf

  • HELLO SIR,

    I HAVE FINALLY DID READ AND WRITE BY NEW CODE , 

    APART FROM THIS I HAVE FEW QUESTIONS 

    1)  AS PER TEC.DATASHEET OF BQXXXX , WE CAN USE THE I2C AT 100KHZ AND 400KHZ , IF I WANT TO SET THE BQ I2C AT 200KHZ CAN I OR NOT?

    2) AS YOU EARLY SAID THAT , IN BQ CRC IS BYDEFAULT ENABLE THEN IF I WANT TO DISABLE THE SAME SAME HOW I CAN DO THE SAME?

    3) IN CODE I WANT TO READ THE CUV AND COV DATA  I SEATED  IN THIS ( BQ769x2_SetRegister(COVThreshold, 0x55, 1);)  TO VERYFIY IS IT SET OF NOT THEN HOW CAN I DO THE SAME ?

    4)  HOW CAN TAKE MY BQXXX DEVICE INTO SEALED MODE AFTER MICRCONTROLLER PROGRAMMING?

    5) DIRECT COMMAND AND SUBCOMMAND AND COMMAND-SUBSUMMAND - AND I ENABLE AND DISABLE THE CRC OF THE SAME?

    THANK YOU SIR FOR SUPPORT AND I FAITHFULLY TO GET THESE LAST QUARIES .

  • Dear Arjun,

    1. The device is only meant to do 100kHz and 400kHz I2C.

    2. You would need to modify the register at Settings:Configuration:Comm Type to select which communication mode you want. I've attached the options below. For more information, view section 9.1 in the Technical Reference Manual

    3. If you wish to see whether a COV or CUV occurred, you can read the values in the Safety Status A Register, bits 2 and 3. If you wish to determine whether your write has successfully occurred, you would just need to read to the COV/CUV Threshold register under Protections:CUV/COV:Threshold.

    4. To put your device into SEALED mode, you can set the Security:Settings:Security Settings[SEAL] bit so that it enters SEALED mode on power-up, or you can send the 0x0030 SEAL() subcommand to put it into SEALED mode.

    5. I'm not 100% sure what you are asking on this question, but when you disable CRC, it should also apply to commands and subcommands.

    Best,

    Asher Nederveld

  • hello sir

    I want read the data memory to verify that after writing all threshold so I could read them , I tried the same by the following way by reading the tec datasheet  :-

    void BQ769x2_Get_Register_data( uint16_t reg_add)
    {

    uint8_t RX_RegData[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    uint8_t rx_byte[32] = {0x00,0x00};

    uint8_t length;
    uint8_t crc_rx;

    //TX_RegData in little endian format
    RX_RegData[0] = reg_add & 0xff;
    RX_RegData[1] = (reg_add >> 8) & 0xff;

    I2C_WriteReg(0x3E, RX_RegData, 2);
    delayUS(2000);

    I2C_ReadReg(0X40,RX_34Byte , 34);
    crc_rx = RX_34Byte[32];
    length = RX_34Byte[33];

    for(int i =0; i<length ; i++)
    {
    RX_34Byte[i] = RX_34Byte[40+i];
    }
    }

    but did not get any output from the same , please let me correct where I am wrong and make changes.

     thanks!

  • Dear Arjun,

    When you say you followed the tec datasheet, are you referring to section 13.1 of the technical reference manual? If you are, it is worth noting that it says to start reading the buffer at x40. I believe your implementation uses 40 (not x40) in the following line:

    RX_34Byte[i] = RX_34Byte[40+i];

    It is worth noting though that TI does provide this function for reading registers using the STM32 for the BQ76952:

    int I2C_ReadReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
    {
    	unsigned int RX_CRC_Fail = 0;  // reset to 0. If in CRC Mode and CRC fails, this will be incremented.
    	uint8_t RX_Buffer [MAX_BUFFER_SIZE] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    #if CRC_Mode
    	{
    		uint8_t crc_count = 0;
    		uint8_t ReceiveBuffer [10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    		crc_count = count * 2;
    		unsigned int j;
    		unsigned int i;
    		unsigned char CRCc = 0;
    		uint8_t temp_crc_buffer [3];
    
    		HAL_I2C_Mem_Read(&hi2c1, DEV_ADDR, reg_addr, 1, ReceiveBuffer, crc_count, 1000);
    		uint8_t crc1stByteBuffer [4] = {0x10, reg_addr, 0x11, ReceiveBuffer[0]};
    		CRCc = CRC8(crc1stByteBuffer,4);
    		if (CRCc != ReceiveBuffer[1])
    		{
    			RX_CRC_Fail += 1;
    		}
    		RX_Buffer[0] = ReceiveBuffer[0];
    
    		j = 2;
    		for (i=1; i<count; i++)
    		{
    			RX_Buffer[i] = ReceiveBuffer[j];
    			temp_crc_buffer[0] = ReceiveBuffer[j];
    			j = j + 1;
    			CRCc = CRC8(temp_crc_buffer,1);
    			if (CRCc != ReceiveBuffer[j])
    				RX_CRC_Fail += 1;
    			j = j + 1;
    		}
    		CopyArray(RX_Buffer, reg_data, crc_count);
    	}
    #else
    	HAL_I2C_Mem_Read(&hi2c1, DEV_ADDR, reg_addr, 1, reg_data, count, 1000);
    #endif
    	return 0;
    }

    Hope this helps!

    Best,

    Asher Nederveld

  • Dear Sir, thank you for your humble support,

    just I want to know one more , as I verifying that which parameter  I able to read correct or not then I found that  some parameter I able to read and write correct but some not, is there anything which that I not able understand ? or any specific reason for the same? let me know! 

    as I know delay is two byte , and also have write in _set_bq_register()  but still not getting actual value , which is I have set

    .

    ~arjuna

  • Dear Arjun,

    Can you try to read Protections:OCC:Recovery Threshold or any other two byte parameters to see whether the issue is pertaining to two byte registers? Can you also share your set_bq_register() function if its different than the TI provided I2C_WriteReg() function?

    Also, have you confirmed whether or not that this is purely a read error versus a write error? It might be smart to test how long it takes to trigger COV to make sure the write is going through with an oscilloscope. The delay before any write should be ~244.2ms. Can you show a logic analyzer capture of the waveforms sent and received when you try to read the delay value? This would also give insight into where the read/write is going wrong.

    Best,

    Asher Nederveld

  • Hello sir, as my above problem has been solved,

    Now I am facing one more problem with the same IC(BQ7695202) , In this time I am using BQstudio to program my BMS. (I have 2 BMS for 40 ampere and 60 ampere) 

    When I am doing short circuit with of 40 ampere BMS then SCD working fine.

    But When I am doing short circuit with of 60 ampere BMS ,  then BQ76xxx  getting reset again and again (watchdog timer bit gets high) and by doing the same 7-8 times the BQ7xx becomes goes in shutdown mode (as mention in BQ-technical datasheet - due to RAM failure occurred )

    We have verify everything and have try possible solutions but couldn't get the solution of the same,

    Please let you give me the solution for the same it is very important for us.

    I have attached the schematics of the BMS and also with .gg file for both (40/60 ampere)

    SLERU16040V0200R1_DT255.gg (1).csv

    SS16_V2.0 14-06-2023 (8).pdf

    SS16_13022023.gg.csv

    This is what we getting during SCD..

    Apart from this, I also seen that, during short circuit discharging the BQ7xx getting slightly hot and its going in Over internal temperature fault. after this BQxx being reset again and again (WD bits gets high all the time).

    Q2. My last question is that dose BQ76952 core have kalman filter to estimate the accurate SoC, If not then is the SoC we are getting is accurate how can I understand this concept or if you have document related to the same then please share.

    thanks and regards

  • Dear Arjun,

    Looking at your .gg files, I'm not sure your current calculations are correct. You're respective SCD thresholds are 7 and 10 for 40A and 60A. Given your current sense resistor setup is 8 resistors in parallel of 10mOhms of resistance, this gives total resistance of 1.25mOhm. A 7 for an SCD threshold means a total of 150mV is seen across the SRP and SRN pins. With your resistance right now, you'd need roughly 120A to trigger an OCD, not 40A. Likewise, a 10 implies 250mV across the SRP and SRN pins, correlating to a necessary current of 200A to trigger.

    Can you confirm your device reaches 200A during a short circuit event? If it doesn't, the fault wouldn't trigger, allowing the device to become unpowered as the voltage of the pack falls with the short circuit. With not enough power, it could be possible that a RAM failure occurs if the memory is no longer getting power.

    For your second question, the chip does not feature a Kalman filter built into it to determine SoC. It does provide all the necessary voltages, charges, and currents to determine SoC though. If you wish, a stack-level gauge like the BQ34Z100-G1 can be used in conjunction with the BQ769x2 to provide SoC calcs.

    Best,
    Asher Nederveld

  • Hello sir,

    Sorry, I forget to mention that things:-

    For 60A -->  shunt 10 miliohm (8 Nos.)  = Req = 1.25 miliohm

    For 40A --> shunt 4 miliohm (4 Nos.)  = Req = 1 miliohm

    At .gg files

    For 60A   -->  SCD = 10 (250 mV)  = 200A

    For 40A   -->  SCD =  7 (150 mV)  = 150A

    One more thing is that, during short circuit discharging the BQ76952 get completely reset and REG1 voltage become zero due to that I2C connection become lost for 1-2 sec and then BQ7xx get stucked in loop and watchdog bits become high -forever

  • Dear Arjun,

    Does SCD trigger when you run the 60A SCD test? The device shouldn't be heating up that much in one short circuit, especially if room temp is ~30C. Have you tried swapping the BQ769x2 chip to see if the same problem persists across multiple devices?

    For the complete reset, is it clearing all registers or just restarting the hardware? Generally, if the SCD isn't triggering and the device continues to pull high current and the pack voltage drops, the chip might stop receiving power.

    I'll try running your .gg file in the morning to see if I can see the same results you are seeing on an EVM.

    Best,
    Asher Nederveld

  • Hello Sir,

    1. Yes, SCD gets triggered and have tried the different BQ76x2 device but the same problem is occurred.

    2. its just resting the hardware or power supply due to that the I2C connection become lost and the changes we made after OTP in the same  that become also reset due to the lost of power supply on REG1 

    ok sir, let me know what is the cause behind that ! 

  • Dear Arjun,

    Besides the sense resistor change, is there any changes in the hardware of the set-up? While testing the .gg file on the EVM, I was able to trigger an SCD and have the FETs turn off.

    One thing that would be good to check is that all your DSG FETs are still in good condition. It's possible that the FETs might have gotten damaged some how and is acting as a short so the whether or not the DSG FET is on, current can flow. If that is the case, a short circuit triggering SCD is software wouldn't be able to turn the gate off. This would lead to the chip not receiving power and therefore causing a reset.

    Likewise, what are you using for the SCD test? Typically its best to use a battery that doesn't have a current limit like a power supply to make sure you can reach 200A. I noticed you delay is ~450uA so it might be good to try shortening the time delay if you are trying to use a power supply for the test. This likely won't fix anything, but it would be good to test.

    One last question, why did you vary the resistances from FET gate to source on the power path? Typical applications use 10Mohm resistors, but you seem to use both 1Mohm and 470K resistors.

    Best,
    Asher Nederveld