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/MSP430FR2311: I2C setup code to read a differential pressure sensor

Part Number: MSP430FR2311

Tool/software: Code Composer Studio

Hi All,

I have a MSP430 micro controller on a launch pad board and I wish to read a differential pressure sensor via its I2C interface. It is a Sensirion SDP610.

I am using code composer 9 and, a lanch pad board.

I would like some simple code to get this up and running so far I have this setup code: This is sourced from : https://electronics.stackexchange.com/questions/67524/msp430-i%C2%B2c-single-write-read-example

void init_I2C(void) {
  _DINT();
  IE2 |= UCB0RXI             //Enable RX interrupt //UCRXIE0_1
  IE2 |= UCB0TXIE;                          // Enable TX interrupt //UCRXIE0_1
  while (UCB0CTL1 & UCTXSTP);               // Ensure stop condition got sent
  UCB0CTL1 |= UCSWRST;                      // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
  UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
  UCB0BR1 = 0;
  UCB0I2CSA = 0x40;                         // Slave Address is 040h
  UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
}

void Transmit(void){
    while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
    __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
}
void Receive(void){
   UCB0CTL1 &= ~UCTR ;                  // Clear UCTR
   while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
    UCB0CTL1 |= UCTXSTT;                    // I2C start condition
    while (UCB0CTL1 & UCTXSTT);             // Start condition sent?
    UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
    __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
}

However, the line of code of IE2 is unresolved.

I do have the SDP610 sensor working via a arduino and open source library so I know it works.

My hardware setup of the I2C line uses P1.2 as SDA and P1.3 as SCL.

Can someone help me set up the I2C communicate just so I can scan for a devices and print that information out to a terminal aka uart or just via the inbuilt debugger and stepping over.

Thanks

  • This was written for a G2553, so there are a few differences in the USCI. Example msp430fr231x_euscib0_i2c_10.c might be instructive:

    http://dev.ti.com/tirex/explore/node?node=ANl1oYi0.klyjvtEKGoMlA__IOGqZri__LATEST

    If you're using the Launchpad, don't forget to remove the jumpers on J7 and J8, which are also connected to P1.2/3.

  • If you follow Bruce's link to the examples, there is also a I2C_standard_master example which is probably your best starting place.  

    But, you would have to combine this with a UART example to accomplish what you are trying to do.  

    Thanks,

    JD

  • Thanks for your reply.

    I still have my issue with the I2C but do have a working UART to send data to a terminal.

    I am using the SDP610 differential pressure sensor which, I have working via an arduino library. I am therefore writing a request as it states in the datasheet for the sensor and then in my code trying to store the response and output it via uart. However, when I scope my I2C pins (SDA,SCL) I only see the request once and my statemachine does not run further. But this does imply my setup code is correct just my runtime code does not work correctly.

    Below is my code which gets stuck at the EVENT_I2CDONE_READ never being set.

    In my main code I have 2 handlers one for the sensor and one for the I2C.

    When it comes to asking for the data from the sensor by reading the device the i2cstate is not doe and, it is not in reading mode. I am not sure what is causing this issue.

    Please can you give me some suggestions for how to debug this thanks.

    void SDP610EventHandler(EVENT event, U32 eventArg)
    {
        U8 rxBuf[SDP610_MAXARGS];
        U8 bytesRead;
        U8 Pressure_data[2];//Variable for pressure data to be received
        U8 checksum;//Check sum variable
    
        switch (event) {
        case EVENT_INIT:
            SDP610State(SDP610STATE_INIT, SDP610DELAY_SETTLING);   // Settling time
            break;
        case EVENT_TICK:
            if (sdp610DelayMs) { if (sdp610DelayMs <= eventArg) sdp610DelayMs = 0; else sdp610DelayMs -= eventArg; }    // State timer
            if (!sdp610DelayMs) SDP610StateMachine();   // Run StateMachine while timer not running
            break;
        case EVENT_I2CDONE_READ:
            if (!eventArg) {   // I2C Error set the state
                switch (sdp610State) {
                case SDP610STATE_GETTINGPRESSURE:
                    SDP610State(SDP610STATE_REQPRESSURE, 0); // Restart pressure request
                    break;
                }
                break;
            }
            bytesRead = I2CGetData(rxBuf);//Read data
            switch (sdp610State) {  // No error if we get here, so get data
            case SDP610STATE_GETTINGPRESSURE://Process the data
                if (3 != bytesRead) break;//2 bytes for data 1 for checksum from datasheet
                SDP610State(SDP610STATE_CHECKINGDATA,0);//Move to the checking state
                break;
    
            case SDP610STATE_CHECKINGDATA://Perform the check if pass store the data
    
                Pressure_data[0] = rxBuf[0];//First 8 bits msb's
                Pressure_data[1] = rxBuf[1];//Last 8 bits  lsb's
                checksum         = rxBuf[2];//Check sum
    
                if(CheckCrc(Pressure_data, 2, checksum) == 0){//If it is 0 check sum passed else failed
                    //Store data
                    Pressure_result = Pressure_data[0] << 8 | Pressure_data[1];//Storing the pressure data
                }
                else
                {
                    Pressure_result = -10000;//Return stupid value as check sum failed
                }
                //Advertise the pressure result
                SDP610State(SDP610STATE_DONE, 0);   // All finished with SDP610 now
                break;
            }
            break;//End of sdp610 case statements
        case EVENT_I2CDONE_WRITE:
            switch (sdp610State) {
            case SDP610STATE_INIT: // Fall through...
                sdp610DelayMs = 0;
                break;
            case SDP610STATE_REQPRESSURE:
                break;
            }
            break;
        default: break;  // To avoid compiler warnings
        }
    }
    
    void SDP610StateMachine(void)
    {
        switch (sdp610State) {
        case SDP610STATE_INIT:
            SDP610State(SDP610STATE_REQPRESSURE, 0); // Straight on to get pressure after init finishes
            break;
        case SDP610STATE_REQPRESSURE:
            if (I2CWrite(SDP610Address, SDP610Read, 0x01)) { // Write Read_Pressure command into SDP register to get response
            //if (I2CWrite(SDP610Address, 0x00, SDP610Read)) { // Write Read_Pressure command into SDP address register to get response
                SDP610State(SDP610STATE_GETPRESSURE, SDP610DELAY_REQPRESSURE);   // Wait a while, then start polling for pressure ready
            }
            break;
        case SDP610STATE_GETPRESSURE:
            if (I2CRead(SDP610Address, 0x00, 3)) {
                SDP610State(SDP610STATE_GETTINGPRESSURE, 0); // Wait for EVENT_I2CDONE_READ
            }
            break;
    
        case SDP610STATE_DONE:
            break;
        default: break;
        }
    }

  • Is it possible to use the arduino wire library inside of the code composer ide? I need to emulate the following code:

    float SDP6xClass::GetPressureDiff(void)
    {
      int16_t res;
      if (readSensor(ePresHoldCmd, (uint16_t*)&res)) {
    	return ((float)(res)/SCALEFACTOR);
      } else {
    	  return -10000000;
      }
    }
    
    
    /******************************************************************************
     * Private Functions
     ******************************************************************************/
    
    bool SDP6xClass::readSensor(uint8_t command, uint16_t* res)
    {
        uint16_t result;
    	uint8_t data[2];
    	uint8_t checksum;
    	unsigned long startTime;
    	
        Wire.beginTransmission(eSDP6xAddress);  //begin
        Wire.write(command);          //send the pointer location
        delay(100);
        Wire.endTransmission();                 //end
    
        Wire.requestFrom(eSDP6xAddress, 3);
    	
    	  startTime = millis();
        while(Wire.available() < 3) {
    		//wait 500ms for results.
    		if (millis() - startTime > 500) {
    			Wire.endTransmission();
    			return false;
    		}
        }
    
    	//Store the result
    	data[0] = Wire.read();
    	data[1] = Wire.read();
    	checksum = Wire.read();
    	
    	if (CheckCrc(data, 2, checksum) == NO_ERROR) {
    		result = (data[0] << 8);
    		result += data[1];
    		*res = result; 
    		return true;
    	}
    	
    	return false;
    }
    
    

    Thanks

  • Your code posts (paste/attach?) don't seem to be working. I don't see any code after the original post.

  • I have re added the code in my previous post it was already in there but for some reason did not appear in the support reply message.

    The arduino scl and sda lines look like this

    But my code output looks like this (msp430)

    I know my code is detecting the i2c device as if i remove it the second pulse no longer exists or if I change the I2C address in the msp code from 40 to something else. But I can not see the data.

    Also the code I want to emulate is the arduino sdp610 code it is as follows:

    bool SDP6xClass::readSensor(uint8_t command, uint16_t* res)
    {
        uint16_t result;
    	uint8_t data[2];
    	uint8_t checksum;
    	unsigned long startTime;
    	
        Wire.beginTransmission(eSDP6xAddress);  //begin
        Wire.write(command);          //send the pointer location
        delay(100);
        Wire.endTransmission();                 //end
    
        Wire.requestFrom(eSDP6xAddress, 3);
    	
    	  startTime = millis();
        while(Wire.available() < 3) {
    		//wait 500ms for results.
    		if (millis() - startTime > 500) {
    			Wire.endTransmission();
    			return false;
    		}
        }
    
    	//Store the result
    	data[0] = Wire.read();
    	data[1] = Wire.read();
    	checksum = Wire.read();
    	
    	if (CheckCrc(data, 2, checksum) == NO_ERROR) {
    		result = (data[0] << 8);
    		result += data[1];
    		*res = result; 
    		return true;
    	}
    	
    	return false;
    }

    The result is res and this is basically the value I want to have in my msp430.

  • See my below reply. But

    I now can see data on the I2C data line and the clock running too. However, I am unable to see both bytes of data and the check sum value. Therefore could you please have a look at this code:

    This code is run in a loop and should get the data from the differential pressure sensor however, when I uncomment the reading of the second byte and or the check sum the code looks up and nothing is output and the sda and clock lines both lie flat.

    void Read_Diff_pressure(void)
    {
        int err = 0;//Used for error checking
        uint8_t rx_byte[2];
        uint16_t result;
        uint8_t checksum  = 0;
        while (UCB0CTL1 & UCTXSTP);// Ensure stop condition got sent
        UCB0CTL1 |= UCTXSTT+ UCTR; // Generating START + I2C transmit (write)
        UCB0I2CSA = SDP610Address; // SDP610 7 bit address 0x40
        while(!(UCB0IFG & UCTXIFG)); //wait until reg address got sent
        while (UCB0CTL1 & UCTXSTP);// Ensure stop condition got sent
    
        UCB0TXBUF = SDP610Read; // sending the read command 0x78
        while(!(UCB0IFG & UCTXIFG)); //wait until reg address got sent
        while (UCB0CTL1 & UCTXSTP);// Ensure stop condition got sent
    
        UCB0CTL1 |= UCTXSTT; //generate RE-START
        UCB0I2CSA = SDP610Address; // SDP610 7 bit address 0x40
        UCB0CTL1 &=~ UCTR; //receive mode
    
        while(UCB0CTL1 & UCTXSTT); //wait till START condition is cleared
        rx_byte[0] = UCB0RXBUF; //read byte
        while(!(UCB0IFG & UCRXIFG)); //wait while the Byte is being read
        UCB0CTL1 |= UCTXNACK; //generate a NACK
        UCB0CTL1 |= UCTXSTP; //generate stop condition
        while(UCB0CTL1 & UCTXSTP); //wait till stop condition got sent
    
        /*
        while(UCB0CTL1 & UCTXSTT); //wait till START condition is cleared
        rx_byte[1] = UCB0RXBUF; //read byte
        while(!(UCB0IFG & UCRXIFG)); //wait while the Byte is being read
        UCB0CTL1 |= UCTXNACK; //generate a NACK
        UCB0CTL1 |= UCTXSTP; //generate stop condition
        while(UCB0CTL1 & UCTXSTP); //wait till stop condition got sent
        
        while(UCB0CTL1 & UCTXSTT); //wait till START condition is cleared
        checksum = UCB0RXBUF; //check sum byte
        while(!(UCB0IFG & UCRXIFG)); //wait while the Byte is being read
        UCB0CTL1 |= UCTXNACK; //generate a NACK
        UCB0CTL1 |= UCTXSTP; //generate stop condition
        while(UCB0CTL1 & UCTXSTP); //wait till stop condition got sent
        */
        /*
        if (CheckCrc(rx_byte, 2, checksum) == 0) {
            result = (rx_byte[0] << 8);
            result += rx_byte[1];
            Pressure_result = (float)(result/SCALEFACTOR);
        }
         */
    }

    With the parts of the code uncommitted as such my data and clock lines look as follows:

  • When you request a Start (UCTXSTT) the transaction will start immediately, so you need to make sure everything is in place first. Similarly, you shouldn't read RXBUF until RXIFG is set.

    I recommend  User Guide (SLAU445I) Figures 24-12 and 24-13. There's quite a lot of information in them.

    Specifically:

    >    UCB0CTL1 |= UCTXSTT+ UCTR; // Generating START + I2C transmit (write)
    >    UCB0I2CSA = SDP610Address; // SDP610 7 bit address 0x40
    You should reverse the order of these statements.
    >    UCB0CTL1 |= UCTXSTT; //generate RE-START
    >    UCB0I2CSA = SDP610Address; // SDP610 7 bit address 0x40
    >    UCB0CTL1 &=~ UCTR; //receive mode
    You should set UCTXSTT last in this sequence.
    >    rx_byte[0] = UCB0RXBUF; //read byte
    >    while(!(UCB0IFG & UCRXIFG)); //wait while the Byte is being read
    You should reverse the order of these statements.
    [Edit: Attempts to fix the formatting -- mostly unsuccessful.]

**Attention** This is a public forum