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.
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!
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.
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.
**Attention** This is a public forum