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.

MSP430F5438A: I2C Code

Part Number: MSP430F5438A
Other Parts Discussed in Thread: MSP430FR2311, HDC1080

Hello,

I am trying to find an I2C example code from where I can understand how to customize it for my purpose. Trying to communicate with a sensor having I2C protocol. I'm using MSP430F5438A Exp board and IDE Code Composer studio. Following are the tasks have to do to communicate the sensor:

1. Need to configure the sensor (In several addresses of the sensor I have to write different values suppose in 0x0E register I write 0x08, in 0x0D I like to write 0x01 and so on)

2. Read raw data from the sensor (Sending the address from where I like to read multiple bytes).

I was trying to understand register level I2C codes from MSP430 ware. I was wondering does any of it doing something similar? 

I appreciate any suggestion. Also if none of the register level code doesn't serve the purpose, please help me find similar sort of example code. 

Thanks.

Rana 

  • Hi Rana

    We have series code examples about I2C that can guide you have to use configure MSP430's I2C module. You can get it at resource explorer or TI.COM.

    For how to read or write the sensor register you should to see the protocol of the I2C in the sensor's datasheet.

    Best regards

    Gary

  • Hello Gao,

    Thanks for your response. I already mentioned I went through the register level codes. Also, I read the datasheet. The sources you refer is too broad. Can you please refer specific example which I can follow for the purpose? 

    Thanks,

    Rana.

  • Hi Rana

    What's the sensor do you use? I will try to find some similar code for you.

    Best regards
    Gary
  • Hello Gao,
    I am implementing BNO055.

    I appreciate your time.

    Thanks,
    Rana
  • Hi

    You can refer to this example using MSP430FR2311 as master to read the temperature and humidity sensor HDC1080. The demo code provides how to read a register’s value, how to write values to register and the sensing data. I have attached the capture of the SCL and SDA of this demo using the Saleae.

    //
    //                                /|\  /|\
    //               MSP430FR2311      10k  10k
    //                   Master         |    |   Slave
    //             -----------------   |    |   --------
    //            |     P1.2/UCB0SDA|<-|----|->|        |
    //            |                 |  |       |        |
    //            |                 |  |       |HDC1080 |
    //            |     P1.3/UCB0SCL|<-|------>|        |
    //            |                 |           --------
    //
    
    
    #include <msp430.h>
    #include <stdint.h>
    #include <stdbool.h>
    
    unsigned char TXData[3],Read_data;
    unsigned char RXSData[5];
    
    unsigned char TXByteCtr,RXByteCtr;
    unsigned short value,value1;
    unsigned char *pRXData = 0x0;                       // Pointer to RX data
    
    uint16_t u16TxCount = 0;
    uint16_t u16RxCount =0;
    
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;                         // Stop watchdog timer
    
        // Configure Pins for I2C
        P1SEL0 |= BIT2 | BIT3;                            // I2C pins
    
        // Disable the GPIO power-on default high-impedance mode
        // to activate previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
    
        pRXData = (unsigned char *) RXSData;
        // Configure USCI_B0 for I2C mode
        UCB0CTLW0 |= UCSWRST;                             // put eUSCI_B in reset state
        UCB0CTLW0 |= UCMODE_3 | UCMST|UCSYNC;             // I2C master mode, SMCLK
    //   UCB0CTLW1 |= UCCLTO_1;                           // time_out 28ms(You can enable the timeout if you needed)
        UCB0BRW = 0x28;                                    // baudrate = SMCLK / 0x28
      //  UCB0TBCNT = 0x0002;                     // number of bytes to be received
        UCB0I2CSA =0x40;              // configure slave address
        UCB0CTLW0 &=~ UCSWRST;                            // clear reset register
        UCB0IE |= UCTXIE0 | UCRXIE;
        __bis_SR_register(GIE);
    
    
        //read the device ID
        TXByteCtr = 1;                                    // Transmitter bytes
        RXByteCtr=2-1;                                    // Receive bytes
        u16TxCount = 0;
        u16RxCount=0;
        TXData[0]=0xFF;                                   //Register address to be read
        while (UCB0CTLW0 & UCTXSTP);                      // Ensure stop condition got sent
        UCB0CTLW0 |= UCTR | UCTXSTT;                      // I2C TX, start condition
        __delay_cycles(2000);
    
       //write two bytes to a register 0x02
        TXByteCtr = 3;                                    // Transmitter bytes
        u16TxCount = 0;
        TXData[0]=0x02;                                   //Register address need to be configured
        TXData[1]=0x10;
        TXData[2]=0x00;
        Read_data=0;
        UCB0TBCNT =3;                     // number of bytes to be received
        UCB0CTLW1 |= UCASTP_2;  // Automatic stop generated after UCB0TBCNT is reached
        while (UCB0CTLW0 & UCTXSTP);                      // Ensure stop condition got sent
        UCB0CTLW0 |= UCTR | UCTXSTT;                      // I2C TX, start condition
        __delay_cycles(4000);
        //read the Temperature and Humidity
        TXByteCtr = 1;                                    // Transmitter bytes
        RXByteCtr=4-1;                                    // Receive bytes
        u16TxCount = 0;
        u16RxCount=0;
        TXData[0]=0x00;                                   //Trigger the conversion
        Read_data=1;
        UCB0CTLW1 &= ~UCASTP_3;
        while (UCB0CTLW0 & UCTXSTP);                      // Ensure stop condition got sent
        UCB0CTLW0 |= UCTR | UCTXSTT;                      // I2C TX, start condition
        __delay_cycles(40000);
    
    
        while(1)                                               // Remain in LPM0 until all data
        {
            __delay_cycles(10);  // Put a break point here
        }
    
    }
    
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCIB0_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      switch(__even_in_range(UCB0IV,USCI_I2C_UCBIT9IFG))
      {
            case USCI_NONE: break;                        // Vector 0: No interrupts break;
            case USCI_I2C_UCALIFG: break;
            case USCI_I2C_UCNACKIFG:
                UCB0CTL1 |= UCTXSTT;                      //resend start if NACK
              break;                                      // Vector 4: NACKIFG break;
            case USCI_I2C_UCSTTIFG: break;                // Vector 6: STTIFG break;
            case USCI_I2C_UCSTPIFG: break;                // Vector 8: STPIFG break;
            case USCI_I2C_UCRXIFG3: break;                // Vector 10: RXIFG3 break;
            case USCI_I2C_UCTXIFG3: break;                // Vector 14: TXIFG3 break;
            case USCI_I2C_UCRXIFG2: break;                // Vector 16: RXIFG2 break;
            case USCI_I2C_UCTXIFG2: break;                // Vector 18: TXIFG2 break;
            case USCI_I2C_UCRXIFG1: break;                // Vector 20: RXIFG1 break;
            case USCI_I2C_UCTXIFG1: break;                // Vector 22: TXIFG1 break;
            case USCI_I2C_UCRXIFG0:
    
                u16RxCount++;                      // Decrement RX byte counter
                *pRXData++= UCB0RXBUF;              // Multiple bytes left to receive
                if(u16RxCount==RXByteCtr)
                {
                    UCB0CTLW0|=UCTXSTP;
                }
                break;                // Vector 24: RXIFG0 break;
            case USCI_I2C_UCTXIFG0:
                 if (u16TxCount < TXByteCtr)
                    {
                     UCB0TXBUF=TXData[u16TxCount];
                    }
                    else
                    {
                     UCB0CTLW0 &= ~UCTR;
                     UCB0CTLW0 |= UCTXSTT;                      // I2C TX, start condition
                     if(Read_data)
                     {
                       __delay_cycles(20000);    // Wait for conversion >15ms
                       UCB0CTLW0 |= UCTXSTT;                      // I2C TX, start condition
                     }
                    }
                 u16TxCount++;
              break;                                      // Vector 26: TXIFG0 break;
            case USCI_I2C_UCBCNTIFG: break;               // Vector 28: BCNTIFG
            case USCI_I2C_UCCLTOIFG: break;               // Vector 30: clock low timeout
            case USCI_I2C_UCBIT9IFG: break;               // Vector 32: 9th bit
    
            default: break;
      }
    }
    
    
    
    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/166/HDC1080_5F00_write_5F00_read.logicdata

    Useful links  

    HDC1080 DATASHEET

    Saleae GUI

  • BNO055_1.zipHello Gao,

    Thanks for sharing the example code. I got some hints from your code. But I found the configuration different. But anyway I tried to write it for my own in MSP430F5438A. I can write values to different registers. Also, I can read a single byte with my code, for example, I got proper value while reading device ID. Now the problem is with burst read. I like to read 6 bytes starting from address 0x08. According to datasheet, (BNO055)the register address will increase automatically. I like to get data continuously from the addresses and that's why put it in a while loop. But it's not returning the data properly (Getting zero always). I'm attaching my code and the Saleae files(BNO055_1 is reading 6 bytes, and BNO055_2 is reading 6 bytes continuously). Can you please tell me what's wrong with the burst read?

    #include <msp430.h>
    
    #include <stdint.h>
    
    
    void Clock_setup();   // using default SMCLK ~1MHz for now
    void I2C_setup_s1();  // I2C setup for sensor 1
    void BNO055_setup_s1(void);  // Sensor 1 configuration setup
    char I2C_receive_s1(char reg_add);  // receive 1 bytes from sensor
    void I2C_receive_s6(char start_add, char *buffer, unsigned int no_ofbyte);   //receive 6 bytes from sensor
    void I2C_transmit_s1(char reg_add, char data);  // transmit data to sensor
    
    char accbuffer[6];
    int x_s1; // x value from sensor 1
    int y_s1; // y value from sensor 1
    int z_s1; // z value from sensor 1
    volatile unsigned char volt [5];
    
    void init_serial (void);
    void init_serial (void)
    {
         P5SEL |= 0xC0;              // 5.6 and 5.7 for TX/RX- UCA1
         UCA1CTL1 |= UCSWRST;
         UCA1CTL1 |= UCSSEL_1;       //32768 Hz
         UCA1BR0 = 03;               // Baudrate 9600
         UCA1BR1 = 0x00;
         UCA1MCTL = 0x06;            // Modulation  Sx=3, Fx= 0
         UCA1CTL0 = 0x00;
         UCA1CTL1 &= ~UCSWRST;        // In operation mode
    
        }
    
    void ADC_value (int);
    void ADC_value (int ADC_Data)
    {
        volatile char x=3;
        volt [3] = volt [2] = volt [1] = volt [0] = 0x30;
        while (ADC_Data > 0)
        {
            volt [x] = (ADC_Data%10)| 0x30;  // Separating unit digit
            ADC_Data = ADC_Data/10;          // rest of the digit than last digit
            x--;
        }
        volt [4] = '\0';
        }
    
    void Send_Serial (void);
    void Send_Serial (void)
    {
        volatile char i=0;
        while (volt[i] != '\0')
        {
            UCA1TXBUF = volt[i];
    
            while (UCA1STAT & UCBUSY);
            i++;
        }
        UCA1TXBUF = 0x20;            // Space
        while (UCA1STAT & UCBUSY);
    
        }
    
    void Send_Serial_1 (void);
    void Send_Serial_1 (void)
    {
        volatile char i=0;
        while (volt[i] != '\0')
        {
            UCA1TXBUF = volt[i];
    
            while (UCA1STAT & UCBUSY);
            i++;
        }
        UCA1TXBUF = 0x0a;            //NL
        while (UCA1STAT & UCBUSY);
        UCA1TXBUF = 0x0d;            //Enter
        while (UCA1STAT & UCBUSY);
    
        }
    
    void main(){
        WDTCTL = WDTPW + WDTHOLD;
        Clock_setup();
        I2C_setup_s1();
        BNO055_setup_s1();
        //char add = I2C_receive_s1(0x03);
    
        while(1){
        I2C_receive_s6(0x08, accbuffer, 6); // Read 6 bytes of data from accelerometer
    
              x_s1 = (accbuffer[1] << 8) | accbuffer[0];
              ADC_value (x_s1);
              Send_Serial ();
              y_s1 = (accbuffer[3] << 8) | accbuffer[2];
              ADC_value (y_s1);
              Send_Serial ();
              z_s1 = (accbuffer[5] << 8) | accbuffer[4];
              ADC_value (z_s1);
              Send_Serial_1 ();
        }
        return 0;
    }
    
    void Clock_setup(){
        P11DIR |= BIT0;    // check ACLK, 32768 Hz default
        P11SEL |= BIT0;    // check ACLK, 32768 Hz default
        P11DIR |= BIT1;    // check MCLK, 1.045 MHz default
        P11SEL |= BIT1;    // check MCLK, 1.045 MHz default
        P11DIR |= BIT2;    // check SMCLK, 1.045 MHz default
        P11SEL |= BIT2;    // check SMCLK, 1.045 MHz default
    }
    
    void I2C_setup_s1() {
      P3SEL |= BIT7;                            //  P5.4(UCB1_SCL), P3.7(UCB1_SDA)
      P5SEL |= BIT4;
      UCB1CTL1 |= UCSWRST;                      // reset enable
      UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC;     // master + I2C mode + Sync
      UCB1CTL1 = UCSSEL_2 + UCSWRST;            //use SMCLK + still reset
      UCB1BR0 = 4;                              // default SMCLK 1M/4 = 250KHz
      UCB1BR1 = 0;                              //
      UCB1I2CSA = 0x28;                         // BNO055 address 0x28
      UCB1CTL1 &= ~UCSWRST;                     // reset clear
      //UCB1IE |= UCTXIE + UCRXIE;             //TX and RX interrupt enabled
    }
    
    void BNO055_setup_s1(void){
        I2C_transmit_s1(0x07, 0x00);   //page id
        I2C_transmit_s1(0x3E, 0x00);   //power mode
        I2C_transmit_s1(0x3B, 0x00);   //unit select m/s2
        I2C_transmit_s1(0x41, 0x24);   //axis remap default
        I2C_transmit_s1(0x42, 0x00);   //axis map sign
        I2C_transmit_s1(0x3D, 0x01);   //operation mode= acclr only
    
    }
    
    
    char I2C_receive_s1(char reg_add){
    char rx_byte;
        UCB1CTL1 |= UCTR + UCTXSTT;
        UCB1TXBUF = reg_add;
        while(!(UCB1IFG & UCTXIFG));                          //wait until reg address got sent
        while( UCB1CTL1 & UCTXSTT);                         //wait till START condition is cleared
        UCB1CTL1    |=  UCTXSTT;                          //generate RE-START
        //UCB1I2CSA   =   slave_add;                        //slave address
        UCB1CTL1    &=~     UCTR;                             //receive mode
        while( UCB1CTL1 & UCTXSTT);                         //wait till START condition is cleared
        rx_byte     =   UCB1RXBUF;                      //read byte
        UCB1CTL1    |=   UCTXSTP;                         //generate stop condition
        while(UCB1CTL1 & UCTXSTP);                            //wait till stop condition got sent
    
    return rx_byte;
    }
    
    void I2C_receive_s6(char start_add, char *buffer, unsigned int no_ofbyte){
        unsigned int i;
            //UCB1I2CSA   =   slave_add;                        //slave address
            while(!(UCB1IFG & UCTXIFG));                          //wait until slave address got sent
            UCB1CTL1    |=  UCTXSTT + UCTR;                   // Generating START condition + I2C transmit (write)
            UCB1TXBUF   =   start_add;                     //write register address
            while(!(UCB1IFG & UCTXIFG));                          //wait until reg address got sent
            while( UCB1CTL1 & UCTXSTT);                         //wait till START condition is cleared
            UCB1CTL1    |=  UCTXSTT;                          //generate RE-START condition
            //UCB1I2CSA   =   slave_add;                        //slave address
            UCB1CTL1    &=~ UCTR;                                 //receive mode
            while( UCB1CTL1 & UCTXSTT);                         //wait till START condition is cleared
            //buffer[0] = UCB1RXBUF;                              //dummy read
            //while(!(UCB1IFG & UCRXIFG));                        //wait till byte is completely read
            for(i=0;i<no_ofbyte-1;++i){
            buffer[i] = UCB1RXBUF;                              //burst read
            while(!(UCB1IFG & UCRXIFG));                        //wait while the Byte has being read
            }
            buffer[no_ofbyte-1] = UCB1RXBUF;                   //last Byte read
            while(!(UCB1IFG & UCRXIFG));                        //wait
            UCB1CTL1    |=   UCTXSTP;                         //generate stop condition
            while(UCB1CTL1 & UCTXSTP);                            //wait till stop condition got sent
    
    }
    
    void I2C_transmit_s1(char reg_add, char data){
        //UCB1I2CSA       =  slave_add;                  //slave address for transmit mode
        UCB1CTL1        |= UCTR + UCTXSTT;             // I2C transmit (write) mode + generating START condition
        UCB1TXBUF       =    reg_add;               //register address to measure temperature/pressure
        while(!(UCB1IFG & UCTXIFG));                          //wait until reg address got sent
        while(UCB1CTL1 & UCTXSTT);                    //wait till START condition is cleared
        UCB1TXBUF       =         data;                       //send data to register
        while(!(UCB1IFG & UCTXIFG));                          //wait until data got sent
        UCB1CTL1        |=    UCTXSTP;                    //generate a STOP condition
        while(UCB1CTL1 & UCTXSTP);                            //wait until stop condition got sent
    }
    

     

  • A couple of things jump out:

    > x_s1 = (accbuffer[1] << 8) | accbuffer[0];
    Since accbuffer is "char", this will lose the high order byte (=0) of x_s1. Try:
    > x_s1 = ((unsigned)accbuffer[1] << 8) | (unsigned)accbuffer[0];

    > for(i=0;i<no_ofbyte-1;++i){
    > buffer[i] = UCB1RXBUF; //burst read
    > while(!(UCB1IFG & UCRXIFG)); //wait while the Byte has being read
    > }
    The first time through this fetches the Rx byte before it's ready. This is the kind of thing that can sometimes work "by accident", but you shouldn't rely on this. Try reversing the while() and the assignment.
  • Hello McKenney,

    Thank you for your suggestion. So, modifies the code as you said. Now getting 4 bytes and after that NAK. What do think about the possible issue? Attachment is the output of SCL and SDA-

  • Based on the log at the lower right, you're receiving 5 bytes before the NACK. That suggests you're issuing the Stop prematurely.

    What does the code in I2C_receive_s6 look like now?
  • Hi,

    So the current code for the function is below:

    void I2C_receive_s6(char start_add, char *buffer, unsigned int no_ofbyte){
        unsigned int i;
                //UCB1I2CSA   =   slave_add;                        //slave address
                while(!(UCB1IFG & UCTXIFG));                          //wait until slave address got sent
                UCB1CTL1    |=  UCTXSTT + UCTR;                   // Generating START condition + I2C transmit (write)
                UCB1TXBUF   =   start_add;                     //write register address
                while(!(UCB1IFG & UCTXIFG));                          //wait until reg address got sent
                while( UCB1CTL1 & UCTXSTT);                         //wait till START condition is cleared
                UCB1CTL1    |=  UCTXSTT;                          //generate RE-START condition
                //UCB1I2CSA   =   slave_add;                        //slave address
                UCB1CTL1    &=~ UCTR;                                 //receive mode
                while( UCB1CTL1 & UCTXSTT);                         //wait till START condition is cleared
                //buffer[0] = UCB1RXBUF;                              //dummy read
                //while(!(UCB1IFG & UCRXIFG));                        //wait till byte is completely read
                for(i=0;i<no_ofbyte-1;++i){
                while(!(UCB1IFG & UCRXIFG));                        //wait while the Byte has being read
                buffer[i] = UCB1RXBUF;                              //burst read
                //while(!(UCB1IFG & UCRXIFG));                        //wait while the Byte has being read
                }
                while(!(UCB1IFG & UCRXIFG));                        //wait while the Byte has being read
                buffer[no_ofbyte-1] = UCB1RXBUF;                   //last Byte read
                //while(!(UCB1IFG & UCRXIFG));                        //wait
                UCB1CTL1    |=   UCTXSTP;                         //generate stop condition
                while(UCB1CTL1 & UCTXSTP);                            //wait till stop condition got sent
    }

    Now at this point, it looks like I am getting values. I'm attaching the logic analyzer file here 123.zip. After a couple of bytes of zeroes, it started returning values. But I can't see anything in the teraterm when trying to send the values to PC.  If you see my previous code, in main(), I was trying to send the data to PC like below:

              x_s1 = (((unsigned char)accbuffer[1] << 8) | (unsigned char)accbuffer[0]);
              ADC_value (x_s1);
              Send_Serial ();
              y_s1 = (((unsigned char)accbuffer[3] << 8) | (unsigned char)accbuffer[2]);
              ADC_value (y_s1);
              Send_Serial ();
              z_s1 = (((unsigned char)accbuffer[5] << 8) | (unsigned char)accbuffer[4]);
              ADC_value (z_s1);
              Send_Serial_1 ();

      Something wrong in conversion? 

  • I don't know why you're only getting 5 bytes. I also don't have your equipment. I do see some "unusual" things in your code, though I can't tie them to your symptom:
    1) You should set UCTR appropriately before setting STT
    2) You should send the Stop while the last Rx byte is arriving (right after you exit the for() loop).
    The I2C unit has some arcane properties, and these things may work some of the time. This is the big value in the Example programs.
    ----------------------------------
    If you're seeing nothing at all over the serial link, you should check your connections. I'm supposing that you got your MCTL values from the book. You may want to try sending a fixed string ("BNO0055 Test" or some such) out at startup, just to isolate the symptom.
    ----------------------------------
    > x_s1 = (((unsigned char)accbuffer[1] << 8) | (unsigned char)accbuffer[0]);
    This has the same flaw as before. Try:
    > x_s1 = ((unsigned)accbuffer[1] << 8) | (unsigned)accbuffer[0];
  • Hi

    Thanks for Bruce to give your valuable advise.
    Here is some my advises
    Have you notice that the BNO055 need 400 ms to start up(in the datasheet page 13)and have the switch time limit(page 21) and you should keep in mind the output data rate(page 31). That maybe why you read the 0 at first time.
    For second problem you suggest you test the UART independently, you just sent one byte to your PC first to see if it can works.

    Best regards
    Gary

**Attention** This is a public forum