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: Custom PCB, FETs stay closed no matter what

Part Number: BQ76952
Other Parts Discussed in Thread: BQSTUDIO

Tool/software:

Hi, 

I'm quite new to electrical engineering and the TI platform, please excuse any mistakes I make in formating, documentation etc.

I designed custom PCB as a BMS and used the BQ76952 chip, below you can see the schematic, also with cell wiring, and a source code I test on esp32 in Arduino IDE with I2C communication. I searched web, talked to chatbots, but still could get a software solution to my problem, the charge and discharge gates are closed. Do you think there may be a problem in my schematic or cell wiring? Is there some better way to test it out than with my code? Not sure if BQSTUDIO would work? Thanks so much for your help. I appreciate every answer. 

This is the output from the code in the console

Cell 1 voltage: 3.686 V
Cell 2 voltage: 4.102 V
Cell 3 voltage: 3.686 V
Cell 4 voltage: 3.666 V
Cell 5 voltage: 0.000 V
Cell 6 voltage: 0.000 V
Cell 7 voltage: 0.000 V
Cell 8 voltage: 0.000 V
Cell 9 voltage: 0.000 V
Cell 10 voltage: 0.000 V
Cell 11 voltage: 0.000 V
Cell 12 voltage: 0.000 V
Cell 13 voltage: 0.000 V
Cell 14 voltage: 0.000 V
Cell 15 voltage: 0.000 V
Cell 16 voltage: 3.839 V
FET Status: 1110000

SCH_Schematic1_2025-04-03.pdf

#include <Wire.h>

// BQ76952 I2C address (7-bit)
#define BQ76952_I2C_ADDR 0x08

// Command addresses
#define CONTROL_STATUS 0x00
#define BATTERY_STATUS 0x12
#define CELL1_VOLTAGE_L 0x14
#define CELL1_VOLTAGE_H 0x15
#define FET_STATUS 0x7F

// Variables to track communication status
bool commEstablished = false;
int retryCount = 0;
const int maxRetries = 5;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22, 400000);  // Initialize I2C with default pins (SDA=21, SCL=22)
  
  // Try to establish communication
  while (!commEstablished && retryCount < maxRetries) {
    if (checkCommunication()) {
      commEstablished = true;
      Serial.println("Communication with BQ76952 established successfully!");
    } else {
      retryCount++;
      Serial.print("Communication failed, retry ");
      Serial.print(retryCount);
      Serial.println("/5");
      delay(1000);
    }
  }
  
  if (!commEstablished) {
    Serial.println("Failed to establish communication with BQ76952");
    while(1); // Halt if communication fails
  }
}

void loop() {
  // Read and print cell voltages (example for cells 1-4)
  for (int cell = 1; cell <= 16; cell++) {
    float voltage = readCellVoltage(cell);
    Serial.print("Cell ");
    Serial.print(cell);
    Serial.print(" voltage: ");
    Serial.print(voltage, 3);
    Serial.println(" V");
  }
  
  // Read and print FET status
  uint8_t fetStatus = readRegister(FET_STATUS);
  Serial.print("FET Status: ");
  Serial.println(fetStatus, BIN);
  
  // Check if FETs are enabled
  bool chgEnabled = (fetStatus & 0x01) != 0;
  bool dsgEnabled = (fetStatus & 0x02) != 0;
  
  Serial.print("CHG FET: ");
  Serial.println(chgEnabled ? "ENABLED" : "DISABLED");
  Serial.print("DSG FET: ");
  Serial.println(dsgEnabled ? "ENABLED" : "DISABLED");
  
  Serial.println("---------------------");
  delay(1000); // Delay between readings
}

bool checkCommunication() {
  // Try to read the Battery Status register
  Wire.beginTransmission(BQ76952_I2C_ADDR);
  Wire.write(BATTERY_STATUS);
  if (Wire.endTransmission(false) != 0) { // Send repeated start
    return false;
  }
  
  // Request 2 bytes (Battery Status is 16-bit)
  if (Wire.requestFrom(BQ76952_I2C_ADDR, 2) != 2) {
    return false;
  }
  
  // If we got data, communication is working
  uint16_t batteryStatus = Wire.read() | (Wire.read() << 8);
  return true;
}

float readCellVoltage(int cellNumber) {
  // Calculate register addresses for the cell
  uint8_t regLow = CELL1_VOLTAGE_L + (2 * (cellNumber - 1));
  uint8_t regHigh = regLow + 1;
  
  // Read low and high bytes
  uint8_t lowByte = readRegister(regLow);
  uint8_t highByte = readRegister(regHigh);
  
  // Combine bytes and convert to voltage (mV to V)
  int16_t voltage_mV = (highByte << 8) | lowByte;
  return voltage_mV / 1000.0;
}

uint8_t readRegister(uint8_t reg) {
  Wire.beginTransmission(BQ76952_I2C_ADDR);
  Wire.write(reg);
  Wire.endTransmission(false); // Send repeated start
  
  Wire.requestFrom(BQ76952_I2C_ADDR, 1);
  while (Wire.available() < 1); // Wait for data
  return Wire.read();
}

  • Hello Adam,

    Did you use the 0x0022 FET_ENABLE() subcommand to toggle the [FET_EN] bit when you were testing your FETs?


    Best Regards,
    Alexis

  • Hi Alexis, 

    Thanks for the reply!

    I tried it, but I don't think that the chip is in testing mode. I don't know how to change it. If I try to run the command it doesn't do anything.

    Best, 

    Adam 

  • Another updated

    I managed to narrow it down, and it looks like the device is in SLEEP mode and isn't initialized yet. Does anyone know what's going on? 

    Reading the 0x12 Battery Status() Command returns this 1100010010000100 

  • Hello Adam,

    Table 6-2. 0x12 Battery Status() Bit Definitions of the technical reference manual (TRM) should help identify what those bits mean. 

    The reason for sending the subcommand FET_ENABLE is because the part has FET_EN by default = 0 as shown in Table 13-34. Mfg Status Init Register Field Descriptions of the TRM. 

    Are you referring to the sample code and/or Software Development Guide we have when attempting to communicate with our device? 

    If the SLEEPCHG bit is not set in the Settings:FET:FET Options:SLEEPCHG , this will disable the CHG FET during SLEEP mode. This is mentioned in Section 5.2.2 High-Side NFET Drivers of the BQ76952 TRM, in the paragraphs after Manual Control.

    Best Regards,
    Alexis

  • Hey Alexis, 

    So, I tried the sample code, I used it to create a very similar code that would run on ESP32. Monitoring the 0x12 Battery Status() before and after entering the config mode. The last bit, which should indicate if the device is in config mode always stays 0. 

    I called the FET_ENABLE, but both FETs are still closed. The alarm status register returns 11011000000000. Indicating a bit is set in Safety Status B() or Safety Status C() and Safety Status A(). While all three of these return 0

    Best, 

    Adam 

  • Is it also possible that this might be a hardware issue? I'm checking through the datasheet and my schematic. I'm not sure if the negative side of the first cell should be connected the way I have it in my design. Might this be causing all these issues?

  • Hello Adam,

    Thank you for your patience. 

    I'm not sure if the negative side of the first cell should be connected the way I have it in my design

    Your VC1 connection looked fine to me. 

    The alarm status register returns 11011000000000

    From this, it also indicates that the CHG/DSG FETs are ON as bits 5[XDSG] and 6[XCHG] bits are set when the CHG/DSG FET is off. 

    Can you check the CHG and DSG pin voltages with a multimeter or grab a waveform of them when you power up the device, and then write FET_EN?


    Best Regards,
    Alexis 

  • Hi Alexis

    The DSG voltage is 0V and CHG is 0.2V below the VC16 voltage. After writing the command, pushing it from esp32 i2c to the chip using the code below, it doesn't changes a thing. The voltages remain same. Although, I noticed that the DSG voltage sometimes increases to 2V but then drops back to 0V.

    Wire.beginTransmission(0x08);               // I2C address (0x08)
    Wire.write(0x3E);                           // Subcommand register (0x00)
    Wire.write((byte)command & 0x00FF);         // LSB
    Wire.write((byte)(command >> 8) & 0x00FF);  // MSB
    Wire.endTransmission();
    delay(10);  // Short delay after sending

    Best Regards, 

    Adam 

  • Hi Adam,

    You might want to configure the device with all protections and permanent fails disabled, make FET_EN=0 and PF_EN=0.  Then in that state make sure your comms are working properly, read cell voltages, current, temp, to ensure you get reasonable data.  You can clear AlarmStatus, then make sure you aren't still getting any safety alerts, status, or PF alerts or status.  Then try using the DSGTEST and CHGTEST commands, to see if you can force the FET drivers on.  

    Thanks,

    Terry