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.

MSP430G2553 I2C problem

Other Parts Discussed in Thread: MSP430G2553, ENERGIA, LDC1614

Hi ,

I am communicating with MMA8452Q Accelerometer. 

I don't think this is an hardware problem, since I have pullups resistor(10k).

My code is;

-main.c is;

#include "msp430G2553.h"
#include "TI_USCI_I2C_master.h"

#define LED1 0x1

unsigned char MMA_ADDRESS = 0x1D;
unsigned char WHO_AM_I = 0x0D;

unsigned char array[2] = { 0, 0 };


void whoami()
{
TI_USCI_I2C_transmitinit(MMA_ADDRESS , 12); // init transmitting with accel slave Address
while ( TI_USCI_I2C_notready() ); // wait for bus to be free
TI_USCI_I2C_transmit(1,WHO_AM_I); // transmit WITHOUT a stopbit

TI_USCI_I2C_receiveinit(MMA_ADDRESS , 12); // init receiving with USCI
while ( TI_USCI_I2C_notready() ); // wait for bus to be free
TI_USCI_I2C_receive(1,array);

LPM0;
}

int main(void) {

WDTCTL = WDTPW + WDTHOLD; // Disable Watchdog

P1DIR |= 0x01; 

whoami();
if(array[0]==0x2A || array[1]==0x2A )
{
P1OUT ^= 0x01;
}

LPM0;

return 0;
}

-TI_USCI_I2C_master.c  is;

#include <msp430g2553.h> // device specific header
//#include "msp430x22x4.h"
//#include "msp430x23x0.h"
//#include "msp430xG46x.h"
// ... // more devices are possible

#include "TI_USCI_I2C_master.h"

signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;

//------------------------------------------------------------------------------
// void TI_USCI_I2C_receiveinit(unsigned char slave_address,
// unsigned char prescale)
//
// This function initializes the USCI module for master-receive operation.
//
// IN: unsigned char slave_address => Slave Address
// unsigned char prescale => SCL clock adjustment
//-----------------------------------------------------------------------------
void TI_USCI_I2C_receiveinit(unsigned char slave_address,
unsigned char prescale){
P1SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0
P1SEL2 |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0
UCB0CTL1 = UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = prescale; // set prescaler
UCB0BR1 = 0;
UCB0I2CSA = slave_address; // set slave address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0I2CIE = UCNACKIE;
IE2 = UCB0RXIE; // Enable RX interrupt
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmitinit(unsigned char slave_address,
// unsigned char prescale)
//
// This function initializes the USCI module for master-transmit operation.
//
// IN: unsigned char slave_address => Slave Address
// unsigned char prescale => SCL clock adjustment
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmitinit(unsigned char slave_address,
unsigned char prescale){
P1SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0
P1SEL2 |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0
UCB0CTL1 = UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = prescale; // set prescaler
UCB0BR1 = 0;
UCB0I2CSA = slave_address; // Set slave address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0I2CIE = UCNACKIE;
IE2 = UCB0TXIE; // Enable TX ready interrupt
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-receiver mode.
//
// IN: unsigned char byteCount => number of bytes that should be read
// unsigned char *field => array variable used to store received data
//------------------------------------------------------------------------------
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){
TI_receive_field = field;
if ( byteCount == 1 ){
byteCtr = 0 ;
__disable_interrupt();
UCB0CTL1 |= UCTXSTT; // I2C start condition
while (UCB0CTL1 & UCTXSTT); // Start condition sent?
UCB0CTL1 |= UCTXSTP; // I2C stop condition
__enable_interrupt();
} else if ( byteCount > 1 ) {
byteCtr = byteCount - 2 ;
UCB0CTL1 |= UCTXSTT; // I2C start condition
} else
while (1); // illegal parameter
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-transmit mode.
//
// IN: unsigned char byteCount => number of bytes that should be transmitted
// unsigned char *field => array variable. Its content will be sent.
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){
TI_transmit_field = field;
byteCtr = byteCount;
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
}

//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)
//
// This function is used to look for a slave address on the I2C bus.
//
// IN: unsigned char slave_address => Slave Address
// OUT: unsigned char => 0: address was not found,
// 1: address found
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){
unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;
ucb0i2cie = UCB0I2CIE; // restore old UCB0I2CIE
ie2_bak = IE2; // store IE2 register
slaveadr_bak = UCB0I2CSA; // store old slave address
UCB0I2CIE &= ~ UCNACKIE; // no NACK interrupt
UCB0I2CSA = slave_address; // set slave address
IE2 &= ~(UCB0TXIE + UCB0RXIE); // no RX or TX interrupts
__disable_interrupt();
UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP; // I2C TX, start condition
while (UCB0CTL1 & UCTXSTP); // wait for STOP condition

returnValue = !(UCB0STAT & UCNACKIFG);
__enable_interrupt();
IE2 = ie2_bak; // restore IE2
UCB0I2CSA = slaveadr_bak; // restore old slave address
UCB0I2CIE = ucb0i2cie; // restore old UCB0CTL1
return returnValue; // return whether or not
// a NACK occured
}

//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_notready()
//
// This function is used to check if there is commuincation in progress.
//
// OUT: unsigned char => 0: I2C bus is idle,
// 1: communication is in progress
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_notready(){
return (UCB0STAT & UCBBUSY);
}


#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
if (UCB0STAT & UCNACKIFG){ // send STOP if slave sends NACK
UCB0CTL1 |= UCTXSTP;
UCB0STAT &= ~UCNACKIFG;
}

}


#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
if (IFG2 & UCB0RXIFG){
if ( byteCtr == 0 ){
UCB0CTL1 |= UCTXSTP; // I2C stop condition
*TI_receive_field = UCB0RXBUF;
TI_receive_field++;
}
else {
*TI_receive_field = UCB0RXBUF;
TI_receive_field++;
byteCtr--;
}
}
else {
if (byteCtr == 0){
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
}
else {
UCB0TXBUF = *TI_transmit_field;
TI_transmit_field++;
byteCtr--;
}
}
}

Thanks,

 

  • Don’t expect us to buy the accelerometer and test your code to figure out what is wrong.

    If you have a problem, then please describe the problem in detail. What did you do, what did you expect and what did or did not happen?
    Any tests with scope or logic analyzer? Link to the sensor datasheet?

    Maybe your code has no obvious bugs, it just wasn’t written to do what you thought it should do. We can’t tell because we don’t know your intention is.
    This is not limited to the I2C part.

    For a clock speed of ~100kHz, 10k might be not strong enough. It depends on line length and capacitance, as well as the number of slaves (and sometimes the type: CMOS or older LS type inputs)

    However, one thing I can say for sure: TI_USCI_I2C_transmit() expects a char* as second argument, but “WHO_AM_I” is a char, you need to pass “&WHO_AM_I” to pass the reference. Don’t you get a compiler warning?

  • Hi Turhan, would you please send me a link to download TI_USCI_I2C_master.h library? It seems that everibody knowns it but I just can't find it. Actually I've found different things under this name so I dont' know which is the correct one. Is it compatible with Code Composer Studio?
    I'm starting with I2C in a MSP430G2553.
    Thanks.
  • There are thirteen I2C examples for the G2553 at: www.ti.com/.../slac485
    with the name: msp430g2xx3_uscib0_i2c

    I think there is one dma and one non-dma i2c library:http://www.ti.com/general/docs/litabsmultiplefilelist.tsp?literatureNumber=slaa382

  • Tony, yes I've worked with this examples but they don't use TI_USCI_I2C_master.h library.
    Slaa382 explain how to use this library, but I couldn find any link for downloading it.

    I would like to use it because it makes easier to work with I2C.

    It seems that it comes from year 2007, may be it is not updated and suitable to work with MSP430G2553 and CCS?
    Best regards.

  • Well I finally found TI_USCI_I2C_master.h library, I copy it below.
    Honestly, with so may articles referencing this library, I had thought it was a bigger piece of software.
    Regards. Petrus



    //=======================TI_USCI_I2C_master.h======

    #ifndef USCI_LIB
    #define USCI_LIB

    #define SDA_PIN BIT7
    #define SCL_PIN BIT6

    //#define SDA_PIN 0x02 // msp430x261x UCB0SDA pin
    //#define SCL_PIN 0x04 // msp430x261x UCB0SCL pin

    void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale);
    void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale);


    void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field);
    void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field);


    unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address);
    unsigned char TI_USCI_I2C_notready();


    #endif
  • Hello Petrus,

    I would like to know your progress on using basic I2C? I am also working on an application that uses I2C. so,  planning to use the I2C master library. Any tips are suggestions would be helpful. 

    Thanks, 

  • Hi Santosh,
    The first thing I did was run some of the "msp430g2xx3_uscib0_i2c" examples that come with CCS, and they were very helpful to start and see some response from the components. They show how to manage I2C communication by low-level programming (you have to manage every bit).

    Besides you have a lot of examples for Arduino platform, which runs on Energia. At the end of this post you'll find a working example that communicates with a MMA8652 freescale accelerometer by using the wire.h library. For an improved debug you can import an Energia project to CCS and I did so. It worked, by first time I got an answer from my accelerometer, the thing is that the Energia-CCS conversion incorporates many libraries and software accessories, and you loose some control over you project.

    While searching I understood that theTI_USCI_I2C_master.h library is mentioned by everybody so it seems it is the thing we need to work with I2C in CCS with a MSP430G2553. It is supposed to facilitate the interface programming.
    In my case, just I found it but didn't try it yet, I have to do it on the next days. Actually it looked to me too short, we will see. But I don't have an MMA8652 example using this library so I'll have to develop it.

    Hope this to be helpful to you. What is your application about?
    Best Regards.
    Petrus

    ________________________________________________________________________________________________________
    //Arduino Example MSP430G2553 communicating via I2C with a MMA8652 accelerometer

    #include <Wire.h>

    // I2C BUS: already defined in "wire" librairy
    // SDA: PIN 2 with pull up 4.7K to 3.3V on arduino Micro
    // SCL: PIN 3 with pull up 4.7K to 3.3V on arduino Micro
    // Accelerometer connected to +3.3V of arduino DO NOT CONNECT TO 5V (this will destroy the accelerometer!)
    // all GND Pin of accelerometer connected to gnd of arduino

    /********************ACCELEROMETER DATAS************/
    // adresss of accelerometer
    int adress_acc=0X1D; // MMA8653FC and MMA8652FC
    // adress of registers for MMA8653FC
    int ctrl_reg1 = 0x2A;
    int ctrl_reg2 = 0x2B;
    int ctrl_reg3 = 0x2C;
    int ctrl_reg4 = 0x2D;
    int ctrl_reg5 = 0x2E;
    int int_source = 0x0C;
    int status_ = 0x00;
    int f_setup = 0x09;
    int out_x_msb = 0x01;
    int out_y_msb = 0x03;
    int out_z_msb = 0x05;
    int sysmod = 0x0B;
    int xyz_data_cfg = 0x0E;

    /******PROGRAM DATAS**********/
    int result [3];
    int axeXnow ;
    int axeYnow ;
    int axeZnow ;


    void setup(){
    Wire.begin(); // start of the i2c protocol
    Serial.begin(9600); // start serial for output
    ACC_INIT(); // initialize the accelerometer by the i2c bus. enter the sub to adjust the range (2g, 4g, 8g), and the data rate (800hz to 1,5Hz)
    }

    //------------------------------------------------------------------

    void loop()
    {
    I2C_READ_ACC(0x00); // to understand why 0x00 and not 0x01, look at the data-sheet p.19 or on the comments of the sub. This is valid only becaus we use auto-increment
    // NOTE: This communication is taking a little less than 1ms to be done. (for data-rate calculation for delay)
    Serial.print(axeXnow);
    Serial.print(";");
    Serial.print(axeYnow);
    Serial.print(";");
    Serial.print(axeZnow);
    Serial.print(";");
    Serial.println();
    delay(50);
    }

    //------------------------------------------------------------------

    void ACC_INIT()
    {
    I2C_SEND(ctrl_reg1 ,0X00); // standby to be able to configure
    delay(10);

    I2C_SEND(xyz_data_cfg ,B00000000); // 2G full range mode
    delay(1);
    // I2C_SEND(xyz_data_cfg ,B00000001); // 4G full range mode
    // delay(1);
    // I2C_SEND(xyz_data_cfg ,B00000010); // 8G full range mode
    // delay(1);

    I2C_SEND(ctrl_reg1 ,B00000001); // Output data rate at 800Hz, no auto wake, no auto scale adjust, no fast read mode
    delay(1);
    // I2C_SEND(ctrl_reg1 ,B00100001); // Output data rate at 200Hz, no auto wake, no auto scale adjust, no fast read mode
    // delay(1);
    // I2C_SEND(ctrl_reg1 ,B01000001); // Output data rate at 50Hz, no auto wake, no auto scale adjust, no fast read mode
    // delay(1);
    // I2C_SEND(ctrl_reg1 ,B01110001); // Output data rate at 1.5Hz, no auto wake, no auto scale adjust, no fast read mode
    // delay(1);
    }

    //------------------------------------------------------------------

    void I2C_SEND(unsigned char REG_ADDRESS, unsigned char DATA) //SEND data to MMA7660
    {

    Wire.beginTransmission(adress_acc);
    Wire.write(REG_ADDRESS);
    Wire.write(DATA);
    Wire.endTransmission();
    }

    //------------------------------------------------------------------

    void I2C_READ_ACC(int ctrlreg_address) //READ number data from i2c slave ctrl-reg register and return the result in a vector
    {
    byte REG_ADDRESS[7];
    int accel[4];
    int i=0;
    Wire.beginTransmission(adress_acc); //=ST + (Device Adress+W(0)) + wait for ACK
    Wire.write(ctrlreg_address); // store the register to read in the buffer of the wire library
    Wire.endTransmission(); // actually send the data on the bus -note: returns 0 if transmission OK-
    Wire.requestFrom(adress_acc,7); // read a number of byte and store them in wire.read (note: by nature, this is called an "auto-increment register adress")

    for(i=0; i<7; i++) // 7 because on datasheet p.19 if FREAD=0, on auto-increment, the adress is shifted
    // according to the datasheet, because it's shifted, outZlsb are in adress 0x00
    // so we start reading from 0x00, forget the 0x01 which is now "status" and make the adapation by ourselves
    //this gives:
    //0 = status
    //1= X_MSB
    //2= X_LSB
    //3= Y_MSB
    //4= Y_LSB
    //5= Z_MSB
    // 6= Z_LSB
    {
    REG_ADDRESS[i]=Wire.read(); //each time you read the write.read it gives you the next byte stored. The couter is reset on requestForm
    }


    // MMA8653FC gives the answer on 10bits. 8bits are on _MSB, and 2 are on _LSB
    // this part is used to concatenate both, and then put a sign on it (the most significant bit is giving the sign)
    // the explanations are on p.14 of the 'application notes' given by freescale.
    for (i=1;i<7;i=i+2)
    {
    accel[0] = (REG_ADDRESS[i+1]|((int)REG_ADDRESS[i]<<8))>>6; // X
    if (accel[0]>0x01FF) {accel[1]=(((~accel[0])+1)-0xFC00);} // note: with signed int, this code is optional
    else {accel[1]=accel[0];} // note: with signed int, this code is optional
    switch(i){
    case 1: axeXnow=accel[1];
    break;
    case 3: axeYnow=accel[1];
    break;
    case 5: axeZnow=accel[1];
    break;
    }
    }

    }

    //------------------------------------------------------------------

    void I2C_READ_REG(int ctrlreg_address) //READ number data from i2c slave ctrl-reg register and return the result in a vector
    {
    unsigned char REG_ADDRESS;
    int i=0;
    Wire.beginTransmission(adress_acc); //=ST + (Device Adress+W(0)) + wait for ACK
    Wire.write(ctrlreg_address); // register to read
    Wire.endTransmission();
    Wire.requestFrom(adress_acc,1); // read a number of byte and store them in write received
    }
  • Hello Petrus,

    I did try to run the examples in ccs but I dont know how to see any response on the oscilloscope. Did you use a scope to see the response of the i2c bus or anything else?

    And my application is with LDC1614 (INDUCTANCE TO DIGITAL CONVERTER)

    I also tried GRACE and the code example given in main.cfg files and when I compile, It gave a bunch of errors. 

    Thanks,

  • Santosh, for scope signals please refer to my other post: e2e.ti.com/.../406022 "MMA Accelerometer Basic example". There Dennis Eichmann gives some explanations about the signals that you can expect.
    In my case, I used the oscilloscope to see if something was happening on the SCL and SDA lines, mostly to detect hardware trouble. At this level it is a good practice to make your program iterate in order to facilitate signal detection.
    Once you receive a response from your i2c peripheral and you know it is alive, you can debug easier with CCSs debugging features, for example by displaying the expressions (variables values).
    At the beginning it is a difficult job, because you work with two unknowns: you don't know if the device is alive or if the software is ok. It helps if you find a working example code for your component and CCS, it was not my case.
    Best regards.
    Petrus

**Attention** This is a public forum