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.

problem interfacing of cc430f5137 with sht25

Other Parts Discussed in Thread: CC430F5137

Dear Guys,

               I am inerfacing sht25 with cc430f5137 .I want to read temperature value from this sensor but I am not getting it . I am using supply voltage of 2.5 V for msp and the same supply is given to sht25 from msp board and ground is same for both msp and sht25. 10 k pull up resistor  for sda and scl. In order to get temperature data from sensor, first I have to select transmit mode and I am selecting sensor in Hold master mode ,for that I am sending 0xE3 as stated in the data sheet . My code hangs in the trasmit isr which is case 12 in switch case and TXIFG is not set.Kindly help me out .I need urgent help or if somebody has already made this code then kindly share it .Thanks 

#include <msp430.h>
#include <stdint.h>
#include<string.h>
#include"types.h"


#define LED7 BIT7
#define LED6 BIT6
volatile int a=0,b=0;
volatile int i;
unsigned char TXData;
unsigned char TXByteCtr;

volatile uint16_t Temp;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT


P3DIR |= LED6 +LED7;
P3OUT &= ~(LED6 +LED7);

PMAPPWD = 0x02D52; // Get write-access to port mapping regs
P1MAP3 = PM_UCB0SDA; // Map UCB0SDA output to P2.6
P1MAP1 = PM_UCB0SCL; // Map UCB0SCL output to P2.7
PMAPPWD = 0; // Lock port mapping registers

P1SEL |= BIT1 + BIT3; // Select P2.6 & P2.7 to I2C function


UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 |= UCSSEL_2; // 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
UCB0IE |= UCTXIE; // Enable TX interrupt
UCB0IE |= UCNACKIE;
UCB0IE |= UCRXIE;

while (1)
{
TXByteCtr = 0x01;

while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition

__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts

__no_operation(); // Remain in LPM0 until all data


if(a==1) // when not acknowledged by the sensor
{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
a=0;
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; // 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
UCB0IE |= UCTXIE; // Enable TX interrupt
UCB0IE |= UCNACKIE;
UCB0IE |= UCRXIE;
// Holds TX data
// Load TX byte counter
// Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT;
__bis_SR_register(LPM0_bits + GIE);
}


if(b==1)   // for receiver setting
{

b=0;


UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 |= UCSSEL_2;
UCB0CTL1 &=~UCTR;// 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
UCB0IE |= UCTXIE; // Enable TX interrupt
UCB0IE |= UCNACKIE;
UCB0IE |= UCRXIE;

UCB0CTL1 |= UCTXSTT;


__bis_SR_register(LPM0_bits + GIE);
}
}
}
//------------------------------------------------------------------------------
// The USCIAB0_ISR is structured such that it can be used to transmit any
// number of bytes by pre-loading TXByteCtr with the byte count.
//------------------------------------------------------------------------------
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
switch(__even_in_range(UCB0IV,12))
{
case 0: break; // Vector 0: No interrupts
case 2: break; // Vector 2: ALIFG
case 4:
P3OUT |=LED7;
a=1;

__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0

break; // Vector 4: NACKIFG
case 6: break; // Vector 6: STTIFG
case 8:
break; // Vector 8: STPIFG
case 10:

for (i=0; i<2; i++)
{


if(i==0)
Temp= UCB0RXBUF<<8;
UCB0CTL1 |= UCTXSTP;
if(i==1)
Temp |= UCB0RXBUF;

}
while(UCB0CTL1 & UCTXSTP);
printf("Hello world %d", Temp);

__bic_SR_register_on_exit(LPM0_bits);

break; // Vector 10: RXIFG
case 12:
// Vector 12: TXIFG
if (TXByteCtr) // Check TX byte counter
{
UCB0TXBUF = TXData;
while(!(UCB0IFG&UCTXIFG)); // code stucks here 
TXByteCtr--;
P3OUT |=LED6;// Decrement TX byte counter
}
else
{

UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
b=1;

__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0


}
break;
default: break;
}
}

  • When mapping module functions to a different pin than the default (and why else should one bother to use the port mapping), then you’ll need to unmap them from their original locations too. At least if they are used as inputs, which is true for the SDA and SCL. Else the two pin s will be OR’d, which will likely result in the USCI never seeing a low level on these signals.

     Why do you wait inside the TX ISR for another TX interrupt? It’s a death sin to wait for a hardware event inside an ISR.
    However, best case, you should eventually see this bit set again, when the USCI is done sending the start byte and the slave has responded with an ACK.
    But if the slave didn’t respond, or the slave is holding the master, then this will never happen.

    So possible reasons are: the slave doesn’t answer because your slave address is wrong (it is 7 bit, without the R/W bit), or the bus is busy because the slave is holding SCL low (hold master) and won’t release it. In this case, the bus is stalled, and there is nothing you could do (except resetting the slave, e.g. by switching its supply off), but at least your code should detect this timeout and cope with it.
    In any case, remove this waiting loop from the ISR.

     Also, if nothing more is to be sent, don’t clear TXIFG (it has already been cleared by reading UCB0IV in the switch). Instead, set UCTXSTP, so the USCI will end the transaction and release the bus by generating a stop condition.

    BTW: when using the __even_in_range intrinsic, you either define a case statement for every possible case (you tell the compiler, which cases are possible, by the intrinsic parameters), or you have a default case for all cases you don’t want to handle. Having both is superfluous.

  • Dear Jens ,

               I didnt understand  about port maping,how can we unmap them.

    I have tried myself another code for sht25 via interrupt. When I place many breakpoints in my line of code then I am getting accurate temperature data from the sensor  without converting it into celsius but when i run the code without breakpoints then the sensor does not acknowledge and the code stucks in UCNACKLIFG. I am giving correct address and it is 7 bit address.Can you have a look on my code and can tell me where the problem lies.Waiting for your reply


    #include "msp430.h"
    #include <stdint.h>
    #include<string.h>
    #include <stdio.h>

    volatile int a=0;
    volatile int b=0;
    volatile unsigned char TXData;
    volatile unsigned char TXByteCtr;
    volatile unsigned char RXByteCtr;
    volatile uint16_t Temp;
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT


    P3DIR |= BIT6 +BIT7;
    P3OUT &= ~(BIT6 +BIT7);
    PMAPPWD = 0x02D52; // Get write-access to port mapping regs
    P1MAP3 = PM_UCB0SDA; 
    P1MAP1 = PM_UCB0SCL; 
    PMAPPWD = 0; // Lock port mapping registers

    P1SEL |= BIT1 + BIT3; 


    UCB0CTL1 |= UCSWRST; // Enable SW reset
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
    UCB0BR0 = 16; // fSCL = SMCLK/12 = ~100kHz
    UCB0BR1 = 0;


    UCB0I2CSA = 0x40; // Slave Address is 040h
    UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
    UCB0IE |= UCTXIE;
    UCB0IE |= UCRXIE;// Enable TX interrupt
    UCB0IE |= UCNACKIE;
    UCB0IE |= UCSTPIE ;
    UCB0IE |= UCSTTIE ;
    TXData = 0xF3; // Holds TX data

    while (1)
    {
    __delay_cycles(20000);
    TXByteCtr = 0x01; // Load TX byte counter
    RXByteCtr = 0x01;
    while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT;

    __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts

    __no_operation(); // Remain in LPM0 until all data

    loop:            // is TX'd
    if(a==1)
    {
    a=0;
    UCB0CTL1 |= UCTR +UCTXSTT; // I2C stop condition
    printf("%s","not acknowledgement interrupt outer");
    __bis_SR_register(LPM0_bits + GIE);

    if (UCB0STAT&UCBBUSY)
    goto loop;

    }

    if(b==1){
    b=0;

    UCB0CTL1 &=~UCTR;// Use SMCLK, keep SW reset

    UCB0CTL1 |= UCTXSTT;

    __bis_SR_register(LPM0_bits + GIE);
    }

    loop2:// is TX'd
    if(a==1)
    {
    a=0;
    UCB0CTL1 |= UCTXSTT; // I2C stop condition

    printf("%s","not acknowledgement interrupt outer");
    __bis_SR_register(LPM0_bits + GIE);

    if (UCB0STAT&UCBBUSY)
    goto loop2;

    }

    }
    }

    //------------------------------------------------------------------------------
    // The USCIAB0_ISR is structured such that it can be used to transmit any
    // number of bytes by pre-loading TXByteCtr with the byte count.
    //------------------------------------------------------------------------------
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    {
    switch(__even_in_range(UCB0IV,12))
    {
    case 0: break; // Vector 0: No interrupts
    case 2: break; // Vector 2: ALIFG
    case 4:
    P3OUT |=BIT7; 
    a=1; 
    printf("%s","not acknowledgement interrupt");
    __bic_SR_register_on_exit(LPM0_bits); //   My code hangs here when I dont use breakpoints and only bit 7 turns                                                                           on and does not print also "not acknowledgement interrupt"

    break;              // Vector 4: NACKIFG
    case 6:

    printf("%s","in start flag");
    __bic_SR_register_on_exit(LPM0_bits);
    break;             // Vector 6: STTIFG
    case 8:


    printf("%s","in stop flag");
    __bic_SR_register_on_exit(LPM0_bits);
    break;                    // Vector 8: STPIFG
    case 10:
    if (RXByteCtr)
    {
    RXByteCtr--;

    Temp= UCB0RXBUF<<8;
    UCB0CTL1 |= UCTXSTP;

    }
    else{

    Temp|= UCB0RXBUF;
    while(UCB0CTL1 & UCTXSTP);
    P3OUT |=BIT6;

    printf("Temp=%d", Temp);
    __bic_SR_register_on_exit(LPM0_bits);
    }
    break; // Vector 10: RXIFG
    case 12: // Vector 12: TXIFG
    if (TXByteCtr) // Check TX byte counter
    {

    UCB0TXBUF = TXData;
    TXByteCtr--;

    }
    else
    {

    UCB0CTL1 |= UCTXSTP;
    while (UCB0CTL1 & UCTXSTP);// I2C stop condition
    b=1;
    printf("%s","transmission finished");
    __bic_SR_register_on_exit(LPM0_bits);

    }
    break;
    default: break;


    }

    }

  • When a function is mapped to a port pin by default, and you map it to a different pin, it is mapped to both. In case of an output, this is no problem. But in case of an input, the two signals will be OR’d then. And since one is not active (always 1) the result will be always 1. You need to map PM_ANALOG to the original pin.

     When code runs with breakpoints but not without, then apparently at or around the location of the breakpoint, you don’t wait for an event (but since a breakpoint wastes a lot of time, the event will have happened when you continue).

     Probably, the sensor requires some time for a conversion, and in this time it is inaccessible (does not respond). So either you’ll get a ‘read’ signal form the sensor by GPIO (many sensors provide such a signal), or you keep retrying on a NACK until it works (of course on the very first communication, you should not eternally retry but consider that the sensor might be really not there)

     You can’t use printf inside the ISR. Best case it takes a lot of time, but worst case, it locks because it needs interrupts by itself (especially if sending through UART rather than the debug console).

     BTW: don’t use goto. It’s ugly at best and a cause of trouble in worst case.
    rather do something like this:

    while(1){
      if (!looping) break;
    }

  • Dear Jens,

                  Thanks for your very informative reply.But I want to ask you more about port mapping.In cc430f5137 SDA  and SCL are assigned to P1.3 and P1.2 respectively as shown below.

    P1.3/PM_UCB0SIMO/PM_UCB0SDA/S21 

    P1.2/PM_UCB0SOMI/PM_UCB0SCL/S20

    Now if I write P1SEL |= BIT2 + BIT3; 

    Does it mean that I can use PM_UCBOSDA and PM_UCBOSCL on pins P1.3 and P1.2 without port mapping.If yes then on the same pins we have also PM_UCB0SIMO and PM_UCB0SOMI how the compiler will differentiate I want to use whether I2c pins or SPI pins because I have simply written P1SEL |= BIT3 + BIT2;

    and my second question if I want to portmap both PM_UCBOSDA and PM_UCBOSCL onto pins P1.0 and P1.1 respectively so is this the correct code mentioned below
    __disable_interrupt(); // Disable Interrupts
    PMAPKEYID = 0x02D52; // Enable Write-access
    #ifdef PORT_MAP_RECFG
    PMAPCTL = PMAPRECFG; // Allow reconfiguration
    #endif

    P1MAP0 = PM_UCB0SDA;
    P1MAP1 = PM_UCB0SCL;

    PMAPKEYID = 0; // Disable Write-Access
    #ifdef PORT_MAP_EINT
    __enable_interrupt(); // Re-enable all interrupts
    #endif
    P1SEL |= BIT1 + BIT0;
    or I have to map PM_ANALOG on both pins P1.3 and P1.2 before and then mapping PM_UCBOSDA and PM_UCBOSCL onto pins P1.0 and P1.1.
    Waiting for your reply

  • PM_UCB0SIMO and PM_UCB0SDA are aliases of the same mapping value. Which one is actually used, depends on the USCIB0 configuration. It could be as well named ‘USCIB0 signal line #1’ but I guess nobody would consider this convenient.
    PxSEL only switches from GPIO to module signal (whatever ‘module signal’ means).

    And yes, since PM_UCB0SDA is the default setting, you can use it without using the port mapping controller.

    Note that S21 is an independent thing. Here the LCD controller switches the pin between analog (LCD) signal and digital signal. Which has precedence, because the port mapping only determines, which digital signal to use.

     About your second question: it is unimportant in which order you map the signal to new pin and unmap it from the old one, but you (usually) need to do it. You can map one signal to (or from) all available pins at the same time. If output, then the signal will appear on all these port pins. If input, the module will read an OR’d signal from all pins. So. if one of all of them is high, the module will read high, if all are low, the module will read low. This might be convenient if you want to capture the moment in which any one of several signals goes high by a single timer capture input.
    But in most cases, it won’t be what you want, so assign PM_ANALOG to the default pin, before or after you map the function to another pin, but before you use the function.

  • Dear Jens,

                 So is this the right way when I want to do port mapping of PM_UCB0SDA and PM_UCB0SCL to pins P1.1 and P1.0 respectively when their default mapping is P1.3 and P1.2 in cc43f5137.

    _disable_interrupt(); // Disable Interrupts before altering Port Mapping registers
    PMAPKEYID = 0x02D52; // Enable Write-access to modify port mapping registers

    #ifdef PORT_MAP_RECFG
    PMAPCTL = PMAPRECFG; // Allow reconfiguration during runtime
    #endif

    P1MAP1 = PM_UCB0SDA;

    P1MAP0 = PM_UCB0SCL;

    P1MAP3=PM_ANALOG;

    P1MAP2=PM_ANALOG;


    PMAPKEYID = 0; // Disable Write-Access to modify port mapping registers
    #ifdef PORT_MAP_EINT
    __enable_interrupt(); // Re-enable all interrupts
    #endif
    P1SEL |= BIT1 + BIT0;

    Thanks

  • Yes, this should do.
    In case of signals that are plain output, mapping the original to PM_ANALOG isn’t necessary (then you have the output on more than one pin), but the USCI signals are both directions.

  • Thanks a lot for your precious reply .

    Regards,

    Faisal Khan

**Attention** This is a public forum