MSP430 LaunchPad Tutorial - Part 4 - UART Transmission

Enrico GaranteJuly 3, 201320 comments

Today we are going to learn how to communicate using UART with the Launchpad. For this purpose I will replace the default microcontroller that comes with the board with the MSP430G2553. It is the most powerful device in the MSP430 Value Line and it comes with an integrated hardware UART module, along with 16 Kb of Flash memory, 512 bytes of SRAM and an 8-channel, 10 bit ADC.

Quick Links

UART communication can be useful when dealing with sensors: as a basic example, we could send data taken from a temperature sensor with the internal ADC to a computer, using a cheap bluetooth module connected to the UART pins on the Launchpad.

This article is available in PDF format for easy printing

In this tutorial we will see a program that waits to receive a certain character from the UART port and then transmit a response to the other device. The communication happens in full-duplex at 115200 BPS, 8 bits of data with no parity and 1 stop bit.

Enough chatter, let's start with the tutorial already! The first statements will be familiar to you:

#include "msp430g2553.h"
#define TXLED BIT0
#define RXLED BIT6
#define TXD BIT2
#define RXD BIT1
const char string[] = { "Hello World\r\n" };
unsigned int i; //Counter 

As always, we include the header file for the microcontroller and then define some macros for better reading.
Then we declare an array of chars (a simple C string) that will store our response to the other terminal. At last we declare a counter variable that will help us later when sending the response.

int main(void)
{
   WDTCTL = WDTPW + WDTHOLD; // Stop WDT
   DCOCTL = 0; // Select lowest DCOx and MODx settings<
   BCSCTL1 = CALBC1_1MHZ; // Set DCO
   DCOCTL = CALDCO_1MHZ;

Here's the main routine: its the first line will disable the Watchdog timer. After that, we have three lines of code that will calibrate and set the internal oscillator at 1 MHz. 

This will be the master clock (SMCLK) used by the UART and all the other on-board peripherals.

   P2DIR = 0xFF; // All P2.x outputs<
   P2OUT &= 0x00; // All P2.x reset
   P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
   P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
   P1DIR |= RXLED + TXLED;
   P1OUT &= 0x00;

Now we set the input and outputs: with the first two lines we disable the PORT2 that comes on the G2553; it is always a good idea to disable the I/O pins that we don't use in order to reduce noise and current consumption.

Line 3 and 4 make sure that P1.1 and P1.2 are switched to the "special function" mode, that is UART mode for the G2553. In fact the P1SEL and P1SEL2 registers multiplex the PORT1 pins to various internal peripherals.
Unfortunately we can't select which pin to use as TXD or RXD, as you can read on the datasheet (page 43).
The last two lines simply set up the on-board LEDs.

   UCA0CTL1 |= UCSSEL_2; // SMCLK
   UCA0BR0 = 0x08; // 1MHz 115200
   UCA0BR1 = 0x00; // 1MHz 115200
   UCA0MCTL = UCBRS2 + UCBRS0; // Modulation UCBRSx = 5
   UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
   UC0IE |= UCA0RXIE; // Enable USCI_A0 RX interrupt

Here's the good stuff. With the first line we select the SMCLK as the clock source for the UART module, used to generate the desired baud rate (we can also select the external crystal ACLK with UCSSEL_1, provided that we initialized it).

UCA0BR0 and UCA0BR1 select the baud rate: in fact they store the integer divider for the SMCLK (1 MHz). In this case we have 1MHz/8= 125000, but actually we need 115200 and we will have some error that will accumulate over time.
For obvious reasons, we can't even select 9 because otherwise the baud rate will be under 115200 bps. But the UCA0MCTL register comes to help us.
This register in fact is in control of the "modulation": it will select the divider between 8 and 9, therefore switching baud rate during communication to contain the accumulated error.
With 8 as divider, we have 125000-115200=9600 (+8.5%) error. With 9, we have 115200-111111=4089 (-3.6%) error.
The modulator will work roughly like this:

First bit use /8, +8.5% off
Next bit use /9, -3.6% off, accumulated +4.9%
Next bit use /9, -3.6% off, accumulated 1.3%
Next bit use /9, -3.6% off, accumulated -2.3%
Next bit use /8, +8.5% off, accumulated 6.2%

and so on.


As you can see from the device user guide at page 424, there is a table that shows which dividers to use given a certain SMCLK frequency and a desired baud rate, with the expected minimum and maximum error rates for transmit and receive.
The modulation value of 5 has been taken as well from this table.

With the last to lines we enable the UART module and the interrupt for the "receive event", that we will analyze soon.

   __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ int until Byte RXed
   while (1)
   { }
}

The last lines of the main routine will put the microcontroller in a low-power mode and enable the global interrupt flag, as well as entering an infinite loop.

#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
   P1OUT |= RXLED;
   if (UCA0RXBUF == 'a') // 'u' received?
   {
      i = 0; 
      UC0IE |= UCA0TXIE; // Enable USCI_A0 TX interrupt
      UCA0TXBUF = string[i++];
   }
   P1OUT &= ~RXLED;
}

Here's the interrupt routine that will be executed when we receive something. If you have followed the tutorial series, its declaration should not be unknown to you, otherwise go back to the interrupts tutorial.
First we light up a led that will show us that we have received a byte. Then we read the UCA0RXBUF register that stores the received data.
If the byte stored is an "a" we reset the counter and enable the transmitter interrupt that will handle the sending of the response.
After that we load the UCA0TXBUF with the first character to send taken from our response string declared earlier. This register contains the data to send.
Finally we turn off the led.

#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{
   P1OUT |= TXLED;
   UCA0TXBUF = string[i++]; // TX next character
   if (i == sizeof string - 1) // TX over?
      UC0IE &= ~UCA0TXIE; // Disable USCI_A0 TX interrupt
   P1OUT &= ~TXLED;
}

]
Here's the transmitter interrupt routine. As we did before, we turn on a led that will tell us that we are transmitting something.
Then we load the next character to send in the buffer. If there are still characters to send in the response string, we will just turn off the led and wait for the end of transmission of the current byte .
When the character is sent by the UART module, the TX interrupt will happen again and the routine will be executed for the next character.
If we realize that we have reached the end of the response string array (using the sizeof statement that returns how many bytes we have in the array), we disable the TX interrupt and come back to the main cycle.

Here's the complete code for reference:

#include "msp430g2553.h"
 
#define TXLED BIT0
#define RXLED BIT6
#define TXD BIT2
#define RXD BIT1
 
const char string[] = { "Hello World\r\n" };
unsigned int i; //Counter
 
int main(void)
{
   WDTCTL = WDTPW + WDTHOLD; // Stop WDT
   DCOCTL = 0; // Select lowest DCOx and MODx settings
   BCSCTL1 = CALBC1_1MHZ; // Set DCO
   DCOCTL = CALDCO_1MHZ;
   P2DIR |= 0xFF; // All P2.x outputs
   P2OUT &= 0x00; // All P2.x reset
   P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
   P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
   P1DIR |= RXLED + TXLED;
   P1OUT &= 0x00;
   UCA0CTL1 |= UCSSEL_2; // SMCLK
   UCA0BR0 = 0x08; // 1MHz 115200
   UCA0BR1 = 0x00; // 1MHz 115200
   UCA0MCTL = UCBRS2 + UCBRS0; // Modulation UCBRSx = 5
   UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
   UC0IE |= UCA0RXIE; // Enable USCI_A0 RX interrupt
   __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ int until Byte RXed
   while (1)
   { }
}
 
#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{
   P1OUT |= TXLED; 
     UCA0TXBUF = string[i++]; // TX next character 
    if (i == sizeof string - 1) // TX over? 
       UC0IE &= ~UCA0TXIE; // Disable USCI_A0 TX interrupt 
    P1OUT &= ~TXLED; } 
  
#pragma vector=USCIAB0RX_VECTOR 
__interrupt void USCI0RX_ISR(void) 
{ 
   P1OUT |= RXLED; 
    if (UCA0RXBUF == 'a') // 'a' received?
    { 
       i = 0; 
       UC0IE |= UCA0TXIE; // Enable USCI_A0 TX interrupt 
      UCA0TXBUF = string[i++]; 
    } 
    P1OUT &= ~RXLED;
}

This is the last episode in our little journey with the Launchpad. I hope you have enjoyed it and that you have acquired valuable knowledge to work with the MSP430 microcontrollers.


Previous post by Enrico Garante:
   MSP430 LaunchPad Tutorial - Part 3 - ADC


Comments:

[ - ]
Comment by key-boardAugust 21, 2014
Hello
Thankyou for this nice Tutorial but i have one question.
I can not comprehend why you set "UCA0MCTL = UCBRS2 + UCBRS0; // Modulation UCBRSx = 5"
Ich I look into the Userguide in the table on site 424 and look at BRCLK 1000000 Baud Rate 115200, than i would set UCA0MCTL = UCBRS6. Ore i misunderstand you?
Thankyou for Help
[ - ]
Comment by Mark13June 4, 2015
UCBRS2 + UCBRS0=101=6
UCBRSx = 5 means six because first is zero
see 15.4.5
[ - ]
Comment by RobAllen10August 25, 2013
Thanks for writing this. The line by line commentary is very useful.
[ - ]
Comment by NiloldMay 29, 2015
Hi Enrico, thank you very much for your instructions!
I tried to use your code on my lounchpad, but I can't see any sign of data transmission with an oscilloscope on port 1.2. By debugging I certified that the line UCA0TXBUF = string[i++] is been called, and the TX buffer register do get the data. However nothing happens on the 1.2 port. Is there something else I should do to actually transmit the data? Thank you very much.
[ - ]
Comment by Raul35September 29, 2013
Hi Enrico, which are the conditions to the program works?, ie. with putty or hyperterminal, wath are your recommendations for testing? Greetings!
[ - ]
Comment by egaranteNovember 3, 2013
I've tested it with Putty using the Launchpad's internal COM to USB converter.
[ - ]
Comment by wygonski95November 6, 2013
Thanks for the example and the great explanation. It is necessary to change the J3 jumpers for TxD and RxD, right? Isn't the LaunchPad limited to 9600 baud?
[ - ]
Comment by egaranteNovember 30, 2013
Yes you have to put the jumpers on J3 in order to use the Lauchpad's USB COM port. This port is limited to 9600 bps, but you can use an external converter connected to the UART pins and go faster.
[ - ]
Comment by rohit30793November 10, 2013
what is the use of #pragma vector??
[ - ]
Comment by egaranteNovember 30, 2013
#pragma vector=XXX is a directive that tells the compiler that the XXX interrupt will be served by the following function.
Have a look at the interrupt tutorial!
[ - ]
Comment by carlos48December 14, 2013
thanks for the tutorial, will you know of any official guide to learn programming MSP430 in C?, Best regards
[ - ]
Comment by fabiomarinosciDecember 14, 2013
Hi Enrico, excellent works! Why don't you treat also I2c and SPI communication? I think they would be very useful. Regards.
[ - ]
Comment by nikitha62December 17, 2013
Hi Enrico, i have doubt as am working on msp430. how to get printed only receive buffer value only.
[ - ]
Comment by egaranteFebruary 15, 2014
If I've understood correctly, you want to echo back what you have just transmitted to the MSP430. To do so, just put UCA0TXBUF=UCA0RXBUF in the interrupt routine.
[ - ]
Comment by megha33March 18, 2014
hey !
your tutorial is awesome ! i totally liked your explaination.
I have a few doubts , please help me
I am trying to get multichannel ADC working while still being able to send and receive data via UART. Currently, I have the serial communication code working but I require pins 1.1 (TXD) and 1.2 (RXD) to do it. On the other hand, I want to use 6 other channels for ADC sampling. I have been trying to sample from 1.3, 1.4, 1.5, 1.6, and 1.7.

From what I've gathered, setting INCH_7 while preforming multichannel sampling will allow ADC to sample from A0-A7. But I don't want to sample from A1 and A2 since those pins are being used for serial transmission.

Any ideas or tips on how to set this up?
[ - ]
Comment by DubsJune 3, 2014
Hello

I am a newbie, newly graduated, and tasked with programming an RS232 on a MSP4305659. I've no experience using this type of processor or this type of USCI port to do RS232. Do you have any guidance, any tutorials or sites you know of that could provide some guidance using this family of processors?

thanks

Dubs
[ - ]
Comment by Manasu24January 12, 2015
Hi Enrico,
i am using Uart in Irda mode in msp430f5438.
but, it is giving the output valve as 255 always for all commands i send through remote.
tsop34838 is the ir receiver i am using and i hae directly connect the output of this ir receiver to the Rx pin of Uart in msp430f5438.
Thank you
[ - ]
Comment by Nagendra prasathMarch 2, 2015
Hi sir,
The tutorial was useful. What are all the things should I replace in the above program for serial communication using MSP430F5529..
[ - ]
Comment by Chris TTUApril 27, 2015
Hey thanks for the upload, but I was wondering if you could actually change something in the code to send the characters to RAM memory instead of FLASH.
[ - ]
Comment by billy77July 8, 2016
I would like to know where you got the names for the interrupt functions. They are not in the family guide nor are they in the data sheet. The only code in the family guide is assembly and the names are not the same.

To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.

Registering will allow you to participate to the forums on ALL the related sites and give you access to all pdf downloads.

Sign up
or Sign in