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.

  • TI Thinks Resolved

CCS/BQ24160: BQ24160 not charging battery to regulation voltage set in Control/Battery Voltage Register

Part Number: BQ24160

Tool/software: Code Composer Studio

I am using the BQ24160 Battery Charger to charge a 3.7 Li polymer battery and I'm not seeing it reach the full voltage set in the Control/Battery Voltage Register (03).   I set the value to 3.8V using the I2C bus and then set a Watchdog Timer reset to the Status/Control Register every one second.  The battery charges to the default 3.6V but then stops charging after that.

I can manually charge the battery to 4.0V without a problem using a CV/CC power supply.

I'm sending one register byte and one data byte to slave address 0x6B.  I've looked at the I2C commands to the BQ24160 with a scope and they appear correct and the BQ24160 ACKs all the commands.

I have the external FET controlled by BGATE installed.  The SYS voltage is sitting at 3.9V and the BAT voltage usually around 3.58V~3.68V.

Hopefully someone has insights on what the problem is.  I'm not sure what should happen when the battery falls below the regulation voltage.  I would assume the battery charger tries to maintain the 3.8V .

Here is the code I  am using on an MSP430F5659:

unsigned int BQ2416_reset[]    = { 0x02, 0x80 };    // Control Register > Reset all registers to default
unsigned int BQ2416_defaults[] = { 0x02, 0x0D };    // Control Register > Enter Hi-Z Mode, defaults
unsigned int BQ2416_current[]  = { 0x02, 0x2C };    // Control Register > Leave Hi-Z Mode, 500mA current limit
unsigned int BQ2416_voltage[]  = { 0x03, 0x3C };    // Battery Voltage Register > Charge Voltage = 3.8V

// I2C Write to Battery Charger
void I2C_write(int byteCount, unsigned int *data)
{
    B1_Tx_Data = data;                              // TX data array address
    B1_ByteCtr = byteCount;                         // load TX byte counter
    UCB1IE |= UCTXIE;                               // Enable TX interrupt
    UCB1CTL1 |= UCTR | UCTXSTT;                     // I2C TX, start condition
    _delay_cycles(1500);                            // allow transmission completion
    while (UCB1STAT & UCBBUSY);                     // wait for transmission to complete
}

// Battery Initialization
void initBattery(void)
{
    P8DIR |= BIT5 | BIT6;                           // P8.5 to UCB1SDA and
    P8SEL |= BIT5 | BIT6;                           // P8.6 to UCB1SCL

    UCB1CTL1 |= UCSWRST;                            // Enable SW reset
    UCB1CTL0 = UCMST | UCMODE_3 | UCSYNC;           // I2C Master, synchronous mode
    UCB1CTL1 = UCSSEL_2 | UCSWRST;                  // Use SMCLK, keep SW reset
    UCB1BR0 = 40;                                   // fSCL = SMCLK/40 = ~100kHz
    UCB1BR1 = 0;                                    // high byte of word
    UCB1I2CSA = 0x6B;                               // BQ24160 Slave Address is 6Bh
    UCB1CTL1 &= ~UCSWRST;                           // Clear SW reset, resume operation
    UCB1IE |= UCNACKIE | UCTXIE;                    // Enable TX interrupt, NACK interrupt
    UCB1IFG &= ~UCTXIFG;                            // Clear USCI_B1 TX interrupt flag

    // Control Register > Reset all registers to default (0x02, 0x80)
    I2C_write(2, BQ2416_reset);                     // I2C write data to register

    // Control Register > Enter Hi-Z Mode, defaults (0x02, 0x0D)
    I2C_write(2, BQ2416_defaults);                  // I2C write data to register

    // Control Register > Leave Hi-Z Mode, 500mA current limit (0x02, 0x2C)
    I2C_write(2, BQ2416_current);                   // I2C write data to register

    // Battery Voltage Register > Charge Voltage = 3.8V (0x03, 0x3C)
    I2C_write(2, BQ2416_voltage);                   // I2C write data to register
}

#pragma vector = USCI_B1_VECTOR
__interrupt void USCI_B1_ISR(void)
{
  switch(__even_in_range(UCB1IV,12))
  {
  case  0: break;                                       // Vector  0: No interrupts
  case  2: break;                                       // Vector  2: ALIFG
  case  4: break;                                       // Vector  4: NACKIFG
  case  6: break;                                       // Vector  6: STTIFG
  case  8: break;                                       // Vector  8: STPIFG
  case 10:                                              // Vector 10: RXIFG
    if (UCB1STAT & UCNACKIFG)                           // send STOP if slave sends NACK
    {
        UCB1CTL1 |= UCTXSTP;
        UCB1STAT &= ~UCNACKIFG;
    }
    break;
  case 12:                                              // Vector 12: TXIFG
      if (B1_ByteCtr)                                   // Check TX byte counter
      {
        UCB1TXBUF = *B1_Tx_Data++;                      // Load TX buffer
        B1_ByteCtr--;                                   // Decrement TX byte counter
      }
      else
      {
        UCB1CTL1 |= UCTXSTP;                            // I2C stop condition
        UCB1IFG &= ~UCTXIFG;                            // Clear USCI_B1 TX int flag
      }
    default: break;
  }
}

  • Bill,

    It looks like the charger was in the default mode. You set the input current as 500mA and the charging current is default 1A. The charger is in linear charging mode before the battery voltage reaches the minimum system voltage. The battery charger should be in Vin dynamic power management (DPM). Can you check how much is the input voltage and current at the charger terminal with different settings? Can you also read back the registers after the write?

    Regards,

    Eric

    Texas Instruments

    Battery Charger Solutions

  • In reply to ezhao:

    Hey Bill,

    To add to Eric's comment:

    Nowhere in your code do I see the charger's watchdog timer being reset. Just like the MSP430, the charger also has an internal watchdog timer to reset the charging parameters back to default.

    I just adding a periodic (<30s) write to reset the watchdog timer through Register 00[7] (TMR_RST bit).

    Regards,

    Joel H

  • In reply to Joel Hernandez II:

    Sorry, I did not post my main loop that resets the watchdog. Here is the code and the ISR for the battery:

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // disable WDT
    __bis_SR_register( GIE ); // enable global interrupts

    // Setup and initialization
    initGPIO();
    initClocks();
    initBattery();
    initClockTo16MHz();

    while (1)
    {
    // code removed for clarity
    BatteryWD();
    }
    }

    ######################
    peripherals.c
    ######################
    #include <msp430.h>
    #include "peripherals.h"

    unsigned int BQ2416_reset[] = { 0x02, 0x80 }; // Control Register > Reset all registers to default
    unsigned int BQ2416_defaults[] = { 0x02, 0x0D }; // Control Register > Enter Hi-Z Mode, defaults
    unsigned int BQ2416_current[] = { 0x02, 0x2C }; // Control Register > Leave Hi-Z Mode, 500mA current limit
    unsigned int BQ2416_voltage[] = { 0x03, 0x3C }; // Battery Voltage Register > Charge Voltage = 3.8V

    // I2C Write to Battery Charger
    void I2C_write(int byteCount, unsigned int *data)
    {
    B1_Tx_Data = data; // TX data array address
    B1_ByteCtr = byteCount; // load TX byte counter
    UCB1IE |= UCTXIE; // Enable TX interrupt
    UCB1CTL1 |= UCTR | UCTXSTT; // I2C TX, start condition
    _delay_cycles(1500); // allow transmission completion
    while (UCB1STAT & UCBBUSY); // wait for transmission to complete
    }

    // Battery Initialization
    void initBattery(void)
    {
    P8DIR |= BIT5 | BIT6; // P8.5 to UCB1SDA and
    P8SEL |= BIT5 | BIT6; // P8.6 to UCB1SCL

    UCB1CTL1 |= UCSWRST; // Enable SW reset
    UCB1CTL0 = UCMST | UCMODE_3 | UCSYNC; // I2C Master, synchronous mode
    UCB1CTL1 = UCSSEL_2 | UCSWRST; // Use SMCLK, keep SW reset
    UCB1BR0 = 40; // fSCL = SMCLK/40 = ~100kHz
    UCB1BR1 = 0; // high byte of word
    UCB1I2CSA = 0x6B; // BQ24160 Slave Address is 6Bh
    UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
    UCB1IE |= UCNACKIE | UCTXIE; // Enable TX interrupt, NACK interrupt
    UCB1IFG &= ~UCTXIFG; // Clear USCI_B1 TX interrupt flag

    // Control Register > Reset all registers to default (0x02, 0x80)
    I2C_write(2, BQ2416_reset); // I2C write data to register

    // Control Register > Enter Hi-Z Mode, defaults (0x02, 0x0D)
    I2C_write(2, BQ2416_defaults); // I2C write data to register

    // Control Register > Leave Hi-Z Mode, 500mA current limit (0x02, 0x2C)
    I2C_write(2, BQ2416_current); // I2C write data to register

    // Battery Voltage Register > Charge Voltage = 3.8V (0x03, 0x3C)
    I2C_write(2, BQ2416_voltage); // I2C write data to register
    }

    // Battery Watchdog
    void BatteryWD(void)
    {
    B1_Tx_Data[0] = 0x00; // Battery Voltage Register
    B1_Tx_Data[1] = 0x80; // reset watchdog timer
    B1_ByteCtr = 2; // load TX byte counter
    UCB1IE |= UCTXIE; // Enable TX interrupt
    UCB1CTL1 |= UCTR | UCTXSTT; // I2C TX, start condition
    _delay_cycles(2000); // allow transmission completion
    }

    //------------------------------------------------------------------------------
    // The USCIB1_ISR is structured such that it can be used to transmit any
    // number of bytes by pre-loading TXByteCtr with the byte count.
    //------------------------------------------------------------------------------
    #pragma vector = USCI_B1_VECTOR
    __interrupt void USCI_B1_ISR(void)
    {
    switch(__even_in_range(UCB1IV,12))
    {
    case 0: break; // Vector 0: No interrupts
    case 2: break; // Vector 2: ALIFG
    case 4: break; // Vector 4: NACKIFG
    case 6: break; // Vector 6: STTIFG
    case 8: break; // Vector 8: STPIFG
    case 10: // Vector 10: RXIFG
    if (UCB1STAT & UCNACKIFG) // send STOP if slave sends NACK
    {
    UCB1CTL1 |= UCTXSTP;
    UCB1STAT &= ~UCNACKIFG;
    }
    break;
    case 12: // Vector 12: TXIFG
    if (B1_ByteCtr) // Check TX byte counter
    {
    UCB1TXBUF = *B1_Tx_Data++; // Load TX buffer
    B1_ByteCtr--; // Decrement TX byte counter
    }
    else
    {
    UCB1CTL1 |= UCTXSTP; // I2C stop condition
    UCB1IFG &= ~UCTXIFG; // Clear USCI_B1 TX int flag
    }
    default: break;
    }
    }
  • In reply to ezhao:

    Eric, I looked at the charger SW output with a scope and it appears to be generating switching waveforms. i'm assuming it's not in linear regulation mode. I will make more measurements and post them soon.
  • In reply to Bill Watson:

    Bill,

    Is the issue resolved?

    Regards,

    Eric

    Texas Instruments

    Battery Charger Solutions

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.