msp430temperaturetexas-instruments

Reading temperature values from TMP117 sensor using MSP430FR5969 MCU


I'm trying to read temperature values from the TMP117 sensor [1] connected to an MSP430FR5969 MCU [2] through the I2C protocol. The data in the result register of the sensor is in two's complement format, has a data width of 16 bits, and a resolution of 0.0078125 °C. I used Code Composer Studio to program the MCU and I've attached the code below:

#include <msp430.h> 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>

#define SLAVE_ADDR  0x48
#define CONVERSION_READY  0x10
#define TMP117_TEMP_REG  0x00
#define TMP117_CONFIG_REG  0x01
#define TMP117_RESOLUTION 0.0078125f

#define CMD_TYPE_0_SLAVE      0
#define CMD_TYPE_1_SLAVE      1
#define CMD_TYPE_2_SLAVE      2

#define CMD_TYPE_0_MASTER      3
#define CMD_TYPE_1_MASTER      4
#define CMD_TYPE_2_MASTER      5

#define TYPE_0_LENGTH   1
#define TYPE_1_LENGTH   2
#define TYPE_2_LENGTH   6

#define MAX_BUFFER_SIZE     20

char temperature[] = "Temperature is: ";
char dot[] = ".";
char celcuis[] = " degree Celcius\r\n";

int i;
char text[] = " I am an MSP430FR5969\r\n";

char rx_char[5];

volatile int rx_val = 0;

void clockSetup();
void gpioSetup();
void uartSetup();
void i2cSetup();
void ser_output(char *str);

uint8_t MasterType1 [TYPE_1_LENGTH] = {0x02, 0x20};

uint8_t SlaveType1 [TYPE_1_LENGTH] = {0};

typedef enum I2C_ModeEnum{
    IDLE_MODE,
    NACK_MODE,
    TX_REG_ADDRESS_MODE,
    RX_REG_ADDRESS_MODE,
    TX_DATA_MODE,
    RX_DATA_MODE,
    SWITCH_TO_RX_MODE,
    SWITHC_TO_TX_MODE,
    TIMEOUT_MODE
} I2C_Mode;

I2C_Mode MasterMode = IDLE_MODE;

/* The Register Address/Command to use*/
uint8_t TransmitRegAddr = 0;

uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t RXByteCtr = 0;
uint8_t ReceiveIndex = 0;
uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t TXByteCtr = 0;
uint8_t TransmitIndex = 0;

I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count);

I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count);
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);

I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count)
{
    MasterMode = TX_REG_ADDRESS_MODE;
    TransmitRegAddr = reg_addr;
    RXByteCtr = count;
    TXByteCtr = 0;
    ReceiveIndex = 0;
    TransmitIndex = 0;

    UCB0I2CSA = dev_addr;
    UCB0IFG &= ~(UCTXIFG + UCRXIFG);
    UCB0IE &= ~UCRXIE;
    UCB0IE |= UCTXIE;

    UCB0CTLW0 |= UCTR + UCTXSTT;
    __bis_SR_register(LPM0_bits + GIE);

    return MasterMode;
}

I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
{
    MasterMode = TX_REG_ADDRESS_MODE;
    TransmitRegAddr = reg_addr;

    CopyArray(reg_data, TransmitBuffer, count);

    TXByteCtr = count;
    RXByteCtr = 0;
    ReceiveIndex = 0;
    TransmitIndex = 0;

    UCB0I2CSA = dev_addr;
    UCB0IFG &= ~(UCTXIFG + UCRXIFG);
    UCB0IE &= ~UCRXIE;
    UCB0IE |= UCTXIE;

    UCB0CTLW0 |= UCTR + UCTXSTT;
  __bis_SR_register(LPM0_bits + GIE);

    return MasterMode;
}

void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
    uint8_t copyIndex = 0;
    for (copyIndex = 0; copyIndex < count; copyIndex++)
    {
        dest[copyIndex] = source[copyIndex];
    }
}

void main(void)
{
    WDTCTL = WDTPW | WDTHOLD;

    clockSetup();
    gpioSetup();
    uartSetup();
    i2cSetup();

    __bis_SR_register(GIE);


    while (1)
    {
           _delay_cycles(500000);
            I2C_Master_ReadReg(SLAVE_ADDR, 0x00, TYPE_1_LENGTH);
            CopyArray(ReceiveBuffer, SlaveType1, TYPE_1_LENGTH);

            if(ReceiveBuffer[1] & CONVERSION_READY)
            {
                I2C_Master_ReadReg(SLAVE_ADDR, 0x00, TYPE_1_LENGTH);
                CopyArray(ReceiveBuffer, SlaveType1, TYPE_1_LENGTH);
                _no_operation();
            }

    ltoa(rx_val, rx_char, 10);
    ser_output(temperature);
    ser_output(rx_char);
    ser_output(dot);
    ser_output(celcuis);
    }
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
  //Must read from UCB0RXBUF
 //// uint8_t rx_val = 0;
  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
      break;
    case USCI_I2C_UCSTTIFG:  break;         // Vector 6: STTIFG
    case USCI_I2C_UCSTPIFG:  break;         // Vector 8: STPIFG
    case USCI_I2C_UCRXIFG3:  break;         // Vector 10: RXIFG3
    case USCI_I2C_UCTXIFG3:  break;         // Vector 12: TXIFG3
    case USCI_I2C_UCRXIFG2:  break;         // Vector 14: RXIFG2
    case USCI_I2C_UCTXIFG2:  break;         // Vector 16: TXIFG2
    case USCI_I2C_UCRXIFG1:  break;         // Vector 18: RXIFG1
    case USCI_I2C_UCTXIFG1:  break;         // Vector 20: TXIFG1
    case USCI_I2C_UCRXIFG0:                 // Vector 22: RXIFG0
        rx_val = UCB0RXBUF;
        if (RXByteCtr)
        {
          ReceiveBuffer[ReceiveIndex++] = rx_val;
          RXByteCtr--;
        }
        if (RXByteCtr == 1)
        {
          UCB0CTLW0 |= UCTXSTP;
        }
        else if (RXByteCtr == 0)
        {
          UCB0IE &= ~UCRXIE;
          MasterMode = IDLE_MODE;
          __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
        }
        break;
    case USCI_I2C_UCTXIFG0:                 // Vector 24: TXIFG0
        switch (MasterMode)
        {
          case TX_REG_ADDRESS_MODE:
              UCB0TXBUF = TransmitRegAddr;
              if (RXByteCtr)
                  MasterMode = SWITCH_TO_RX_MODE;   // Need to start receiving now
              else
                  MasterMode = TX_DATA_MODE;        // Continue to transmision with the data in Transmit Buffer
              break;

          case SWITCH_TO_RX_MODE:
              UCB0IE |= UCRXIE;              // Enable RX interrupt
              UCB0IE &= ~UCTXIE;             // Disable TX interrupt
              UCB0CTLW0 &= ~UCTR;            // Switch to receiver
              MasterMode = RX_DATA_MODE;    // State state is to receive data
              UCB0CTLW0 |= UCTXSTT;          // Send repeated start
              if (RXByteCtr == 1)
              {
                  //Must send stop since this is the N-1 byte
                  while((UCB0CTLW0 & UCTXSTT));
                  UCB0CTLW0 |= UCTXSTP;      // Send stop condition
              }
              break;

          case TX_DATA_MODE:
              if (TXByteCtr)
              {
                  UCB0TXBUF = TransmitBuffer[TransmitIndex++];
                  TXByteCtr--;
              }
              else
              {
                  //Done with transmission
                  UCB0CTLW0 |= UCTXSTP;     // Send stop condition
                  MasterMode = IDLE_MODE;
                  UCB0IE &= ~UCTXIE;                       // disable TX interrupt
                  __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
              }
              break;

          default:
              __no_operation();
              break;
        }
        break;
    default: break;
  }
}

    void ser_output(char *str)
    {
        while(*str !=0)
        {
            while(!(UCA0IFG&UCTXIFG));
            UCA0TXBUF = *str++;
        }
    }

    void gpioSetup()
    {
         P1OUT   &= ~BIT0;                             // Clear P1.0 output latch
         P1DIR   |= BIT0;                              // For LED
         P1SEL1  |= BIT6 | BIT7;                      // I2C pins
         P2SEL1  |= BIT0 | BIT1;                      // USCI_A0 UART operation
         P2SEL0  &= ~(BIT0 | BIT1);
         PM5CTL0 &= ~LOCKLPM5;
    }

    void clockSetup()
    {
        FRCTL0 = FRCTLPW | NWAITS_1;
        CSCTL0_H = CSKEY >> 8;
        CSCTL1 = DCORSEL | DCOFSEL_0;
        CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
        CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;
        CSCTL0_H = 0;
    }

    void uartSetup()
    {
        UCA0CTL1 |= UCSWRST;
        UCA0CTL1 |= UCSSEL_2;
        UCA0BR0 = 6;
        UCA0BR1 = 0;
        UCA0MCTLW = 0xAA;
        UCA0MCTLW |= UCOS16 | UCBRF_1;
        UCA0CTL1 &= ~UCSWRST;
        UCA0IE |= UCRXIE;
    }

    void i2cSetup()
    {
        UCB0CTLW0  |= UCSWRST;
        UCB0CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC;
        UCB0CTLW1  |= UCSSEL_2;
        UCB0BRW   = 10;
        UCB0I2CSA = 0x0048;
        UCB0CTLW0  &= ~UCSWRST;
        UCB0IE |= UCRXIE | UCNACKIE | UCBCNTIE;
    }

I get the following data:

Temperature values in ReceviedBuffer, and transmitted value to PuTTY terminal

(i) My first question is that why I'm getting the RecevieBuffer1 values on the terminal and the missing value of the RecevieBuffer[0].

(ii) My second question is that how would I convert the 16-bit raw data to value in Celsius.

Many thanks


Solution

  • To get a 16-bit value from your buffer of bytes you need to cast each byte up to 16-bit values, shift the second byte by 8-bits, and OR the two together. In one line it would look like this:

    int16_t value = int16_t(buffer[0]) | int16_t(buffer[1]) << 8;
    

    Based on the value you are reading of 0x0aaf, I would guess the temperature sensor you are using probably outputs the value in in celsius*100 to keep it an integer and still have 100th of degree precision. So to get the value in celsius you'd have to cast to a float or double and divide by 100.0. So 0x0aaf is 2735, meaning 27.35 degrees C.