0
\$\begingroup\$

I'm trying to learn how to use UART on a MSP430G2553 and I wrote this simple program. The program should set up a timer interrupt to happen once a second. The interrupt service routine should toggle a LED, send a count value to my laptop using UART, and increment the counter. My SMCLK is set to 125 kHz, so I set UCOS16 to 1 to use oversampling, UCBR1 to a prescalar of 1, and UCBRF1 to a modulation value of 10 for a baud rate of 4800. Below is my code:

#include <msp430.h> 

volatile unsigned int count = 0; //global variable to increment every timer interrupt and send through UART - must be volatile because ISR can change it at any time

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer

    //set clock to 1 MHz and to use DCO
    DCOCTL = DCO1 + DCO0;
    BCSCTL1 = RSEL0 + RSEL1 + RSEL2;//7;
    BCSCTL2 = DIVS0 + DIVS1; //SMCLK = MCLK / 8, everything else 0 so it uses DCO as source

    //UART settings
    UCA0CTL1 = UCSSEL1 + UCSWRST; //set SMCLK as source and put UCA0 in reset state
    UCA0CTL0 = 0; //parity disabled, LSB first, 8 bit data, UART mode
    UCA0BR0 = 1; //want prescalar of 1 - prescalar of 1, modulation of 10 and SMCLK of 125 kHz should result in baud rate of 4800
    UCA0BR1 = 0; //want prescalar of 1
    UCA0MCTL = UCBRF_10 + UCOS16; //modulation of 10 and oversampling enabled
    UCA0CTL1 &= ~UCSWRST; //take UCA0 out of reset state

    //timer settings
    TA0CTL = TASSEL1 + ID1 + ID0 + MC1 + TACLR; //set SMCLK as source, divide source by 8, set to continuous mode, enable interrupts
    TA0CCTL1 &= ~CAP; //set CAP to 0 for compare mode
    TA0CCTL1 |= CCIE; //enable interrupts

    TA0CCR1 = 15625; //1usec * 8 * 8 * 15625 should give an interrupt once a second

    //set pin 1 for output
    P1DIR = BIT0;

    //enable interrupts globally
    _EINT();
    LPM0;
}

#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A (void) {
    TA0CCR1 += 15625; //reset counter
    TA0CCTL1 &= ~CCIFG; //clear flag
    P1OUT ^= BIT0; //toggle LED

    //wait for USCI to be inactive
    while((UCA0STAT & UCBUSY) == 1) {

    };

    UCA0TXBUF = count; //send current count value via UART
    count++; //increment count
}

I can tell the timer interrupt is working because the LED is blinking once a second. However, when I set up PUTTY to try to watch the count value increase every second, no characters or values ever show up. I've tried sending chars and ints that don't change instead of the count value, but that doesn't seem to help. I've also set a breakpoint in the timer interrupt service routine and I'm able to step through it, but nothing shows up on PUTTY. Does anyone know what might be going on?

\$\endgroup\$
10
  • \$\begingroup\$ you need to set the pin into UART mode. \$\endgroup\$ Commented Oct 10, 2021 at 6:24
  • \$\begingroup\$ @Jasen I tried adding 'P1DIR = BIT0 + BIT2; //set P1.0 for output for LED and P1.2 for output for UART Tx P1SEL = BIT1 + BIT2; //Set P1.1 and P1.2 for UART P1SEL2 = BIT1 + BIT2; //Set P1.1 and P1.2 for UART' before the line 'UCA0CTL1 &= ~UCSWRST; //take UCA0 out of reset state' but it still doesn't work. \$\endgroup\$
    – dman
    Commented Oct 10, 2021 at 9:31
  • \$\begingroup\$ @dman I don't want to bother reading your code and refreshing my memory via the TI manuals until I better understand what you are doing. I use PuTTY myself on a PC. But it is usually being used with virtual COM ports over a USB connection mediated by other ICs. Not real COM ports. You mention an MCU but not a board design. So I need to know exactly what is connected and how it is connected up. Are you using virtual COM ports? Or a real serial port using RS-232 signaling? Convince me. \$\endgroup\$
    – jonk
    Commented Oct 10, 2021 at 9:39
  • \$\begingroup\$ Check that the uart port is toggling, send "UUUUU" repeatedly and measure the frequency of the signal (should be half baud rate) \$\endgroup\$ Commented Oct 10, 2021 at 10:13
  • \$\begingroup\$ @jonk I'm using a USB COM port on my computer to try receiving the signal, and the LaunchPad's backchannel UART to send it, so the signal is traveling over the same USB cable that Code Composer Studio uses to program and debug the board. I have the jumpers on the LaunchPad set to use software UART. The backchannel UART shows up as a separate COM port in the computer's Device Manager, and that is the COM port I am setting up PuTTY for. \$\endgroup\$
    – dman
    Commented Oct 11, 2021 at 9:45

1 Answer 1

1
\$\begingroup\$

There were multiple problems. As pointed out by @Jasen, the Tx and Rx pins needed to be set to UART mode. Also, as pointed out by @jonk the LaunchPad's backchannel UART and virtual COM port on a computer don't work well together so I had to use the actual Tx and Rx pins. Also, when UCBRx is set to 0 or 1 the prescalar and modulator stages are bypassed so the baud rate was off. I changed the clock, timer and UART settings so the SMCLK is 500 kHz and the UART's baud rate is 9600. I also saw a lot of errors in the data transmitted over UART so I started using odd parity and two stop bits. Below is working code.

#include <msp430.h> 

volatile unsigned int count = 0; //global variable to increment every timer interrupt and send through UART - must be volatile because ISR can change it at any time

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer

    //set clock to 1 MHz and to use DCO
    DCOCTL = DCO1 + DCO0;
    BCSCTL1 = RSEL0 + RSEL1 + RSEL2;//7;
    BCSCTL2 = DIVS0; //SMCLK = MCLK/2, everything else 0 so it uses DCO as source

    //UART settings
    UCA0CTL1 = UCSSEL1 + UCSWRST; //set SMCLK as source and put UCA0 in reset state
    UCA0CTL0 = UCPEN + UCSPB; //0; //parity disabled, LSB first, 8 bit data, UART mode
    UCA0BR0 = 3;//1; //want prescalar of 3, modulation of 4 and SMCLK of 500 kHz should result in baud rate of 9600
    UCA0BR1 = 0; //want prescalar of 3
    UCA0MCTL = UCBRF_4 + UCOS16; //modulation of 4 and oversampling enabled

    //timer settings
    TA0CTL = TASSEL1 + ID1 + ID0 + MC1 + TACLR; //set SMCLK as source, divide source by 8, set to continuous mode, enable interrupts
    TA0CCTL1 &= ~CAP; //set CAP to 0 for compare mode
    TA0CCTL1 |= CCIE; //enable interrupts

    TA0CCR1 = 62500;//1usec * 2 * 8 * 62500 should give interrupt once a second

    //set pin 1 for output
    P1DIR = BIT0 + BIT2; //set P1.0 for output for LED and P1.2 for output for UART Tx
    P1SEL = BIT1 + BIT2; //Set P1.1 and P1.2 for UART
    P1SEL2 = BIT1 + BIT2; //Set P1.1 and P1.2 for UART

    UCA0CTL1 &= ~UCSWRST; //take UCA0 out of reset state

    //enable interrupts globally
    _EINT();
    LPM0;
}

#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A (void) {

    TA0CCR1 += 62500; //reset counter
    TA0CCTL1 &= ~CCIFG; //clear flag
    P1OUT ^= BIT0; //toggle LED

    //wait for USCI to be inactive
    while((UCA0STAT & UCBUSY) == 1) {
    };

    UCA0TXBUF = count; //send current count value via UART
    count++; //increment count
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.