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.

MSP430G2xx3 launchpad UART baud rate @ 9600

 Hi,

Can anyone help me in setting baud rate on BRCLK Frequency = 1,048,576 (1.05Mhz) on launchpad MSP430G2xx3 board?  I modified TI example code to include changes for 1.05 Mhz clock but I don't see any change when analyzed through oscilloscope, basically signal width remains same between 1Mhz to 1.05 Mhz.. i.e., 104us.

Modified TI example code.

#include <msp430.h>

#define BAUDRATE   9600



//------------------------------------------------------------------------------
// Hardware-related definitions
//------------------------------------------------------------------------------
#define UART_TXD   0x02                     // TXD on P1.1 (Timer0_A.OUT0)
#define UART_RXD   0x04                     // RXD on P1.2 (Timer0_A.CCI1A)

//------------------------------------------------------------------------------
// Conditions for BAUDRATE Baud SW UART, SMCLK = 1MHz
//------------------------------------------------------------------------------


#define UART_TBIT_DIV_2     (1000000 / (BAUDRATE * 2))
#define UART_TBIT           (1000000 / BAUDRATE)

//------------------------------------------------------------------------------
// Global variables used for full-duplex UART communication
//------------------------------------------------------------------------------
unsigned int txData;                        // UART internal variable for TX
unsigned char rxBuffer;                     // Received UART character

//------------------------------------------------------------------------------
// Function prototypes
//------------------------------------------------------------------------------
void TimerA_UART_init(void);
void TimerA_UART_tx(unsigned char byte);
void TimerA_UART_print(char *string);

int k = 0;

//------------------------------------------------------------------------------
// main()
//------------------------------------------------------------------------------
int main(void)
{
    WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer
    if (CALBC1_1MHZ==0xFF)                    // If calibration constant erased
    {
      while(1);                               // do not load, trap CPU!!
    }

    DCOCTL = 0;                             // Select lowest DCOx and MODx settings
    BCSCTL1 = CALBC1_1MHZ;                  // Set DCOCLK to 1MHz
    DCOCTL = CALDCO_1MHZ;

    UCA0CTL1 |= UCSSEL_2;                     // SMCLK
    UCA0BR0 = 109;                            // 1.05MHz 9600
    UCA0BR1 = 0;                              // 1.05MHz 9600
    UCA0MCTL = UCBRS0;                        // Modulation UCBRSx = 1
    UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**

    P1OUT = 0x00;                           // Initialize all GPIO
    P1SEL = UART_TXD + UART_RXD;            // Timer function for TXD/RXD pins
    P1DIR = 0xFF & ~UART_RXD;               // Set all pins but RXD to output
    P2OUT = 0x00;
    P2SEL = 0x00;
    P2DIR = 0xFF;



    __enable_interrupt();

      TimerA_UART_init();                     // Start Timer_A UART
  //  TimerA_UART_print("Hello Krishna\r\n");
  //  TimerA_UART_print("How are you ?.\r\n");

    for (;;)
    {
        // Wait for incoming character
     //   __bis_SR_register(LPM0_bits);

        // Echo received character
          TimerA_UART_tx('U');

          for(k = 0; k<100; k++);

     }
       // TimerA_UART_tx(0x0f);

}
//------------------------------------------------------------------------------
// Function configures Timer_A for full-duplex UART operation
//------------------------------------------------------------------------------
void TimerA_UART_init(void)
{
    TACCTL0 = OUT;                          // Set TXD Idle as Mark = '1'
    TACCTL1 = SCS + CM1 + CAP + CCIE;       // Sync, Neg Edge, Capture, Int
    TACTL = TASSEL_2 + MC_2;                // SMCLK, start in continuous mode
}
//------------------------------------------------------------------------------
// Outputs one byte using the Timer_A UART
//------------------------------------------------------------------------------
void TimerA_UART_tx(unsigned char byte)
{
    while (TACCTL0 & CCIE);                 // Ensure last char got TX'd
    TACCR0 = TAR;                           // Current state of TA counter
    TACCR0 += UART_TBIT;                    // One bit time till first bit
    TACCTL0 = OUTMOD0 + CCIE;               // Set TXD on EQU0, Int
    txData = byte;                          // Load global variable
    txData |= 0x100;                        // Add mark stop bit to TXData
    txData <<= 1;                           // Add space start bit
}

//------------------------------------------------------------------------------
// Prints a string over using the Timer_A UART
//------------------------------------------------------------------------------
void TimerA_UART_print(char *string)
{
    while (*string) {
        TimerA_UART_tx(*string++);
    }
}
//------------------------------------------------------------------------------
// Timer_A UART - Transmit Interrupt Handler
//------------------------------------------------------------------------------
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
    static unsigned char txBitCnt = 10;

    TACCR0 += UART_TBIT;                    // Add Offset to CCRx
    if (txBitCnt == 0) {                    // All bits TXed?
        TACCTL0 &= ~CCIE;                   // All bits TXed, disable interrupt
        txBitCnt = 10;                      // Re-load bit counter
    }
    else {
        if (txData & 0x01) {
          TACCTL0 &= ~OUTMOD2;              // TX Mark '1'
        }
        else {
          TACCTL0 |= OUTMOD2;               // TX Space '0'
        }
        txData >>= 1;
        txBitCnt--;
    }
}
//------------------------------------------------------------------------------
// Timer_A UART - Receive Interrupt Handler
//------------------------------------------------------------------------------
#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A1_ISR(void)
{
    static unsigned char rxBitCnt = 8;
    static unsigned char rxData = 0;

    switch (__even_in_range(TA0IV, TA0IV_TAIFG)) { // Use calculated branching
        case TA0IV_TACCR1:                        // TACCR1 CCIFG - UART RX
            TACCR1 += UART_TBIT;                 // Add Offset to CCRx
            if (TACCTL1 & CAP) {                 // Capture mode = start bit edge
                TACCTL1 &= ~CAP;                 // Switch capture to compare mode
                TACCR1 += UART_TBIT_DIV_2;       // Point CCRx to middle of D0
            }
            else {
                rxData >>= 1;
                if (TACCTL1 & SCCI) {            // Get bit waiting in receive latch
                    rxData |= 0x80;
                }
                rxBitCnt--;
                if (rxBitCnt == 0) {             // All bits RXed?
                    rxBuffer = rxData;           // Store in global variable
                    rxBitCnt = 8;                // Re-load bit counter
                    TACCTL1 |= CAP;              // Switch compare to capture mode
                    __bic_SR_register_on_exit(LPM0_bits);  // Clear LPM0 bits from 0(SR)
                }
            }
            break;
    }
}
//------------------------------------------------------------------------------

  • Hello Raj,

    From first glance, it appears that you're missing the P1SEL2.     Since you're using the UART TX and RX you need to make sure you're using P1SEL and P1SEL2:

    P1SEL = UART_TXD + UART_RXD;

    P1SEL2 = UART_TXD + UART_RXD;

    I hope this helps.

    Regards,

    S.

  • Hi,

    Adding P1SEL2 = UART_TXD + UART_RXD; stopped communication to UART.

    How can we select 9600 baud rate at 1.05 Mhz clock?

  • I think the problem is I haven't set system clock to 1.05Mhz , i.e.,

       BCSCTL1 = CALBC1_1MHZ;                  
       DCOCTL = CALDCO_1MHZ;

    How to manually calibrate and use BCSCTL1 & DCOCTL  registers to 1.05 Mhz?

  • Raj,

    Based off the setting you had initally, you had P.1 and P.2 configured as capture/compare pins:

     

    I missed one other thing; you also need to modify the UCBRSx bits in the UCAxMCTL register.   You currently have it set to 0 which would explain why you're not receiving anything from the UART.   In order to receive the modulation scheme to get 1.05 MHz @ 9600 bauds from the UART, you will need to change this value what listed in the table you attached (2):

    UCA0CTL1 |= UCSSEL_2;                     // SMCLK
    UCA0BR0 = 109;                            // 1.05MHz 9600
    UCA0BR1 = 0;                              // 1.05MHz 9600
    UCA0MCTL = UCBRS2;                        // Modulation UCBRSx = 1
    UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**



    Regards,

    S.A.

  • Raj P said:
    Adding P1SEL2 = UART_TXD + UART_RXD; stopped communication to UART.

    No, it stopped the communicaiton with the timer. Because the code you posted is using the timer to do a software UART. It doesn't use the hardware UART (USCI) at all.

  • Jens,

    What is difference between timer based UART and hardware UART? I believed timer based UART still uses hardware UART functionality for Rx & Tx functionality. Please correct me if I am wrong.

  • Thanks for detailed reply, I made changes to two definitions in source code ..

    #define UART_TBIT_DIV_2     (1048576/ (BAUDRATE * 2))
    #define UART_TBIT           (1048576/ BAUDRATE)

    I get data on serial port but I see some sort of noise at regular intervals. Is there any mistake?


  • Raj P said:
    I believed timer based UART still uses hardware UART functionality

    No. It uses a timer to generate the individual bits by digital I/O. In case of the MSP, the tiemr can directly generate an output signal change when the time is up, which supports the software and adds some precision. However, it works without hardware UART (and was designed for the G2xx family members which only have an USI module without UART capability).
    The G2xx software UART also has RX and TX flipped compared to the 2553 hardware USCI UART. You'll have to set the RX and TX jumpers accordingly (see LaunchPad documentation)
    Note that even with hardware UART, the maximum baudrate that can be used for the LaunchPad application UART (serial over USB) is 9600Bd. The USCI in the 2553 supports much more, but to use it, you'll need a separate USB/ser converter then.

  • Thanks Jeans.

    The last question I had was about DCO clock settings, on launchpad boards the maximum frequency that could be set is 1 Mhz  (CALBC1_1MHZ) , I need to operate my UART at 1.05 Mhz baud rate , does this mean even DCO should be set for 1.05Mhz? or DCO can still run at 1 Mhz but UART can be configured to run at 1.05Mhz irrespective of DCO clock frequency? 

    I am asking this since I don't see any document which describes how to set DCO clock frequecy above 1 Mhz.

    Appreciate your feedback.

  • Raj P said:
    the maximum frequency that could be set is 1 Mhz  (CALBC1_1MHZ)

    No. Teh DCO can be programmed to, well, depends on MSP but for all but 1x family, the limit is far above the maximum CPU frequency.

    It's just that a certain bit combination in the DCO registers results in different output frequencies on each individual MSP. So CALBC1_1MHz is a factory-provided value that sets the DCO registers to a value that results in 1MHz (as close as possible) on this specific MSP. The calue of CALBC1_1MHZ is different for each MSP. It is nto a constant, but points to a memory location (INFOA) where this value was stored at prduction time. Some MSPs also carry this informaiton for 2,4,8, 12 or 16MHz. See the datasheet for available values.

    If you want to use a different frequency, you need to calibrate it on your own. You can simply use try and error (try different values and output SMCLK to a port pin and check it) or you put a self-calibraiton function into your code that compares the current DCO frequeency to a known reference, such as a 32768Hz crystal. Sample code was posted somewhere in the forum.
    On 4x and 5x/6x family, this feature is available in hardware. On 5x/6x family, you don't even need an external crystal if the precision of the internal REFO is good for you.

    Raj P said:
    I am asking this since I don't see any document which describes how to set DCO clock frequecy above 1 Mhz.

    The users guide tells you how the DCO registers work and the datasheet contains a table telling you the frequency range of different DCO configurations.

  • Thanks Jens.

    Your feedback was very useful in resolving this issue.

**Attention** This is a public forum