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.

Newbie needs a hand...Variables-why doesn't this work.

Other Parts Discussed in Thread: MSP430FR5738

I'm transitioning from PIC to MSP430 and it is painful.

I'm trying to get some I2C code working (communication with a clock), and I think I am missing something fundamental about how variables work. I'm setting up some global variables at the beginning of the code, but the values seem to be ignored later on when I try to wirte to the I2C TX buffer.That is, I can get the I2C hardware to work properly (as monitored with an oscilloscope) when I fill the TX buffer directly (e.g. "UCB0TXBUF = 0xF3"), but using a variable (e.g. "UCB0TXBUF =  TXData[0]) fails to write the correct byte to the buffer. Could someone tell me why this doesn't work or what I should read that will make sense of this issue (Yes, I've done google and other searches ad nauseum). Should I be looking into pointers or volatiles (whatever those are?) Thanks for any help.

#include "msp430fr5738.h"

unsigned int TXData[]= {0xF5,0x00,0xE0,0x8F};// Pointer to TX data
unsigned char cntr = 0;
unsigned char TXByteCtr;

void main(void)

{
WDTCTL = WDTPW + WDTHOLD;
// Init SMCLK = MCLk = ACLK = 1MHz
CSCTL0_H = 0xA5;
CSCTL1 |= DCOFSEL0 + DCOFSEL1; // Set max. DCO setting = 8MHz
CSCTL2 = SELA_3 + SELS_3 + SELM_3; // set ACLK = MCLK = DCO
CSCTL3 = DIVA_3 + DIVS_3 + DIVM_3; // set all dividers to 1MHz

// Configure Pins for I2C
P1SEL1 |= BIT6 + BIT7; // Pin init

UCB0CTLW0 |= UCSWRST; // put eUSCI_B in reset state
UCB0CTLW0 |= UCMODE_3 + UCMST + UCSSEL_2;// I2C master mode, SMCLk
UCB0BRW = 0x8; // baudrate = SMCLK / 8
UCB0CTLW1 |= UCASTP_2; // generates an automatic stop condition after all bytes are sent
UCB0TBCNT = 0x04; // number of bytes to send
UCB0I2CSA = 0x68; // slave address
UCB0CTLW0 &=~ UCSWRST; //clear reset register
UCB0IE |= UCTXIE0 + UCNACKIE; //transmit and NACK interrupt enable


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


_bis_SR_register(GIE);
// __bis_SR_register(LPM0_bits + GIE) ; // LPM3 + Enable interrupt
// __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts

}


#pragma vector = USCI_B0_VECTOR
__interrupt void USCIB0_ISR(void)
{
switch(__even_in_range(UCB0IV,0x1E))
{
case 0x00: break; // Vector 0: No interrupts break;
case 0x02: break;
case 0x04:
UCB0CTLW0 |= UCTXSTT; //resend start if NACK
break; // Vector 4: NACKIFG break;
case 0x18:
UCB0TXBUF = TXData[cntr];
cntr++ ; //increment text counter
break; // Vector 26: TXIFG0 break;
default: break;
}
}

  • By the way, I can get it to work if I assign values to the variables inside the main. I just don't get why they don't work as globals.

  • Your main() quits after it enabled interrupt. The control of the CPU is turned over to the c-exit-code.Your ISR may not get any chance to work.

    You need to add a do-nothing-forever statement of your own at the end of main() so that your ISR can still work while main() is not doing anything but still has the CPU under its control.

    Which c-compile/link/execute are you using? The c-exit-code may be very different. It might have disabled interrupt to "protect" you.

  • Eli Bridge said:
    or volatiles (whatever those are?)

    Declaring a variable as volatile tells the compiler to not make any assumptions about its usage or state.
    Any variable that is accessed outside the normal program flow needs ot be declared volatile. If not, the compile rmay e.g. hold it in a processor register and do comparisons with this copy while an ISR magically and undetected changes the value of the variabel in ram. Or the compielr detects that you change a variable moultiple times inside a funtion without ever reading it. So it may discard the changes or delay the last one until the program flow leaves to a subfunciton or returns to the caller of the funciton. This reduces code size and increases speed, but of yourse won't work if an ISR interrupts the program flow and wants to read the current state of the variable.

    Interrupts are NOT part of the C language. Interrupt code forecfully and unpredictable breaks the compiled program flow and does something that was unknown at compile time. So you need to give the compiler a hint about where an access to a variable may have side-effects. (BTW: all MSP registers are declared as volatile variables).

    So whenever you use a variable in both, main code and interrupt code, it must be declared volatile.

    However, in your ISR, you send TXData[cntr] without chackign fo rany limit. So once the code works, you will start sending and sending the same 256 bytes ever and ever again.

    Also, after starting the transmission, your main code falls off of main. Where is it supposed ot return to? There is no OS to return to. And the transfer isn't done yet too. There is no definde default behaviour if you return from main. I tmay be that the MSP crashes or goes into deep sleep or resets or whatever,. It depends on the comiler specific C startup code.

    The commented code was setting hte XPU into LPM0, which means that execution of the main thread stops until an ISR reactivates it (which never happens in this ISR). If you doN't want this, you should add a while(1); at the end of main.

**Attention** This is a public forum