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.

MSP432P401R: Problems using i2c at other clock speeds other than default 3MHz.

Part Number: MSP432P401R

Hi everyone,

I'm currently trying to communicate with a BQ27441-G1 Fuel Gauge and edit the design capacity using the steps found on page 11 of the technical reference manual (link below).

http://www.ti.com/lit/ug/sluuac9/sluuac9.pdf  

Now with what I've written so far (below), I've been able to write a new design capacity to the BQ27441-G1 successfully.


// Driver Library #include "driverlib.h"
// Standard Library Includes #include <stdbool.h> #include <string.h>
// Toolkit for the BQ27441 Fuel Gauge
#include "BQ27441_Definitions.h" #include "FuelGauge.h" // I2C Master Configuration Parameter const eUSCI_I2C_MasterConfig i2cConfig = { EUSCI_B_I2C_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 3000000, // SMCLK = 3MHz EUSCI_B_I2C_SET_DATA_RATE_100KBPS, // Desired I2C Clock of 100khz 0, // No byte counter threshold EUSCI_B_I2C_NO_AUTO_STOP // No Auto-stop }; int main(void) { // Disabling the Watchdog MAP_WDT_A_holdTimer(); MAP_GPIO_setAsPeripheralModuleFunctionInputPin(I2Cport, SDApin + SCLpin, GPIO_PRIMARY_MODULE_FUNCTION); // Select Port 6 for I2C - Set Pin 4, 5 MAP_I2C_initMaster(EUSCI_module, &i2cConfig); // Initializing I2C Master to SMCLK at 100kbs with no auto-stop MAP_I2C_setSlaveAddress(EUSCI_module, BQ27441_I2C_ADDRESS); // Specify slave address MAP_I2C_setMode(EUSCI_module, EUSCI_B_I2C_TRANSMIT_MODE); // Set Master in transmit mode MAP_I2C_enableModule(EUSCI_module); // Enable I2C Module to start operations MAP_I2C_clearInterruptFlag(EUSCI_module, EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0); // Enable and clear the interrupt flags MAP_Interrupt_enableInterrupt(EUSCI_moduleINT); // Enable master Receive interrupt uint16_t BatCapacity = 1200; // mAh FuelGauge_SetBatteryCap(BatCapacity); int batteryCap = FuelGauge_GetBatteryCap(); int stateOfCharge = FuelGauge_GetStateOfCharge(); int voltage = FuelGauge_GetVoltage(); while (1); }

Where FuelGauge_SetBatteryCap() is a function I wrote that essentially follows the steps on page 11. The other functions also send the appropriate commends to get back what their names imply.

My problem happens when I try to set the DCO clock frequency to something other than the default by adding the driverlib commands...

MAP_CS_setDCOFrequency(8000000);                                                                                               // Setting DCO (clock) to the specified clock speed
MAP_CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);  	// Tie SMCLK to DCO

And changing the frequency in the I2C config...

// I2C Master Configuration Parameter
const eUSCI_I2C_MasterConfig i2cConfig =
{
        EUSCI_B_I2C_CLOCKSOURCE_SMCLK,           // SMCLK Clock Source
	8000000,                                                                       // SMCLK = 8MHz
        EUSCI_B_I2C_SET_DATA_RATE_100KBPS,      // Desired I2C Clock of 100khz
        0,                                                                                     // No byte counter threshold
        EUSCI_B_I2C_NO_AUTO_STOP                           // No Auto-stop
};

My function FuelGauge_SetBatteryCap() will try and retrieve the old checksum value from the BQ27441-G1 (step 7) and get 0x00 back which is unexpected. Then when the new checksum is calculated
from this value and sent to the BQ27441-G1 (step 11), it doesn't acknowledge.

Is there something wrong with the way I'm changing the DCO frequency that is making the I2C malfunction? Is the point at which its failing during design capacity setup have something to do with it?

Thanks in advance!
  • Sorry for the formatting error. I'm a little new to posting. The text tacked onto that last code block is this...

    " My function FuelGauge_SetBatteryCap() will try and retrieve the old checksum value from the BQ27441-G1 (step 7) and get 0x00 back which is unexpected. Then when the new checksum is calculatedfrom this value and sent to the BQ27441-G1 (step 11), it doesn't acknowledge. Is there something wrong with the way I'm changing the DCO frequency that is making the I2C malfunction? Is the point at which its failing during design capacity setup have something to do with it?

    Thanks in advance!"
  • Austin,
    Have you looked at this example for setting the DCO? dev.ti.com/.../

    I am curious if you are using the following lines:

    /* Enabling FPU for DCO Frequency calculation */
    MAP_FPU_enableModule();

    /* Setting the DCO Frequency to a non-standard 8MHz */
    MAP_CS_setDCOFrequency(8000000);

    The center frequencies are 48, 24, 12, 6, 3, and 1.5. 8Mhz will require a calculation. It would also be good to verify the frequency of SMCLK by outputting to a pin (HSMCLK on pin 4.4).

    Regards,
    Chris
  • Hi Chris,

    So I ran the code below with the added lines you suggested and the I2C communication with the Fuel Gauge still failed at the same point. 

    // Driver Library
    #include <driverlib.h>
    // Standard Library Includes
    #include <stdbool.h>
    #include <string.h>
    // Toolkit for the BQ27441 Fuel Gauge
    #include "FuelGauge.h"
    #include "Helpers.h"
    
    // I2C Master Configuration Parameter
    const eUSCI_I2C_MasterConfig i2cConfig =
    {
            EUSCI_B_I2C_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
    		8000000,                                // SMCLK = 8MHz
            EUSCI_B_I2C_SET_DATA_RATE_100KBPS,      // Desired I2C Clock of 100khz
            0,                                      // No byte counter threshold
            EUSCI_B_I2C_NO_AUTO_STOP                // No Auto-stop
    };
    
    int main(void)
    {
    
        // Disabling the Watchdog
        MAP_WDT_A_holdTimer();
    
        MAP_FPU_enableModule();
    
        MAP_CS_setDCOFrequency(8000000);    // Setting DCO (clock) to the specified clock speed
        MAP_CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);  	// Tie SMCLK to DCO
    
        MAP_GPIO_setAsPeripheralModuleFunctionInputPin(I2Cport, SDApin + SCLpin, GPIO_PRIMARY_MODULE_FUNCTION); 		// Select Port 6 for I2C - Set Pin 4, 5
        MAP_I2C_initMaster(EUSCI_module, &i2cConfig);     		// Initializing I2C Master to SMCLK at 100kbs with no auto-stop
        MAP_I2C_setSlaveAddress(EUSCI_module, BQ27441_I2C_ADDRESS); 	// Specify slave address
        MAP_I2C_setMode(EUSCI_module, EUSCI_B_I2C_TRANSMIT_MODE); 		// Set Master in transmit mode
        MAP_I2C_enableModule(EUSCI_module); 			// Enable I2C Module to start operations
        MAP_I2C_clearInterruptFlag(EUSCI_module, EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0); 	// Enable and clear the interrupt flags
        MAP_Interrupt_enableInterrupt(EUSCI_moduleINT); 		// Enable master Receive interrupt
    
        MAP_Interrupt_enableMaster();
    
        uint16_t BatCapacity = 1000; // mAh
    
        FuelGauge_SetBatteryCap(BatCapacity); 
        int batteryCap = FuelGauge_GetBatteryCap();
        int stateOfCharge = FuelGauge_GetStateOfCharge();
        int voltage = FuelGauge_GetVoltage();
    
        while (1);
    }

    I also ran the DCO setting example you recommended just to make sure the SMCLK was at the correct frequency and I measured it at about 8,058,017 Hz when set to 8 MHz which seems close enough. 

    I did manage to get the above code to work when I accidentally left the clock frequency in i2cConfig at 8000000 and set the DCO frequency at 3MHz which I can't explain. I verified these conditions a second time and it seemed to work consistently. 

  • Austin,
    I have tried running a couple of examples and not seeing an issue by changing the frequency. I see in your comments that you are trying to enable the receive interrupt, although I do not see the api call MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0); . Also, I do see that you are seetin the EUSCI to transmit mode, instead of recieve mode: MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_MODE);.

    Are both the transmit and receive functions working properly at 3Mhz and then only the transmit works when you move the DCO to 8Mhz?

    Thanks,
    Chris
  • Inside the function FuelGauge_SetBatteryCap() I do multibyte transfer and then set the module to receive mode and use an interrupt to receive only (snippet below). Sorry for not including this bit earlier.

    void FuelGauge_SetBatteryCap(uint16_t batCap)
    {
    
    	//------------- Transmit ---------------
    	EUSCI_TXBuffer &= 0x00;                                                        // Clear Transmit Buffer
    	MAP_I2C_masterSendMultiByteStart(EUSCI_module, BQ27441_COMMAND_CONTROL);
    	MAP_I2C_masterSendMultiByteNext(EUSCI_module, BQ27441_CONTROL_DEVICE_TYPE);
    	MAP_I2C_masterSendMultiByteNext(EUSCI_module, 0x00);
    	MAP_I2C_masterSendMultiByteStop(EUSCI_module);
    
    	EUSCI_TXBuffer &= 0x00;                                                        // Clear Transmit Buffer
    	MAP_I2C_masterSendSingleByte(EUSCI_module,0x00);
    
    	//------------- Receive ----------------                                       //************************NOTE*************************
    	NUM_OF_REC_BYTES = 2;                                                          // NUM_OF_REC_BYTES accepts values of 2 or greater only
    	MAP_I2C_setMode(EUSCI_module, EUSCI_B_I2C_RECEIVE_MODE);                       // Set to Receive mode
    	MAP_I2C_masterReceiveStart(EUSCI_module);                                      // Start Receiving
    	MAP_I2C_enableInterrupt(EUSCI_module, EUSCI_B_I2C_RECEIVE_INTERRUPT0);         // Enable Receive Interrupt
    	xferIndex = 0;                                                                 // Set RXData index to 0
    	while(rxFlag != 1);                                                            // Wait until receive interrupt flag is received
    	rxFlag = 0;

    But to answer your question, both receive and transmit functions work fine at 3 MHz (without calling setDCOFrequency() ) and I'm able to make it through the whole sequence (the Fuel Gauge procedure) just fine however if I include the call to set the DCO frequency at all (whether its to 3 MHz or 8MHz), the I2C communication works but stops at a very specific point when editing the memory of the Fuel Gauge.

  • Sorry for the delay in response. Please the discussion and examples in this thread: e2e.ti.com/.../2117452

    Regards,
    Chris

**Attention** This is a public forum