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.

MSP430F5529 : UART problem

UART send same character continuously though i sent it only once. my following program run correctly in debug mode but once i came out of debug mode controller send that character continuously. please suggest me suitable changes in following code.  

#include <msp430.h>
#include <stdio.h>

/*
* main.c
*/

volatile unsigned char transmit;

void UART_send_data(unsigned char character) {

transmit = character;
UCA0IE |= UCTXIE;
UCA0IFG |= UCTXIFG;

}

}

int main(void) {

WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer

P3SEL = BIT3+BIT4; // P3.4,5 = USCI_A0 TXD/RXD

UCA0CTL1 |= UCSWRST; // Put state machine in reset

UCA0CTL1 |= UCSSEL_2; // SMCLK

UCA0BR0 = 6; // 1MHz 9600 

UCA0BR1 = 0; // 1MHz 9600

UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16; // Modln UCBRSx=0, UCBRFx=0,

UCA0CTL1 &= ~UCSWRST; // Initialize USCI state machine

__enable_interrupt();

UART_send_data(0x55);

while(1);

}


#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(UCA0IV,4))
{
case 0:break; // Vector 0 - no interrupt

case 2: break;

case 4: // Vector 4 - TXIFG

UCA0TXBUF = transmit;
UCA0IFG &= ~UCTXIFG;
break;


default: break;
}
}

  • I suggest it is because you are writing

    UCA0TXBUF = transmit;
    UCA0IFG &= ~UCTXIFG;

    Maybe the flag isn't set immediately, so the second line doesn't have any effect. The flag is set afterwards. The ISR is called over and over again, sending the byte stored in transmit.

    Instead you could clear the interrupt capability for it

    UCA0IE &= ~UCTXIE;

    Dennis

  • thank you Dennis but as soon as i terminate my Debug session MCU sent some garbage bytes and my code working properly in debug session only.
  • problem has been solved by just adding delay after clock setting statements(code)
  • It's a common mistake to think that hitting a breakpoint in the debugger wills top the world turning.
    It is only the CPU which stops executing the code. But crystal continue to oscillate, data continues to come in, and even unrelated peripherals like the ADC continue to do their job.

    However, the original code did have other flaws. When SWRST is cleared, TXIFG is instantly set (as TXBUF is clear).
    In UART_send_data. TXIE is set, which instantly causes the ISR to be called. The ISR writes to TXBUF, which clears TXIFG. It then clears TXIFG (which in normal execution mode would still be clear anyway, but when single stepping, might be set once again as TXBUF has finished sending while the CPU was stopped by the debugger)) Now the ISR it returns. Either TXIFG is set again in the meantime, in which case the ISR is entered again instantly, or send function continues and sets TXIFG manually, which also causes the ISR to be called, whether the last byte in TXBUF was sent or not.

    As Dennis suggested, don't touch TXIFG manually. Enable TXIE when there is something to send and disable it in the ISR when the ISR detects that there is nothing more to send.
  • Jens,

    do you think, clearing TXIFG manually is a bad thing in general? I do this, too. An example:

    void start_sending_array_data( const uint8_t * array_pointer )
    {
      byte_counter = 1;                // First byte is sent from here
      UART_CLEAR_TX_IFG;               // Clear pending TX interrupt flag
      UART_ENABLE_TX_IR;               // Enable TX interrupts
      UART_TX_BUFFER = *array_pointer; // Send first byte
    }

    Since TXIFG is set after startup, I have to clear it manually before enabling the interrupts.

    Dennis

  • In this case, TXIFG is set because the TX buffer is ready for the next (i.e., first) byte. Instead of writing the first byte to UART_TX_BUFFER manually, you could just let the interrupt handler do this.
  • Yes, that is a possibility, too, of course. You're right.
    But is there any reason not to clear it manually?

    Dennis
  • It is not specified whether manually setting an IFG bit will trigger a DMA transfer.
    Especially during I2C, manually celaring and setting the IFG bit has a different effect on the state machine than doing so implicitly by reading RXBUF or writing to TXBUF (clock stretching) etc.
    In some cases, the IFG bits (or other status bits) are not writable. You can clear them, but you can't set them.
    In general, IFG bits are status info. manually changing them doesn't change the status, but changes the hardware-provided information about its internal state. Somewhat like the don't panic glasses in the hitchhikers guide.

    BTW: In your code above, you could have also skipped clearing TXIFG by writing to TXBUF before setting TXIE (while still starting with a manually written byte)
    And to synchronize with LPM entry, clear GIE, set the IE bits, then enter LPM with setting GIE. Ensures the interrupt is not called before you have entered LPM (leaving you stuck waiting for the already happened interrupt).

    It's more a generic design rule than USCI specific. As usual, rules can be bend, but you should have a really good reason. And properly document what you did and why :)
  • Hi Jens,

    yes, you're absolutely right. Manually clearing the IFG isn't necessary when writing to the TX buffer before enabling IE for it.
    It is just a habit to write to the transmit buffer as the last performed action.

    Dennis
  • thanx dennis and jens for your suggestions. i hope above suggestions will help me in near future and others too.

**Attention** This is a public forum