SDAA084 April   2026 BQ25856-Q1

 

  1.   1
  2.   Abstract
  3.   Trademarks
  4. 1Introduction
  5. 2How to Extend the Life of Supercapacitors
    1. 2.1 Effects of Voltage
    2. 2.2 Effects of Current
    3. 2.3 Effects of Temperature
  6. 3Supercapacitor ESR and Capacitance
    1. 3.1 Estimating Capacitor Capacitance and ESR
    2. 3.2 Measuring Supercapacitor Health With The BQ25856-Q1
    3. 3.3 Estimating the Capacitance and ESR in Reverse Mode
  7. 4Summary
  8. 5Appendix - Example MCU Code for the BQ25858-Q1
  9. 6References

Appendix - Example MCU Code for the BQ25858-Q1











int main(void) {
  SYSCFG_DL_init(); // Initialize the I2C and the timer via SuperCapHealth.sysconfig
  __NVIC_EnableIRQ(I2C_0_INST_INT_IRQN); // Initialize the I2C interrupt routine for I2C communication 
  __NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN); // Initialize the timer interrupt routine.
  timer_exp = 0; // Initialize the timer flag.
  // I2C Settings
  uint8_t DIS_WD[1] = {0x05}; // Disable Watchdog timer
  uint8_t EN_CHG[1] = {0xC9}; // 0x09 for BQ25858-Q1
  uint8_t DIS_CHG[1] = {0xC8}; // 0x08 for BQ25858-Q1
  uint8_t DIS_PRECHG[1] = {0x06}; // Disable Precharge and Termination
  uint8_t EN_ADC[1] = {0xE0}; // One shot conversion mode to control when ADC Reads
  uint8_t VOUT_ADC[1] = {0xEF}; // Set only the VOUT ADC to read (shortens conversion time)
  uint8_t DIS_INT_MASK[3] = {0x7F, 0xFF, 0xFF}; // Set only the ADC interrupt for the best results
  // Current Parameter
  uint8_t CHG_CURRENT[2] = {0x50, 0x00}; // 1 A IOUT setting
  volatile uint16_t ICHG = 0x0000; // 16 bit variable for charge current volatile
  double_t current_conv = 0.05; // 50 mA per bit on BQ2585X-Q1 Register
  volatile double_t current = 0.0; // Current value for ESR and CAP calculations
  // Determine Charge Current in AMPERES
  ICHG = (((uint16_t)CHG_CURRENT[1] << 8) | (uint16_t)CHG_CURRENT[0]) >> 2;
  current = (double_t)ICHG * current_conv;
  // Voltage Parameter
  uint8_t VBAT[2] = {0x00, 0x00};
  // Variable to read ADC Conversion
  volatile unsigned int adc_result0 = 0; // 16 bit variable for ADC Conversion result
  volatile unsigned int adc_result1 = 0;
  volatile unsigned int adc_result2 = 0;
  volatile double_t volt_conv = 0.002; // 2 mV per bit on BQ2585X-Q1 ADC
  volatile double_t voltage0 = 0; // Voltage value for ESR and CAP calculations
  volatile double_t voltage1 = 0;
  volatile double_t voltage2 = 0;
  // Time parameter
  volatile double_t charge_time = 1.0; // 1000 ms charge time
  //Results
  volatile double_t ESR = 0.0; // ESR Result
  volatile double_t CAP = 0.0; // Capacitance result
  // Disable Watchdog to avoid registers being overwritten
  I2C_Write(BQ2585X_TIMER_CONTROL, DIS_WD, 1);
  // Disable Charge to set proper settings
  I2C_Write(BQ2585X_CHARGER_CONTROL, DIS_CHG, 1);
  // Set 1 A IOUT for measurement calculations
  I2C_Write(BQ2585X_CHARGE_CURRENT_LIMIT_LSB, CHG_CURRENT, 2);
  // Disable Precharge and Termination
  I2C_Write(BQ2585X_PRECHARGE_AND_TERMINATION_CONTROL, DIS_PRECHG, 1);
  // Set only VOUT_ADC for best operation
  I2C_Write(BQ2585X_ADC_CHANNEL_CONTROL, VOUT_ADC, 1);
  // Set only ADC interrupts for best operation
  I2C_Write(BQ2585X_MASK_1, DIS_INT_MASK, 3);
  while (1) {
    // Enable the charge sequence
    I2C_Write(BQ2585X_CHARGER_CONTROL, EN_CHG, 1);
    // Start timer to remove EN_CHG delay
    DL_TimerG_startCounter(TIMER_0_INST);
    // Wait for the 1 s timer to finish
    while (!timer_exp);
    // Reset timer flag for next timer cycle
    timer_exp = 0;
    // Perform ADC conversion for initial voltage
    I2C_Write(BQ2585X_ADC_CONTROL, EN_ADC, 1);
    // Wait for ADC conversion to finish
    while (DL_GPIO_readPins(BQ_INT_PORT, BQ_INT_PIN_0_PIN));
    // Read ADC conversion results
    I2C_Read(BQ2585X_VBAT_ADC_LSB, VBAT, 2);
    // Store ADC conversion results for later calculations
    adc_result0 = (VBAT[1] << 8) | (VBAT[0]);
    // Start the timer
    DL_TimerG_startCounter(TIMER_0_INST);
    // Wait for the 1 s timer to finish
    while (!timer_exp);
    // Perform ADC conversion for max voltage
    I2C_Write(BQ2585X_ADC_CONTROL, EN_ADC, 1);
    // Wait for ADC conversion to finish
    while (DL_GPIO_readPins(BQ_INT_PORT, BQ_INT_PIN_0_PIN));
    // Disable charge
    I2C_Write(BQ2585X_CHARGER_CONTROL, DIS_CHG, 1);
    // Read ADC conversion results
    I2C_Read(BQ2585X_VBAT_ADC_LSB, VBAT, 2);
    // Store ADC conversion results for later calculations
    adc_result1 = (VBAT[1] << 8) | VBAT[0];
    // Reset timer flag for next timer cycle
    timer_exp = 0;
    // Start timer to let output voltage settle
    DL_TimerG_startCounter(TIMER_0_INST);
    // Wait for the 1 s timer to finish
    while (!timer_exp);
    // Reset timer flag for next timer cycle
    timer_exp = 0;
    // Perform ADC conversion for final voltage
    I2C_Write(BQ2585X_ADC_CONTROL, EN_ADC, 1);
    // Wait for ADC conversion to finish
    while (DL_GPIO_readPins(BQ_INT_PORT, BQ_INT_PIN_0_PIN));
    // Read ADC conversion results
    I2C_Read(BQ2585X_VBAT_ADC_LSB, VBAT, 2);
    // Store ADC conversion results for later calculations
    adc_result2 = (VBAT[1] << 8) | (VBAT[0]);
    // Convert ADC values to a voltage
    voltage0 = (double_t)adc_result0 * volt_conv;
    voltage1 = (double_t)adc_result1 * volt_conv;
    voltage2 = (double_t)adc_result2 * volt_conv;
    // Calculations for Capacitance and ESR
    CAP = (current * charge_time) / (voltage1 - voltage0);
    ESR = (voltage1 - voltage2) / current;
  }
}