Electrical – I2C driver for MSP432

ci2cmsp430pullupserial

I am trying to develop a I2C driver for MSP432. As of now, I am interfacing a accelerometer through USCI B2_ module on MSP432.

The problem that I am facing is I am getting a NACK in the IFG register when I generate a start condition.

  • What might be the potential issue in the code?

Attached below is the code. Please indicate any mistakes that I made while developing the i2c_write_byte function.

Also:

  • Do I need to have additional pull-up resistors on the SDA and SCL lines?

I have not added additional external pull-up resistors since my sensor already has the pull-up resistors included.

      /**
 * @file i2c.c
 * @brief This file is to be used for the setting the I2C peripheral of the microcontroller.
 * @author Vikrant Waje
 * @date November 18, 2018
 *
 */

//***********************************************************************************
// Include files
//***********************************************************************************
#include"main.h"


//***********************************************************************************
// Global variables
//***********************************************************************************


//***********************************************************************************
// Function implementation
//***********************************************************************************
/*------------------------------------------------------------------------------------------------------------------------------------*/
/*
  @brief: Setup the I2C peripheral.


 @param: None
 @param:None

 @return: None
 */
/*-----------------------------------------------------------------------------------------------------------------------------*/
void i2c_setup(){
    i2c_gpio_setup();
    i2c_set_parameters();
    i2c_enable();
}
/*------------------------------------------------------------------------------------------------------------------------------------*/
/*
  @brief: Assign GPIO to I2C peripherals.
  SCL = P3.7 (UCSI B)(SEL1 =0 , SEL0 = 1 )
  SDA = P3.6 (UCSI B)(SEL1 =0 , SEL1 = 1)

 @param: None
 @param:None

 @return: None
 */
/*-----------------------------------------------------------------------------------------------------------------------------*/
void i2c_gpio_setup(){
   // SCL->SEL1 |=BIT0;
    P3->SEL0 |= (BIT6 | BIT7); //P3_SEL0.7 = 1 and P3_SEL0.6 = 1
}
/*------------------------------------------------------------------------------------------------------------------------------------*/
/*
  @brief: Set the parameters for I2C peripherals.


 @param: None
 @param:None

 @return: None
 */
/*-----------------------------------------------------------------------------------------------------------------------------*/
void i2c_set_parameters(){

   /* I2C_Init_Typedef * i2c_struct = malloc(sizeof(I2C_Init_Typedef));

    i2c_struct->enable = enable_false; // Enable Software reset
    i2c_struct->mode = I2C; //Enable I2C mode
    i2c_struct->master = master_mode; // Enable master mode
    i2c_struct->sync_mode =sync_mode_enable; //Enable sync mode
    i2c_struct->clock_source = smclk;   //Use SMCLK as clock source
   // i2c_struct->acknowledge = sw_ack_enable;    //Software acknowledgement enabled
    i2c_struct->bit_rate =8;*/

    i2c_init();


}

/*------------------------------------------------------------------------------------------------------------------------------------*/
/*
  @brief: Initialise I2c using the parameters set in the structure.


 @param: i2c_struct: Pointer to initialisation structure
 @param:None

 @return: None
 */
/*-----------------------------------------------------------------------------------------------------------------------------*/
void i2c_init(/*I2C_Init_Typedef * i2c_struct*/){

    EUSCI_B2->CTLW0 |=EUSCI_B_CTLW0_SWRST|EUSCI_B_CTLW0_MODE_3|EUSCI_B_CTLW0_MST|EUSCI_B_CTLW0_SYNC|EUSCI_B_CTLW0_SSEL__SMCLK;
    EUSCI_B2->BRW = 0x0008;


    /* EUSCI_B2->CTLW0 |= (i2c_struct->enable |  i2c_struct->mode| i2c_struct->master | i2c_struct->sync_mode | i2c_struct->clock_source  );
   // EUSCI_B2->CTLW1 |= (i2c_struct->acknowledge);
    EUSCI_B2->BRW = i2c_struct->bit_rate;*/
}

/*------------------------------------------------------------------------------------------------------------------------------------*/
/*
  @brief: Enable i2c communication.


 @param: None
 @param:None

 @return: None
 */
/*-----------------------------------------------------------------------------------------------------------------------------*/
void i2c_enable(){
    EUSCI_B2->CTLW0 &= ~(EUSCI_B_CTLW0_SWRST); //Enable i2c communication
}
/*------------------------------------------------------------------------------------------------------------------------------------*/
/*
  @brief: Write byte for I2C.


 @param: data_byte: Data that is to be written
 @param:None

 @return: None
 */
/*-----------------------------------------------------------------------------------------------------------------------------*/

void i2c_write_byte(uint8_t slave_addr,uint8_t reg_addr,uint8_t data_byte){
    while(EUSCI_B2->STATW & EUSCI_B_STATW_BBUSY);
    EUSCI_B2->I2CSA = (slave_addr << 1);    //Set slave address with write bit (LSB = 0)
    EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TR ; //Set as transmitter
    EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TXSTT ; // Send start condition
    while(!(EUSCI_B2->IFG & EUSCI_B_IFG_TXIFG0) ); //Wait until start condition is transmitted
    // EUSCI_B2->IFG &= ~(EUSCI_B_IFG_TXIFG0); //Clear the flag


     EUSCI_B2->TXBUF = reg_addr;    //Send the register address
     while(!(EUSCI_B2->IFG & EUSCI_B_IFG_TXIFG0) ); //Wait until the data in TXBUF(register address) is transmitted
   //  EUSCI_B2->IFG &= ~(EUSCI_B_IFG_TXIFG0); //Clear the flag

     EUSCI_B2->TXBUF = data_byte;    //Send the data byte
     while(!(EUSCI_B2->IFG & EUSCI_B_IFG_TXIFG0) ); //Wait until the data in TXBUF(register address) is transmitted
    // EUSCI_B2->IFG &= ~(EUSCI_B_IFG_TXIFG0); //Clear the flag

     EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TXSTP; // Generate a stop condition
     while(!(EUSCI_B2->IFG & EUSCI_B_IFG_TXIFG0) ); //Wait until the data in TXBUF(register address) is transmitted
     EUSCI_B2->IFG &= ~(EUSCI_B_IFG_TXIFG0); //Clear the flag

}


/*------------------------------------------------------------------------------------------------------------------------------------*/
/*
  @brief: Read byte for I2C.


 @param: None
 @param:None

 @return: data_byte:Data that is read
 */
/*-----------------------------------------------------------------------------------------------------------------------------*/
uint8_t i2c_read_byte(uint8_t slave_addr,uint8_t reg_addr){
    EUSCI_B2->I2CSA = (slave_addr << 1);    //Set slave address with write bit (LSB = 0)
    EUSCI_B2->CTLW0 &= ~(EUSCI_B_CTLW0_TR) ; //Set as Receiver
    EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TXSTT ; // Send start condition

    while(!(EUSCI_B2->IFG & EUSCI_B_IFG_TXIFG0) ); //Wait until start condition is transmitted
     EUSCI_B2->IFG &= ~(EUSCI_B_IFG_TXIFG0); //Clear the flag

     while((EUSCI_B2->CTLW0 & EUSCI_B_CTLW0_TXSTT) );   //Wait for complete slave address to get transmitted

     EUSCI_B2->TXBUF = reg_addr;    //Send the register address
     while(!(EUSCI_B2->IFG & EUSCI_B_IFG_TXIFG0) ); //Wait until the data in TXBUF(register address) is transmitted
     EUSCI_B2->IFG &= ~(EUSCI_B_IFG_TXIFG0); //Clear the flag

     EUSCI_B2->I2CSA = (slave_addr << 1) | (0x01);    //Set slave address with write bit (LSB = 0)
     EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TXSTT ; // Send start condition

     while(!(EUSCI_B2->IFG & EUSCI_B_IFG_TXIFG0) ); //Wait until start condition is transmitted
     EUSCI_B2->IFG &= ~(EUSCI_B_IFG_TXIFG0); //Clear the flag


     while((EUSCI_B2->CTLW0 & EUSCI_B_CTLW0_TXSTT) );   //Wait for complete slave address to get transmitted

     while(!(EUSCI_B2->IFG & EUSCI_B_IFG_RXIFG) ); //Wait until start condition is transmitted
     EUSCI_B2->IFG &= ~(EUSCI_B_IFG_RXIFG); //Clear the flag

     EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TXNACK; //Transmit a NACK


     EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TXSTP; // Generate a stop condition

     return EUSCI_B2->RXBUF;

}

Best Answer

EUSCI_B2->CTLW0 |=EUSCI_B_CTLW0_SWRST|EUSCI_B_CTLW0_MODE_3|EUSCI_B_CTLW0_MST|EUSCI_B_CTLW0_SYNC|EUSCI_B_CTLW0_SSEL__SMCLK;
                ^^

|= does not clear any bits. To modify all register fields, use =.

EUSCI_B2->BRW = 0x0008;

SMCLK / 8 is likely to be too fast.

while(EUSCI_B2->STATW & EUSCI_B_STATW_BBUSY);

Waiting for this bit is not really helpful. Wait for TXSTP to be clear.

EUSCI_B2->I2CSA = (slave_addr << 1);    //Set slave address with write bit (LSB = 0)

An I²C slave address has seven bits, so you must not shift anything. (The hardware automatically handles the R/W bit, based on the TR register bit.)

 EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TXSTP; // Generate a stop condition
 while(!(EUSCI_B2->IFG & EUSCI_B_IFG_TXIFG0) ); //Wait until the data in TXBUF(register address) is transmitted

There is no byte to be transmitted. Either wait for TXSTP to be cleared, or (if your code already does this wait at the beginning of every transaction) do nothing.

EUSCI_B2->CTLW0 &= ~(EUSCI_B_CTLW0_TR) ; //Set as Receiver
EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TXSTT ; // Send start condition

while(!(EUSCI_B2->IFG & EUSCI_B_IFG_TXIFG0) ); //Wait until start condition is transmitted
...

You cannot transmit when the TR bit is not set.

EUSCI_B2->CTLW0 |= EUSCI_B_CTLW0_TXNACK; //Transmit a NACK

TXNACK is used only in slave receiver mode. A master transmits a NACK by setting TXSTP while the last byte is being received, i.e., before the last RXIFG. (See figure 26-13 of the Reference Manual.)