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.

MSP430 and TMP101 I2C Interface

Other Parts Discussed in Thread: TMP101, TMP100

Hello,

First of all let me begin by saying I am very, very new to this. I am taking a class for the first time using MCUs and I am very much confused. I don't find the forums or the support community much help at all yet (because a lot of it is over my head) and I'm hoping that I can really get some help for a beginner. I have some very basic questions for the project I am working on, dealing with the TMP101 temp sensor. Please help by answering questions in a way that a beginner could understand. Also, a response "just read the datasheet" won't help much because I have read a great deal of both datasheets (TMP101 and MSP430) and a lot of it is still Greek to me :)

Ok, so I am hooking up the MCU and the TMP101 in a MASTER/Slave configuration.1.) When wiring the TMP101, what do I wire ADD0 (pin5) to. It says in the TMP101 datasheet that a slave address must be set in the software, which it is (see Code below). This is done when UCB012CSA = 0x49. Now according to the datasheet, this is required when ADD0 is FLOAT, or is not connected. So I did this because I left pin5 unconnected. This was just example code I had copied and originally it was set at 0x48 which makes more sense because this is for just connecting to one device but it says ADD0 has to be 0 so I'm not exactly sure what that means. Does setting it to 0x48 assume the msb is 0? But then I'm back to the original question as to what do I wire pin5 to?

Hope I didn't make that more confusing than it is but as you can tell, I am pretty confused. Second question is, does the ALERT pin (pin3)  need to be wired to anything? According to the datasheet, it has something to do with SMBus? So I assume if using I2C, it is unused? At first I had Vdd going to it (with a 10k pull up resistor, I also had SCL and SDA wired with 10k pull up resistors), then I just completely removed power to it and had no difference in output (although the output is not what I wanted either way).

Ok, so here is my code that I got from some ti example code. Basically, what I think it is supposed to do is if a temp is greater than 28 deg. C, the LED is turned on. If not, the LED is turned off. I changed the one thing I mentioned before (UCB012CSA = 0x49 instead of 0x48) and added a bunch of comments to help me understand it better but other than that it is the same example code. It is not working as it supposed to; the LED turns on no matter what (even after switching the logic) so I am lost at what to do. Please help, and remember I am very new to this.

Code:

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

// CC430F613x Demo - USCI_B0 I2C Master RX single bytes from MSP430 Slave

//

// Description: This demo connects two MSP430's via the I2C bus. The master

// reads from the slave. This is the MASTER CODE. The data from the slave

// transmitter begins at 0 and increments with each transfer. The received

// data is in R5 and is checked for validity. If the received data is

// incorrect, the CPU is trapped and the P1.0 LED will stay on. The USCI_B0

// RX interrupt is used to know when new data has been received.

// ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.045MHz

// Built with CCE Version: 3.2.2 and IAR Embedded Workbench Version: 4.11B

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

#include

"cc430x613x.h"

#define

RED_LED BIT6

#define

GRN_LED BIT0

unsigned

int RxByteCtr;

unsigned

int RxWord = 0;

//volatile unsigned char RxBuffer[1]; // Allocate 128 byte of RAM

void

main(void)

{

WDTCTL = WDTPW + WDTHOLD;

// Stop WDT

P1OUT = 0xFF;

//Enables Port 1 Output as 1111 1111 (binary) //Outputs are all high

// P2OUT |= BIT6 +BIT7;

P3OUT = 0;

//Port 3 Output is low

P1DIR |= GRN_LED;

//OR'd with all 1's ?

P3DIR |= RED_LED;

//Don't understand the purpose of this and above line. //Pg 305 Family UsersGuide

PMAPPWD = 0x02D52;

// Get write-access to port mapping registers

//Same as PMAPKEYID-Chapter 9 FamilyUsersGuide

//0x02D52 must be used to have access

P2MAP6 = PM_UCB0SDA;

// Map UCB0SDA output to P2.6

//USCI_B0 I2C data (open drain and direction controlled by USCI)

//page 323 FamilyUsersGuide

P2MAP7 = PM_UCB0SCL;

// Map UCB0SCL output to P2.7

//USCI_B0 I2C clock

PMAPPWD = 0;

// Mapping complete, lock port mapping registers with an invalid key (anything other than 0x02D52)

P2SEL |= BIT6 + BIT7;

// Assign I2C pins to USCI_B0 By OR'ing.

UCB0CTL1 |= UCSWRST;

// Enable software reset //Would rewriting this as UCSWRST = 1 accomplish the same thing?

//pg. 523 of the Family Users Guide

UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;

// UCMST Selects Master Mode, UCSYNC is bit 0-enables Synchronous Mode

//UCMODE_3 selects I2C mode-11 binary which is equal to 3, but not sure how this works. Does the synchronous mode

// automatically synchronize it? Is the UCMODEx just not even needed? pg.522 FUG

UCB0CTL1 = UCSSEL_2 + UCSWRST;

// Use SMCLK, keep SW reset Note: In FUG, the 0 bit for UCB0CTL0 and UCB0CTL1

//are already 1?

UCB0BR0 = 12;

// fSCL = SMCLK/12 = ~100kHz //SMCLK runs at apprx. 1MHZ, which would actually be fSCL=83.3kHz

//Don't understand the purpose of setting it to this frequency. Timing issue?

UCB0BR1 = 0;

//UCB0BR0 and UCB0BR1 work together to form a prescaler value, not sure how it works Pg 523 of FUG

UCB0I2CSA = 0x49;

// Set slave address //UCB0I2CSA is the Slave Address Register pg. 525 FUG

//The master must first address slave devices via a slave address byte. 0x48 corresponds

//to the slave address 0100 1000 given in Table 12 of the TMP101 datasheet pg 8. The datasheet

//indicates that up to 3 devices can be connected but we are using just one so ADD0=0.

UCB0CTL1 &= ~UCSWRST;

// Clear software reset, resume operation//Would UCSWRST=0 be same thing?-I think it can only be 1.

UCB0IE |= UCRXIE;

// Enable RX interrupt

TA1CTL = TASSEL_2 + MC_2;

// ACLK, upmode, clear TAR ---This should be SMCLK? Why Upmode? Pg 370 FUG

while (1)

{

RxByteCtr = 2;

// Load RX byte counter //Why 2?

UCB0CTL1 |= UCTXSTT;

// I2C start condition //Is there supposed to be a NACK before (Bit 3 of UCB0CTL1 Register pg. 523 FUG)

__bis_SR_register(CPUOFF + GIE);

// Enter LPM0, enable interrupts //LMP0 --Table 1-2 Operation Modes pg. 32 FUG

// Remain in LPM0 until all data

// is RX'd

if

(RxWord < 28) // >28C? //So this is the temperature?

P1OUT |= 0x01;

// Yes, P1.0 = 1

else

P1OUT &= ~0x01;

// No, P1.0 = 0

__disable_interrupt();

TA1CCTL0 = CCIE;

__bis_SR_register(CPUOFF + GIE);

// Enter LPM0, enable interrupts

TA1CCTL0 &= ~CCIE;

// Remain in LPM0 until TACCR0 ----WHAT DOES THIS MEAN???

// interrupt occurs

TA1CCTL0 &= ~CCIE;

//____________________________________________^^^^^^^

}

}

// The USCIAB0TX_ISR is structured such that it can be used to receive any

// 2+ number of bytes by pre-loading RxByteCtr with the byte count.

#pragma

vector = USCI_B0_VECTOR

__interrupt

void USCI_B0_ISR(void)

{

RxByteCtr--;

// Decrement RX byte counter

if

(RxByteCtr)

{

RxWord = (unsigned int) UCB0RXBUF ; // Get received byte

if (RxByteCtr == 1) // Only one byte left?

UCB0CTL1 |= UCTXSTP;

// Generate I2C stop condition

}

else

{

RxWord |= UCB0RXBUF;

// Get final received byte,

// Combine MSB and LSB

__bic_SR_register_on_exit(CPUOFF);

// Exit LPM0

}

}

// Timer A0 interrupt service routine

#pragma

vector=TIMER1_A0_VECTOR

__interrupt

void TIMER1_A0_ISR(void)

{

__bic_SR_register_on_exit(CPUOFF);

// Exit LPM0

}

  • Matthew Schronce said:

    When wiring the TMP101, what do I wire ADD0 (pin5) to.

    I assume since the datasheet suggests leaving the pin floating it should be ok however generally I would say its best to either hook it up to the positive rail with a pull up or tie it to ground. Whichever you choose, just make sure to set the address correctly. (0x48 for ground, 0x49 for pulled up)

    Matthew Schronce said:
    Second question is, does the ALERT pin (pin3)  need to be wired to anything?

    I don't believe so, it appears to be just an output pin which could be additionally read if desired.

    Matthew Schronce said:
    (RxWord < 28) // >28C? //So this is the temperature?

    Sorry its late here and I'm a bit tired and skimming over your code. If you look at Table 8. Resolution of the TMP100 and TMP101 of the data sheet the TMP101 links to you will see there are different conversions and Table 5. Temperature Data Format might help make this clearer.

    You are reading two bytes from the device, but these do not directly represent temperature. For instance, in 12 bit mode the read data must be multiplied by 0.0625 to obtain the appropriate temperature in Celsius. e.g. 0x755 (2047) * .0625 = 128



  • Alan, thank you very much for your response, I really appreciate it and hope you can help me with these questions:

    I assume since the datasheet suggests leaving the pin floating it should be ok however generally I would say its best to either hook it up to the positive rail with a pull up or tie it to ground. Whichever you choose, just make sure to set the address correctly. (0x48 for ground, 0x49 for pulled up)

    --What the datasheet says is for the FLOAT to be used when connecting two devices to the sensor. So I think it has to be 0 since I'm connecting just one device. So then it just hooks up to GND? I'm still confused on that one. And it doesn't say that ADD0 needs a pull up, just SDA, SCL, and the ALERT pins.

    Sorry its late here and I'm a bit tired and skimming over your code. If you look at Table 8. Resolution of the TMP100 and TMP101 of the data sheet the TMP101 links to you will see there are different conversions and Table 5. Temperature Data Format might help make this clearer.

    You are reading two bytes from the device, but these do not directly represent temperature. For instance, in 12 bit mode the read data must be multiplied by 0.0625 to obtain the appropriate temperature in Celsius. e.g. 0x755 (2047) * .0625 = 128

    --I understand that pretty well. From the code, I get that it goes through an ISR which sends back RxWord which was filled by the buffer. I assume that 28 is just a decimal number that corresponds to 28 Deg C that can be translated into the Binary code they have in the datasheet table. What I don't get is the if-else statement that fills the buffer twice (with 2 bytes since RxByteCtr =2 and then decrements). Because there are two bytes (16 bits), and the buffer is only 8 bits, how does this work? I am really lost on that one.
    Thanks, Matt

  • Matthew Schronce said:
    --What the datasheet says is for the FLOAT to be used when connecting two devices to the sensor. So I think it has to be 0 since I'm connecting just one device. So then it just hooks up to GND? I'm still confused on that one. And it doesn't say that ADD0 needs a pull up, just SDA, SCL, and the ALERT pins.

    The ADD0 pin allows you have some choice over the address of the device. This allows 2 of the same devices to be on a bus without this ability you could only talk to one - as all I2C devices must have unique address.

    This being said its up to you which of the addresses you want for your device. You can choose either address even if you only plan on having once device on your i2c bus. So hook it to ground or the positive rail. Floating pins can be unreliable - its possible for a floating pin to be read as high or low as there is no reference voltage. Its possible the device has some protection against this since they suggest leaving it floating however personally I prefer ensuring the state of the pin is as desired.

    Matthew Schronce said:
    --I understand that pretty well. From the code, I get that it goes through an ISR which sends back RxWord which was filled by the buffer. I assume that 28 is just a decimal number that corresponds to 28 Deg C that can be translated into the Binary code they have in the datasheet table. What I don't get is the if-else statement that fills the buffer twice (with 2 bytes since RxByteCtr =2 and then decrements). Because there are two bytes (16 bits), and the buffer is only 8 bits, how does this work? I am really lost on that one.


    Looking at the code - its a little hard to read with the formatting above - that does look somewhat strange. The MSP430 HW buffer stored 1 byte so each interrupt it is up to you to correctly store that byte as desired.

    RxWord is an int which is the correct size to store the two bytes of temperature (at least on 16 bit architecture). However it looks like the bytes are not stored correctly.

    When the first byte comes in you would want to do something similar to the below:

    RxWord = UCB0RXBUF << 4;

    This is from table 3 in the data sheet. This will mean RxWord holds the following valid data 0000XXXXXXXX0000 where X is desired.


    When the second byte comes in, table 4 of the data sheet, we are only interested in moving its MS 4 bits into the lowest 4-bit nibble of RxWord. So you need to do this:

    RxWord |= UCB0RXBUF >>4; This should now mean RxWord would now contain the following desired bits 0000XXXXXXXXXXXX.


    Once you have RxWord you need to convert the temperature into Celsius.

    float temperature = (float)RxWord * 0.0625.

  • Alan, thanks again. Your suggestions are definetly helping. I added what you suggested in the code but there is something that I am really confused about. In the main while loop, the _bis_SR_register(CPUOFF + GIE) is giving me problems debugging. It will not let me move the cursor past this line of code. I am assuming because this puts the MCU in sleep mode and turns everything off? I'm not sure but I have no way to check and see if the code is performing like it is supposed to. Also, at that point in the code, how and where is the ISR performing its' task? According to the CC430 (or MSP430) datasheet, this mode is LPM0 and it disables the CPU and MCLK and SMCLCK is optionally active (which I am using). Like I said, I am assuming this line of code puts the MCU to sleep and then waits for an interrupt to occur but I am unsure how this interrupt is supposed to happen. The next line of code tests the temp value, then it appears to go into some other TimerA Interrupt Capture/Compare. Not sure what is going on there. Man, this is just really confusing but I hope you can make some sense of it. Here is the continous loop that I am talking about:

    while(1)

    {

    RxByteCtr = 2; // Load RX byte counter //2 bytes

    UCB0CTL1 |= UCTXSTT; // I2C start condition // UCB0CTL1 Register pg. 523 FUG)

    __bis_SR_register(CPUOFF + GIE); // Enter LPM0, enable interrupts //LMP0 --Table 1-2 Operation Modes pg. 32 FUG

    //The bis_SR_register is a low power mode that will not exit until interrupt occurs -- I think.

    //UCSCTL6 &= ~SMCLKOFF;---Do I need this?

    // Remain in LPM0 until all data is RX'd

    //temperature = RxWord*0.0625;

    if (RxWord < 000110010000)//25 deg C

    P1OUT |= 0x01;// Yes, P1.0 = 1

    else

    P1OUT &= ~0x01; // No, P1.0 = 0

    __disable_interrupt();

    TA1CCTL0 = CCIE;

    __bis_SR_register(CPUOFF + GIE); // Enter LPM0, enable interrupts

    TA1CCTL0 &= ~CCIE; // Remain in LPM0 until TACCR0  ----WHAT DOES THIS MEAN???

    //interrupt occurs

    TA1CCTL0 &= ~CCIE;

    }

    }

  • Matthew Schronce said:
    In the main while loop, the _bis_SR_register(CPUOFF + GIE) is giving me problems debugging. It will not let me move the cursor past this line of code. I am assuming because this puts the MCU in sleep mode and turns everything off?

    Yes this is entering a low power mode, LPM0. To wake from this state an interrupt service routine has to call:

    __bic_SR_register_on_exit(CPUOFF);

    Which will remove the bit telling the CPU to switch off.

    Matthew Schronce said:
    I'm not sure but I have no way to check and see if the code is performing like it is supposed to. Also, at that point in the code, how and where is the ISR performing its' task?

    The following interrupt service routine is called for I2C handling.

    #pragma vector = USCI_B0_VECTOR__interrupt

    void USCI_B0_ISR(void)

    I would have thought putting a break point in there should break ok but this could well mess up that particular read. If you have leds to spare light one in here.

    Matthew Schronce said:
    Like I said, I am assuming this line of code puts the MCU to sleep and then waits for an interrupt to occur but I am unsure how this interrupt is supposed to happen.

    This interrupt should happen because when you are going to sleep you are setting GIE which is the global interrupt enable and prior to this you have enabled the interrupt UCRXIE. Right before you enter the sleep mode you send a start condition, at which point the I2C hardware starts working and it'll be this which will generate the interrupt when required.

    Matthew Schronce said:
    then it appears to go into some other TimerA Interrupt Capture/Compare. Not sure what is going on there

    I am also not sure what is going on there. It *looks* like it is being used as a delay inbetween reads so if the temperature was greater than 28, go to sleep and wake when the timer A expires. However TAR is not being cleared in there, so they delay would not be constant. And why would you not want to delay readings if the temperature was less than 28 also confuses me somewhat.

    You say you got this from TI sample code, how much did you change and could you link to the original? Is this an exercise for your class if so what are you tasked with? Or is this just you learning - if so how do you want this to work?

  • Hi Alan, one of my buddies sent me the example code soi I will find out where he got it from. I have a bunch of i2c example code that came with Code Composer Studio. Some of it is i2c but it is somewhat difficult to follow....My buddy and I are doing an independent study at our school, trying to become familiar with MCU's. Ultimately what we are trying to do is use the two development boards that came in the CC430 development kit, to transmit the temperature data from one board to the other using the RF capabilities and display it on an LCD screen. We have the LCD displaying "hello world" so we are trying to get the temperature to display on the LCD screen, then we will look at the RF and try to figure that out. Right now, we are just working on getting the temperature sensor to work properly.

     

  • OK I wasn't sure if you had altered it heavily - I was curious about the use of TimerA - to me it looks like it could be scrapped, or if you wanted a sampling delay, better implemented.

**Attention** This is a public forum