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/MSP432P401R: BMI160 I2C read/write functions

Part Number: MSP432P401R

Tool/software: Code Composer Studio

Hello TI community

I plan to use BMI160 IMU as motion sensor in my applcation. I have written the i2c write/read functions as follows (the MCU is MSP432P401R):

/************BMI160 I2C*********/
UCB1CTLW0 |= UCSWRST; // **Initialize USCI state machine**
P6SEL0 |= BIT4 + BIT5;
P6SEL1 &= ~(BIT4 + BIT5); // P6.4:SDA-P6.5:SCL
UCB1CTLW0 |=  UCMST + UCMSB + UCSYNC + UCSSEL_2 + UCMODE_3; // I2C
UCB1BR0 = 12; // fSCL = SMCLK/12 = ~250kHz
UCB1BR1 = 0;
UCB1I2CSA = BMI160_I2C_ADDR; // Set slave address
UCB1CTLW0 &= ~UCSWRST; // **Initialize USCI state machine**

/*********************************************************************************/

int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
{
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */

/*
* The parameter dev_id can be used as a variable to store the I2C address of the device
*/
UCB1CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition
UCB1TXBUF = reg_addr; // Write reg_addr byte
UCB1CTLW0 |= UCTXSTP; // I2C stop condition after 1st TX

UCB1I2CSA |= BMI160_I2C_ADDR; // Set slave address
UCB1CTLW0 &=~UCA10; //10BIT ADDRESS
UCB1CTLW0 &=~UCTR;//CLEAR TRANSMIT MODE
UCB1CTLW0 |= UCTXSTT; // I2C RX, start condition
int i=0;
for (i=0;i<len;i++)
{
reg_data[i]=UCB1RXBUF;
}
UCB1CTLW0 |= UCTXSTP; // I2C stop condition after 1st TX

return rslt;
}

int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
{
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
UCB1CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition
UCB1TXBUF = reg_addr; // Write reg_addr byte
int i=0;
for (i=0;i<len;i++)
{
UCB1TXBUF=reg_data[i];
}
UCB1CTLW0 |= UCTXSTP; // I2C stop condition after 1st TX

return rslt;
}

is it the correct form read/write functions for interfacing with bmi160?

Thanks

Saber

  • Hi Saber,

    Refer to this example: dev.ti.com/.../node

    Regards,
    Fredrik

  • Thanks for your reply Fredrick!

    I think one thing is missing in my code: the acknowledgment bit. How can I check the this bit in my code after I sent a byte to the slave?

    Thanks

    Saber  

  • For receiving and sending data with I2C protocol, I have defined two functions for I2C write and read. The chip I am working it, BMI160, accepts data on I2C bus like what is defined in below:

    For I2C read access:

    I have configured the read/write functions like below:

    1- The I2C configuration:

    /* Select Port 1 for I2C - Set Pin 6, 7 to input Primary Module Function,
    	     *   (UCB0SIMO/UCB0SDA, UCB0SOMI/UCB0SCL).
    	     */
    	    P1->SEL0 |= BIT6+BIT7;
    	    //MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
    	    //        GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
    
    	    stopSent = false;
    
    	    /* Initializing I2C Master to SMCLK at 100khz with no autostop */
    	    MAP_I2C_initMaster(EUSCI_B0_BASE, &i2cConfig);
    
    	    /* Specify slave address */
    	    MAP_I2C_setSlaveAddress(EUSCI_B0_BASE, BMI160_I2C_ADDR);
    
    	    /* Set Master in transmit mode */
    	     MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
    
    	     /* Enable I2C Module to start operations */
    	     MAP_I2C_enableModule(EUSCI_B0_BASE);
    
    	     /* Enable and clear the interrupt flag */
    	     MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE,
    	             EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    
    	     //Enable master Receive interrupt
    	     MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
    
    	 //    MAP_Interrupt_enableSleepOnIsrExit();
    
    	     /* Enable master transmit interrupt */
    	     MAP_I2C_enableInterrupt(EUSCI_B0_BASE,
    	             EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_NAK_INTERRUPT);
    	     MAP_Interrupt_enableInterrupt(INT_EUSCIB0); /* EUSCIB0 IRQ */

    2- I2C write function:

    int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
    {
        int8_t rslt = BMI160_OK; /* Return 0 for Success, non-zero for failure */
    
        /* Transmit interrupt comes from i2c write function*/
        readModule = 0;
    
        /* Load Byte Counter */
        TXByteCtr = len;
    
        /* Making sure the last transaction has been completely sent out */
        while (MAP_I2C_masterIsStopSent(EUSCI_B0_BASE) == EUSCI_B_I2C_SENDING_STOP);
    
        /* Set Master in transmit mode */
         MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
    
        /* Sending the initial start condition *///And register address.
        MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, reg_addr);
    
        while(TRANSMITFLAG);
    
        TRANSMITFLAG=1;
    
       // MAP_Interrupt_enableSleepOnIsrExit();
       // MAP_PCM_gotoLPM0InterruptSafe();
        return rslt;
    }

    3- I2C read function:

    int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
        {
        int8_t rslt = BMI160_OK; /* Return 0 for Success, non-zero for failure */
    
        /* Transmit interrupt comes from i2c read function*/
        readModule = 1;
    
       /*Number of bytes to be received*/
        NUM_OF_REC_BYTES = len;
        MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
    
       /* Making sure the last transaction has been completely sent out */
       while (MAP_I2C_masterIsStopSent(EUSCI_B0_BASE) == EUSCI_B_I2C_SENDING_STOP);
    
         /* Send start and the first byte of the transmit buffer. We have to send
          * two bytes to clean out whatever is in the buffer from a previous
          * send  */
         //MAP_I2C_masterSendMultiByteStart(EUSCI_B0_BASE,reg_addr);
         MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, reg_addr);
    
    
         /* Enabling transfer interrupt after stop has been sent */
         MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
         /* While the stop condition hasn't been sent out... */
         while(!stopSent)
         {
         //    MAP_PCM_gotoLPM0InterruptSafe();
         }
    
         stopSent = false;
         return rslt;
        }

    4- And finally, the I2C interrupt handler is like:

    void EUSCIB0_IRQHandler(void)
    {
        uint_fast16_t status;
    
           status = MAP_I2C_getEnabledInterruptStatus(EUSCI_B0_BASE);
           MAP_I2C_clearInterruptFlag(EUSCI_B0_BASE, status);
    
           if (status & EUSCI_B_I2C_NAK_INTERRUPT)
              {
                  MAP_I2C_masterSendStart(EUSCI_B0_BASE);
              }
           /* If we reached the transmit interrupt, it means we are at index 1 of
               * the transmit buffer. When doing a repeated start, before we reach the
               * last byte we will need to change the mode to receive mode, set the start
               * condition send bit, and then load the final byte into the TXBUF.
               */
              if (status & EUSCI_B_I2C_TRANSMIT_INTERRUPT0)
              {c1++;
                  if(readModule)
                  {
               //   MAP_I2C_masterSendMultiByteNext(EUSCI_B1_BASE, TXData[1]);/////?????
                  MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0);
    
                  MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_MODE);
                  xferIndex = 0;
                  MAP_I2C_masterReceiveStart(EUSCI_B0_BASE);
                  MAP_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
                  }
                  else
                  {
                   /* Check the byte counter */
                          if (TXByteCtr)
                          {
                              /* Send the next data and decrement the byte counter */
                              MAP_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, *reg_data);
                              TXByteCtr--;
                              reg_data++;
                          }
                          else
                          {
                              MAP_I2C_masterSendMultiByteStop(EUSCI_B0_BASE);
                            //  MAP_Interrupt_disableSleepOnIsrExit();
                              TRANSMITFLAG=0;
                          }
                  }
              }
    
              /* Receives bytes into the receive buffer. If we have received all bytes,
               * send a STOP condition */
              if (status & EUSCI_B_I2C_RECEIVE_INTERRUPT0)
              {c2++;
    
                  if(xferIndex == NUM_OF_REC_BYTES - 2)
                  {
                      MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE);
                      *reg_data = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
                      reg_data++;
                      xferIndex++;
                  }
                  else if(xferIndex == NUM_OF_REC_BYTES - 1)
                  {
                      *reg_data = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
                      xferIndex++;
                      reg_data++;
                      MAP_I2C_masterReceiveMultiByteStop(EUSCI_B0_BASE);
                      MAP_I2C_disableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0);
                      MAP_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE);
                      xferIndex = 0;
                      stopSent = true;
                 //     MAP_Interrupt_disableSleepOnIsrExit();
                  }
                  else
                  {
                      *reg_data = MAP_I2C_masterReceiveMultiByteNext(EUSCI_B0_BASE);
                      xferIndex++;
                      reg_data++;
                  }
    
              }
    }

    The code get stuck in 

     while(!stopSent)
         {
         //    MAP_PCM_gotoLPM0InterruptSafe();
         }
    
         stopSent = false;

    It seems the module never go to the interrupt vector.

    Do you have any idea where the problem is?

    Thanks

    Saber

**Attention** This is a public forum