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.

Strange behavior using UART and TimerA

Other Parts Discussed in Thread: MSP430F149, MSP430F169

In the code posted below Timer A is running at 4000 Hz and its interrupt writes a global byte variable "dirBits" to port 1 each time it's called. The line "IE1 |= URXIE0" is commented out in the function that sets up the UART b/c I don't want to use an interrupt to communicate with the user.  The user can hit 'h' which sets stepBits to 0xFF or any other character which will set stepBits to 0x0. The routine echoes a few characters to verify input is being received. It does receive the characters and echos as expected but stepBits never gets set.  Port2 does show the 4000 Hz train as expected.  It doesn't work. But if I uncomment the 'IE1 |= URXIE0' and put the code that is currently in the main loop into an interrupt for RX it works fine.  What's going on here?????? I don't understand how the charcters can be recieved and stepBits is not set.  Any help would be appreciated. I am using IAR C++ 5.10.1 and have this problem on both a MSP430F149 and MSP430F169.


#include  <msp430x14x.h>
void Setup_115200_UART0(void);
void Start_TimerA_4000Hz(void);
void WriteChar(unsigned char ch);

unsigned char stepBits = 0x0;
char ch;

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // Stop WDT
  Setup_115200_UART0();
   
  P1DIR = 0xFF;
  P1OUT = 0x00;
  P2DIR = 0xFF;
  P2OUT = 0x00; 
  Start_TimerA_4000Hz();
      
  _BIS_SR(GIE); // Enable interrupts
 
  while(1)
  {

    // wait for a character to be ready
    while(!(IFG1 & URXIFG0)) {}
    {
      ch = RXBUF0;
      if(ch == 'h')
      {
        stepBits = 0xFF;
        WriteChar(ch);
      }
      else
      {
        stepBits = 0x0;
        WriteChar('#');
        WriteChar(ch);
      }
    }
  }
}
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
 
  P1OUT = stepBits;
  P2OUT = 0xFF;
  _BIS_SR(GIE);// Interrupts are always on. Just a delay.
  _BIS_SR(GIE);
  P1OUT = 0x0;
  P2OUT = 0x0;
}

// Starts timerA at 4000 Hz.  Count up mode so it generates
// a timer A interrupt every time it counts from 0 to CCR0 (2000 in this
//case)
// Similar to example fet140_ta_11.c except changed to source from SMCLK
void Start_TimerA_4000Hz(void)
{
 
  CCTL0 = CCIE;                        // CCR0 interrupt enabled
  CCR0 = 2000-1;                       // Using 8 MHz crystal
  TACTL = TASSEL_2+ MC_1;              // SMCLK, upmode
 
}

// Sets UART0 up for serial communication at 115200 bps.  8 MHz clock
// is installed in XT2.  It also sets MCLK=SMCLK=XT2 once it's verified
// the clock is stable.  Similar to example fet140_uart01_115k.c
void Setup_115200_UART0(void)
{
  int i;
  P3SEL |= 0x30;                            // P3.4,5 = USART0 TXD/RXD
  BCSCTL1 &= ~XT2OFF;                       // XT2on
 
  // Crystals take a little time to stabilize, so wait it out.
  do
  {
    IFG1 &= ~OFIFG;                           // Clear OSCFault flag
    for (i = 0xFF; i > 0; i--);               // Time for flag to set
  }
  while ((IFG1 & OFIFG));                     // OSCFault flag still set?

  BCSCTL2 |= SELM_2 + SELS;                   // MCLK= SMCLK= XT2 (safe)
                                             /////Changedfrom Example////
 
  ME1 |= UTXE0+ URXE0;                        // Enable USART0 TXD/RXD
  UCTL0|= CHAR;                               // 8-bit character
  UTCTL0|= SSEL1;                          // UCLK = SMCLK
  UBR00 = 0x45;                               // 8Mhz/115200 - 69.44
  UBR10 = 0x00;                            
  UMCTL0 &= 0x4A;                         // modulation
  UCTL0 &= ~SWRST;                       // Initialize USART state machine
 // IE1 |= URXIE0;     
}
void WriteChar(unsigned char ch)
{
  while(!(IFG1 & UTXIFG0)){};
  TXBUF0 = ch;
}

 

  • MarkH said:
      _BIS_SR(GIE);// Interrupts are always on. Just a delay.

    No. You're in an ISR. Interrupts are OFF in an ISR (unless you manually enable them again) so no ISR can interrupt the curren tone. And mor eimportant the ISR cannot be interrupted by its own interrupt source - many interrupt sources are persistent until the ISR has handled the cause of the interrupt, such as reading from the RXBUF or writing to TXBUF. Manually enabling the interrupt sinside an ISR which the cause of the interrupt isn't handled will end up in an endless loop of calling the ISR and finally a stack overflow (since the ISR never returns because it is interrupted immediately by itself).

    If you need a delay, use __no_operation() instead. It has same length and execution time (2 bytes, one clock cycle) and it does what it is named after: nothing.

    MarkH said:
      while(!(IFG1 & URXIFG0)) {}
        {...  


    This looks as if the second code block would be executed in the while loop. It is misleading. Replace the {} behind the while by a ';' and things are more clear. It's not an error, just confusing.

    Alternatively, remove the '!' from the while AND the {} behind it. Since URXIFG0 is only set when unread data is in RXBUF, it will be cleared immediately when RXBUF is read. And since the whole block is inside a while(1), things will work fine. Instead of the while(IFG1&URXIFG0) and if() would do as well.

    MarkH said:
    do
      {
        IFG1 &= ~OFIFG;                           // Clear OSCFault flag
        for (i = 0xFF; i > 0; i--);               // Time for flag to set
      }
      while ((IFG1 & OFIFG));                     // OSCFault flag still set? 

    Al loop to 255 is by far not long enough to allow the OFIFG flag to be set again. That is, if the enpty and therefore meaningless FOR loop isn't optimized away at all. From the compilers view it is dead code with the only effect of setting i=0. Check the device datasheet how long it takes for the fault detection to come up again. On the 5438, it is between 100µs and 100ms (my old 1611 datasheet has no info). So chances are that your crystal is still not up when your loop exits as 'functioning'. Especially since the new MSPs start with a much higher frequency (16MHz default = 1600 cycles in 100µs) than the old 1x series (<1MHz default speed).

    About your stepBits variable: you only write to it and never read it. And it is not defined volatile. So the compiler detects that you're writing into the void and does not perform the write at all, as it is superfluous. Or the value is kept in a register and only written when necessary, which never is. If you're looking at it with the debugger, you'll never see a change in the memory location of stepBits. The compiler does not know that you're peeking into the memory outside of program and processor control.
    If you declare the variabel volatile, the compiler assumes that it may be used in an ISR or by hardware (such as DMA) and will always write to it - but only for global variables. Local variables may be still detected as superfluous if there is no reference of them given anywhere.

     

  • Thank you for your excellent answer.  Other than making me feel stupid for not seeing the obvious problem with the interrupt, you've solved all my problems.

  • MarkH said:
    you've solved all my problems.

    Then you're a lucky man :) No matter how many of my problems I solve, there's always still a big heap of unsolved ones.

**Attention** This is a public forum