EmbeddedRelated.com
Forums

External Sensor MCP9808 interfacing with MSP430FR4133

Started by shetty 6 years ago2 replieslatest reply 6 years ago279 views

Microcontroller: MSP430FR4133

Tool/software: IAR Embedded

 Hello,

 I'm a beginner and need some help with a project of mine.

Project- To interface an external temperature sensor MCP9808 through I2C communication with MSP430FR4133 to get temperature value.

Connections

SDA- pin 5.2, SCL- pin 5.3, GND-GND, VDD- 3.3V

I have interfaced a temperature sensor  MCP9808 with MSP430FR4133 through i2c communication. I am using the following code to read the temperature value from the sensor.

I am facing problem to get the desired results.

In MCP9808 data sheet in CONFIG Register part where I have to write

Addressbyte(0x30),Configuration pointer (0x01), MSB(0x00), LSB (0x08)

and read out Addressbyte(0x31), (0x00), (0x08) as a desired result 

but I am reading out Addressbyte(0x31), (0x00), (0x18), (0x01).

I have attached results below which are taken by logic analyzer. Any guidance to help me understand where I am doing mistake will be appreciated.

Results taken by logic analyzer for MCP9808

signal_78531.png


Code:


#define I2C__MSP430FR4133_H_

#include
#include
#include
#include
#include "usci.h"

#define AMBIENT_TEMPERATURE        0x05
//#define Configuration_Reg        0x01
#define DEVICE_ID_REGISTER          0x04
#define MANUFACTURE_ID_REGISTER            0x0054
//#define AdressByte                     0x30


 uint16_t tlen = 0;
 uint16_t rlen = 0;
 int *tx = NULL;
 int *rx = NULL;
 uint8_t addr = 0x18;
// void *tx =(void *)0x01;
// void *rx =(void *)0x00;

 
 
volatile unsigned char RXData;
volatile unsigned char TXData;

long Temperature;
void Stop_WD (void);
uint16_t I2C_TempRead(void);
uint16_t I2C_readMode(void);
void delay_tick(uint16_t);


unsigned char Adressbyte[10];
unsigned char Transmit [10];
unsigned char Meas_Receive [10];


int main(void)
{
 
  Stop_WD();
    
// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings
PM5CTL0 &= ~LOCKLPM5;
Set_I2C();
//Transmit [0] =0x30 & 0xFE;
Transmit [0] = 0x01;
Transmit [1] = 0x00;
Transmit [2]=  0x08;

Meas_Receive [0] = 0x07;


__bis_SR_register(GIE);

I2C_write(&Transmit[0],3,addr);

delay_tick(1);

Set_I2C();


I2C_write_read (&Transmit[0],1,&Meas_Receive [0],3,addr);
//I2C_write(&Transmit[0],1,addr);
//I2C_read(&Meas_Receive [0],2,addr);

I2C_readMode();
I2C_TempRead();

    while (1)
    {
        __delay_cycles(2000);
        while (UCB0CTL1 & UCTXSTP);         // Ensure stop condition got sent
        UCB0CTL1 |= UCTXSTT;                // I2C start condition
      
        __bis_SR_register(LPM0_bits|GIE);   // Enter LPM0 w/ interrupt
    }
}



#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
    case USCI_I2C_UCALIFG:   break;         // Vector 2: ALIFG
    case USCI_I2C_UCNACKIFG:                // Vector 4: NACKIFG
      UCB0CTL1 |= UCTXSTT;                  // resend start I2C start condition
      break;
    case USCI_I2C_UCSTTIFG:  break;         // Vector 6: STTIFG
    case USCI_I2C_UCSTPIFG:          // Vector 8: STPIFG
//     TXData = 0;
//     UCB0IFG &= ~UCSTPIFG;                 // Clear stop condition int flag
     break;
    case USCI_I2C_UCRXIFG3:  break;         // Vector 10: RXIFG3
    case USCI_I2C_UCTXIFG3:  break;         // Vector 14: TXIFG3
    case USCI_I2C_UCRXIFG2:  break;         // Vector 16: RXIFG2
    case USCI_I2C_UCTXIFG2:  break;         // Vector 18: TXIFG2
    case USCI_I2C_UCRXIFG1:  break;         // Vector 20: RXIFG1
    case USCI_I2C_UCTXIFG1:           // Vector 22: TXIFG1
//      UCB0TXBUF = TXData++;
      break;
    case USCI_I2C_UCRXIFG0:                 // Vector 24: RXIFG0
      RXData = UCB0RXBUF;                   // Get RX data
      __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
      break;
    case USCI_I2C_UCTXIFG0:  break;         // Vector 26: TXIFG0
    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;
  }
}

void Stop_WD (void)
 {
   WDTCTL = WDTPW | WDTHOLD;                                    // Stop WDT
 }



uint16_t I2C_readMode(void)
{
  uint8_t UpperByte = 0;
  uint8_t LowerByte = 0;
  uint16_t data = 0;
 
//  UpperByte = i2c_read(); // READ 8 bits
////and Send ACK bit
//LowerByte = i2c_read(); // READ 8 bits
////and Send NAK bit
 
 data = UpperByte<<8|LowerByte;
 return data;
}

uint16_t I2C_TempRead(void)
{
 uint8_t UpperByte = 0;
 uint8_t LowerByte = 0;
 uint16_t Temperature = 0;
 
 
 //Convert the temperature data
//First Check flag bits
if ((UpperByte & 0x80) == 0x80)
{                                                       //TA ³ TCRIT
}
if ((UpperByte & 0x40) == 0x40)
{                                                       //TA > TUPPER
}
if ((UpperByte & 0x20) == 0x20)
{                                                       //TA < TLOWER
}
UpperByte = UpperByte & 0x1F;                           //Clear flag bits

if ((UpperByte & 0x10) == 0x10)
{                                                       //TA < 0°C
UpperByte = UpperByte & 0x0F;                           //Clear SIGN
Temperature = 256 - (UpperByte * 16 + LowerByte / 16);
}
else
{                                                       //TA ³ 0°C
Temperature = (UpperByte * 16 + LowerByte / 16);
                                                        //Temperature = Ambient Temperature (°C)
}
return Temperature;
}

void delay_tick(uint16_t tick)
{
  for (uint16_t i=0;i}
;>





//----------------------------------------------I2C--------------------------------//

void Set_I2C(void)
{
  P5SEL0 |= BIT2 | BIT3;                  // I2C pins
 // Configure USCI_B0 for I2C mode
  UCB0CTLW0 |= UCSWRST;                   // Software reset enabled
  UCB0CTLW0 |= UCMODE_3 | UCMST | UCSYNC; // I2C mode, Master mode, sync
  UCB0CTLW1 |= UCASTP_2;                  // Automatic stop generated

  UCB0BRW = 0x0008;                         // baudrate = SMCLK / 8
  UCB0TBCNT = 0x07;                       // number of bytes to be received
  UCB0I2CSA = 0x18;                       // Slave address is 0x18
  UCB0CTL1 &= ~UCSWRST;
  UCB0IE |= UCRXIE | UCNACKIE | UCBCNTIE ;
 
 
}



//------------------I2C_Master_write-------------------------------------------------//

uint32_t I2C_write(unsigned char* tx, uint32_t tlen,uint8_t addr)

{
  uint32_t r_val = 0;
 
  UCB0I2CSA = addr;                             // Assing slave address
 
  while ((UCB0IFG & UCSTPIFG));                 // Check if Stop condition on
  UCB0CTL1 |= UCTR + UCTXSTT;                   // Start writing through I2C
  while (!(UCB0IFG & UCTXIFG));                 // Wait until TX buffer ready
  for(uint32_t i = 0; i < tlen; i++)
  {           
    UCB0TXBUF = *((uint8_t*)tx + i);            // Write string in  TX buffer of I2C        
    while (!(UCB0IFG & UCTXIFG));               // Wait until TX buffer ready
    if( i == tlen - 1)
    {                                           // If only one byte left to write
      UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
      UCB0IFG &= ~UCTXIFG;                      // Clear USCI_B0 TX int flag
    }
    r_val++;                                    // Increment return value
  }

  return r_val;
}

//----------------I2C_MASTER_READ--------------------------------------------------------//

uint32_t I2C_read(unsigned char* rx, uint32_t rlen, uint8_t addr)

{
  UCB0IFG &= ~UCSTPIFG;
  uint32_t r_val = 0;
 
  UCB0I2CSA = addr;                               // Assing slave address
  if (rlen != 0)
  {
    while ((UCB0CTL1 & UCTXSTP));                 // Check if Stop condition on
    UCB0CTL1 &= ~UCTR;                            // Set writing bit in register to 0
    UCB0CTL1 |= UCTXSTT;                          // Start reading through I2C
    while (!(UCB0CTL1 & UCTXSTT));                // start condition is not sent
    // only one byte
    if (rlen == 1)
    {
      while (!(UCB0IFG & UCRXIFG))                // wait until start condition is sent
      {
        if((UCB0CTL1 & UCTXSTT)==0)
          UCB0CTL1 |= UCTXSTP;                    // generate stop condition
      }
      while (UCB0CTL1 & UCTXSTP);                 // Ensure stop condition got sent
      *((uint8_t*)rx) = UCB0RXBUF;
      return 1;
    }
    // multiple bytes
    for (uint8_t i = 0; i < rlen-1; i++)
    {
      while (!(UCB0IFG & UCRXIFG));                // Wait until new data was written into RX buffer
      *((uint8_t*)rx + i) = UCB0RXBUF;              // Read RX buffer
      r_val ++;                                     // Increment return value      
    }
    UCB0CTL1 |= UCTXSTP;                            // Generate Stop condition  
    while (UCB0CTL1 & UCTXSTP);                     // Wait untill its generated
    *((uint8_t*)rx+rlen-1) = UCB0RXBUF;             // Read last byte
  }
  return r_val++;
}

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

uint32_t I2C_write_read (unsigned char* tx,uint32_t tlen,unsigned char* rx, uint32_t rlen,uint8_t addr)
{
 
  uint32_t r_val = 0;
 
  UCB0I2CSA = addr;                             // Assing slave address
 
  while ((UCB0IFG & UCSTPIFG));                 // Check if Stop condition on
  UCB0CTL1 |= UCTR + UCTXSTT;                   // Start writing through I2C
  while (!(UCB0IFG & UCTXIFG));                 // Wait until TX buffer ready
  for(uint32_t i = 0; i < tlen; i++)
  {           
    UCB0TXBUF = *((uint8_t*)tx + i);            // Write string in  TX buffer of I2C        
    while (!(UCB0IFG & UCTXIFG));               // Wait until TX buffer ready
    if( i == tlen - 1)
    {                                           // If only one byte left to write
      UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
      UCB0IFG &= ~UCTXIFG;                      // Clear USCI_B0 TX int flag
    }
    r_val++;                                    // Increment return value
  }
 
r_val = 0;
 
  if (rlen != 0)
  {
    while ((UCB0CTL1 & UCTXSTP));                 // Check if Stop condition on
    UCB0CTL1 &= ~UCTR;                            // Set writing bit in register to 0
    UCB0CTL1 |= UCTXSTT;                          // Start reading through I2C
    while (!(UCB0CTL1 & UCTXSTT));                // start condition is not sent
    // only one byte
    if (rlen == 1)
    {
      while (!(UCB0IFG & UCRXIFG))                // wait until start condition is sent
      {
        if((UCB0CTL1 & UCTXSTT)==0)
          UCB0CTL1 |= UCTXSTP;                    // generate stop condition
      }
      while (UCB0CTL1 & UCTXSTP);                 // Ensure stop condition got sent
      *((uint8_t*)rx) = UCB0RXBUF;
      return 1;
    }
    // multiple bytes
    for (uint8_t i = 0; i < rlen-1; i++)
    {
      while (!(UCB0IFG & UCRXIFG));                // Wait until new data was written into RX buffer
      *((uint8_t*)rx + i) = UCB0RXBUF;              // Read RX buffer
      r_val ++;                                     // Increment return value      
    }
    UCB0CTL1 |= UCTXSTP;                            // Generate Stop condition  
    while (UCB0CTL1 & UCTXSTP);                     // Wait untill its generated
    *((uint8_t*)rx+rlen-1) = UCB0RXBUF;             // Read last byte
  }
 
  return r_val++;
}


Best Regards,

Shetty 

Student

[ - ]
Reply by mr_banditJanuary 29, 2019

In I2C land, to read a register:

write the device with the device address and the register address

do a read of the device with the device address, then read the value (which could be 1 or 2 bytes)

Meaning: write the device address (say 0x21) with the LS bit == 0, so you actually write 0x42  ... the bits in the byte are [ A6 A5 A4 A3 A2 A1 A0 1 ]  (A6 means the bit at location [ 0100 0000 ], etc)

This means taking the device address and shift left 1 bit. It looks like you are not doing that.

Then write the register address without shifting, so register 0x02 is written a [ 0x02 ]

Then write the address with the read bit: [ A6 A5 A4 A3 A2 A1 A0 0 ]

then read the device for the desired number of bytes

If you look at the datasheet for your device, you should see the exact pattern of bits and SDA/SCL line wiggles. Make sure your logic analyzer trace shows the same wiggles.

(And kudos to you for using a logic analyzer.  You should also consider getting a $35..$400 oscilloscope. - 4 channel 350/400 MHz - http://www.saelig.com/ds1000z-series/ds1054z.htm ... of course, i cannot tell you there is a SW tool to convert this to 100 MHz out on the web...)

Hope this helps ... bandit


[ - ]
Reply by BVRameshJanuary 29, 2019

Dear Shetty,


In your interrupt service routine, you are servicing vector 22: USCI_I2C_UCTXIFG1, and vector 24: USCI_I2C_UCRXIFG0, which means you are receiving from I2C channel 0 and transmitting to I2C channel  1, which is inconsistent. Either you have to use vector 20 and 22 which is channel 1, or vector 24 and 26 which is channel 0, to whichever channel you have connected.

From the details you have given earlier, port 5.2: UCB0SDA, and port 5.3: UCB0SCL, hence you may have to use vector 24 and 26.

Please try this after correcting your code.

Regards,

B V Ramesh.