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.

CCS/BQ27441-G1: Reading from BQ with MSP430F5529

Part Number: BQ27441-G1
Other Parts Discussed in Thread: MSP430F5529

Tool/software: Code Composer Studio

Hello TI team, 

I'm working on MSP430F5529LP with the Fuel Tank MKII Battery BoosterPack to read from the BQ27441 fuel gauge the value of SOC. 
I started  my work  based an old project developed by TI on MSP_EXP432P401R. 

The UART section work fine and I can see the character on my terminal. But as it expected I can't read from BQ27441. 

This is my I2C function to read :

bool I2C_read16(unsigned char pointer, short * result, unsigned int timeout)
{
    uint8_t val = 0;
    uint8_t valScratch = 0;
    short r = 0;

    /* Set master to transmit mode PL */
    USCI_B_I2C_setMode(I2C_BASE,
        USCI_B_I2C_TRANSMIT_MODE);

    /* Clear any existing interrupt flag PL */
    USCI_B_I2C_clearInterrupt(I2C_BASE,
        USCI_B_I2C_TRANSMIT_INTERRUPT);

    /* Initiate start and send first character */
    if (!USCI_B_I2C_masterSendSingleByteWithTimeout(USCI_B0_BASE, pointer, timeout))
    	return 0;

    /*
     * Generate Start condition and set it to receive mode.
     * This sends out the slave address and continues to read
     * until you issue a STOP
     */
    USCI_B_I2C_masterReceiveSingleStart(I2C_BASE);

    /* Wait for RX buffer to fill */
    while(!(USCI_B_I2C_getInterruptStatus(I2C_BASE,
        USCI_B_I2C_RECEIVE_INTERRUPT)));

    /* Read from I2C RX register */
    valScratch = USCI_B_I2C_masterReceiveMultiByteNext(I2C_BASE);

    /* Receive second byte then send STOP condition */
    if (!USCI_B_I2C_masterReceiveMultiByteFinishWithTimeout(I2C_BASE, &val, timeout))
    	return 0;

    /* Shift val to top MSB */
    r = (val << 8);

    /* Read from I2C RX Register and write to LSB of r */
    r |= valScratch;

    /* Return temperature value */
    *result = r;

    return 1;
}

any condition in this code always back return 0 . for exemple this "if (!USCI_B_I2C_masterSendSingleByteWithTimeout(USCI_B0_BASE, pointer, timeout))"

bool USCI_B_I2C_masterSendMultiByteStartWithTimeout(uint16_t baseAddress,
                                                    uint8_t txData,
                                                    uint32_t timeout)
{
    //Store current transmit interrupt enable
    uint8_t txieStatus = HWREG8(baseAddress + OFS_UCBxIE) & UCTXIE;

    //Disable transmit interrupt enable
    HWREG8(baseAddress + OFS_UCBxIE) &= ~(UCTXIE);

    //Send start condition.
    HWREG8(baseAddress + OFS_UCBxCTL1) |= UCTR + UCTXSTT;

    //Poll for transmit interrupt flag.
    while((!(HWREG8(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout)
    {
        ;
    }

    //Check if transfer timed out
    if(timeout == 0)
    {
        return (STATUS_FAIL);
    }

    //Send single byte data.
    HWREG8(baseAddress + OFS_UCBxTXBUF) = txData;

    //Reinstate transmit interrupt enable
    HWREG8(baseAddress + OFS_UCBxIE) |= txieStatus;

    return(STATUS_SUCCESS);
}

Please can Anyone show me the error ? 

  • Hi Amine,

    Pls review the app note below and see if it helps.
    r.search.yahoo.com/.../RS=0ZZ7FFKPj53q9PEXvGTOMbr6mbU-

    thanks
    Onyx
  • Hi Onyx, 

    Thank you for your response. 
    Unfortunately, this resource can't help me because I'm converting codes from MSP432 to MSP430F5529,  not writing them.

    The conversion  is work fine for UART communication but I still have problem in I2C part. 

    This is the I2C_read16 function of the MSP432 : 

    bool I2C_read16(unsigned char pointer, short * result, unsigned int timeout)
    {
        uint8_t val = 0;
        uint8_t valScratch = 0;
        short r = 0;
    
        /* Set master to transmit mode PL */
        I2C_setMode(EUSCI_B1_BASE,
            EUSCI_B_I2C_TRANSMIT_MODE);
    
        /* Clear any existing interrupt flag PL */
        I2C_clearInterruptFlag(EUSCI_B1_BASE,
            EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
        /* Initiate start and send first character */
        if (!I2C_masterSendSingleByteWithTimeout(EUSCI_B1_BASE, pointer, timeout))
        	return 0;
    
        /*
         * Generate Start condition and set it to receive mode.
         * This sends out the slave address and continues to read
         * until you issue a STOP
         */
        I2C_masterReceiveStart(EUSCI_B1_BASE);
    
        /* Wait for RX buffer to fill */
        while(!(I2C_getInterruptStatus(EUSCI_B1_BASE,
            EUSCI_B_I2C_RECEIVE_INTERRUPT0)));
    
        /* Read from I2C RX register */
        valScratch = I2C_masterReceiveMultiByteNext(EUSCI_B1_BASE);
    
        /* Receive second byte then send STOP condition */
        if (!I2C_masterReceiveMultiByteFinishWithTimeout(EUSCI_B1_BASE, &val, timeout))
        	return 0;
    
        /* Shift val to top MSB */
        r = (val << 8);
    
        /* Read from I2C RX Register and write to LSB of r */
        r |= valScratch;
    
        /* Return temperature value */
        *result = r;
    
        return 1;
    }

    And this is my own I2C_read16 function after conversion :

    bool I2C_read16(unsigned char pointer, short * result, unsigned int timeout)
    {
        uint8_t val = 0;
        uint8_t valScratch = 0;
        short r = 0;
    
        /* Set master to transmit mode PL */
        USCI_B_I2C_setMode(I2C_BASE,
            USCI_B_I2C_TRANSMIT_MODE);
    
        /* Clear any existing interrupt flag PL */
        USCI_B_I2C_clearInterrupt(I2C_BASE,
            USCI_B_I2C_TRANSMIT_INTERRUPT);
    
        /* Initiate start and send first character */
        if (!USCI_B_I2C_masterSendSingleByteWithTimeout(USCI_B1_BASE, pointer, timeout))
        	return 0;
    
        /*
         * Generate Start condition and set it to receive mode.
         * This sends out the slave address and continues to read
         * until you issue a STOP
         */
        USCI_B_I2C_masterReceiveSingleStart(I2C_BASE);
    
        /* Wait for RX buffer to fill */
        while(!(USCI_B_I2C_getInterruptStatus(I2C_BASE,
            USCI_B_I2C_RECEIVE_INTERRUPT)));
    
        /* Read from I2C RX register */
        valScratch = USCI_B_I2C_masterReceiveMultiByteNext(I2C_BASE);
    
        /* Receive second byte then send STOP condition */
        if (!USCI_B_I2C_masterReceiveMultiByteFinishWithTimeout(I2C_BASE, &val, timeout))
        	return 0;
    
        /* Shift val to top MSB */
        r = (val << 8);
    
        /* Read from I2C RX Register and write to LSB of r */
        r |= valScratch;
    
        /* Return temperature value */
        *result = r;
    
        return 1;
    }

    After debugging there is a problem with USCI_B_I2C_masterSendSingleByteWithTimeout function. It return 0 , so the I2C_read16 function return 0 too.

    I have two main questions: 
    1- Is it possible to communicate with BQ27441 on Fuel Tank MKII Battery BoosterPack with the MSP430F5529 ??

    2- Can you correct my code if you found something wrong ??

    Thank you. 

  • Amine,

    One of our programming experts will look into this and get back to you latest by tomorrow.

    thanks

    Onyx

  • 1: There is nothing particular to the bq27441 that would prevent it from working.

    2: From a gauge point of view, your code looks correct (if you just want to read a standard command, like SOC or Voltage).

    The main problem is with porting the example code to the MSP430F5529 USCI. It's a bit more involved than just matching the APIs from eUSCI to USCI. For example GPIO and clock setup must also be done specific to the F5529 and your particular setup.

    Here is an app note that discusses porting between eUSCI and USCI. Reading results from the gauge is just a standard two byte read transaction so if this doesn't work, it's likely not gauge related. Please hook up an I2C analyzer or a scope to check if SCL and SDA behave as expected. 

     

  • Hello Onyx and Dominik, 

    Thank you for your assistance. 
    Dominik, thank you for the file, but it look very general and basic. I will read it and focus on it many times. 

    Talking about matching the APIs from eUSCI to USCI, I did my best to do it in the right way, like setting the GPIO and the clock .  I will show you my setting, maybe I did something wrong
    I2C init : 


    /* I2C Master Configuration Parameter */
    USCI_B_I2C_initMasterParam i2cParam =
    {
            USCI_B_I2C_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
    		8000000,                               // SMCLK = 8MHz
    		USCI_B_I2C_SET_DATA_RATE_400KBPS      // Desired I2C Clock of 400khz
    };
    
    
    void I2C_initGPIO()
    {
        /* Select I2C function for I2C_SCL & I2C_SDA */
        GPIO_setAsPeripheralModuleFunctionOutputPin(
        		I2C_SCL_PORT,     // GPIO_PORT_P3
    			I2C_SCL_PIN       // GPIO_PIN2
    			);
    
        GPIO_setAsPeripheralModuleFunctionOutputPin(
        		I2C_SDA_PORT,    // GPIO_PORT_P3
    			I2C_SDA_PIN      // GPIO_PIN1
    			);
    }
    
    
    /***************************************************************************//**
     * @brief  Configures I2C
     * @param  none
     * @return none
     ******************************************************************************/
    
    void I2C_init(void)
    {
            /* Initialize USCI_B0 and I2C Master to communicate with slave devices*/
        USCI_B_I2C_initMaster(I2C_BASE, &i2cParam);
    
        /* Disable I2C module to make changes */
        USCI_B_I2C_disable(I2C_BASE);
    
        /* Enable I2C Module to start operations */
        USCI_B_I2C_enable(I2C_BASE);
    
        return;
    }

    And the clock setting I declared in the main like that [ initClocks(8000000); ] and this is the function :

    void initClocks(DWORD mclkFreq)
    {
        // Assign the REFO as the FLL reference clock
    	UCS_initClockSignal(
    	   UCS_FLLREF,
    	   UCS_REFOCLK_SELECT,
    	   UCS_CLOCK_DIVIDER_1);
    
    	// Assign the REFO as the source for ACLK
    	UCS_initClockSignal(
    	   UCS_ACLK,
    	   UCS_REFOCLK_SELECT,
    	   UCS_CLOCK_DIVIDER_1);
    
        UCS_initFLLSettle(
            mclkFreq/1000,
            mclkFreq/32768);
            //use REFO for FLL and ACLK
            UCSCTL3 = (UCSCTL3 & ~(SELREF_7)) | (SELREF__REFOCLK);
            UCSCTL4 = (UCSCTL4 & ~(SELA_7)) | (SELA__REFOCLK);
    
    }

    One other problem, after debugging my code and run it step by step I found that it stop on the same condition 

    //Poll for transmit interrupt flag.
       while((!(HWREG8(baseAddress + OFS_UCBxIFG) & UCTXIFG)) && --timeout2)
       {
           ;
        }

    What this condition mean, it's waiting interrupt flag to be cleared ? and as a consequence there is no communication between the MSP430 and the BQ27441 ??

    Thank you for your help.

  • Hello, 

    Anyone can help me here !!?

    Thx.

  • The gauge team doesn't have detailed information about microcontroller configuration. The problem appears to be with the MSP430 I2C engine and not the gauge so this should be posted in the MSP430 forum.

    e2e.ti.com/.../msp430

    I can't move this to this forum directly but I suggest you post this in the MSP430 forum where the TI experts for the MSP430 and its peripherals will be able to help you.
  • Okay Dominik. Thank you for your advice.