MSP430 LaunchPad Tutorial - Part 4 - UART Transmission
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
- Part 1: MSP430 Launchpad Tutorial - Part 1 - Basics
- Part 2: MSP430 Launchpad Tutorial - Part 2 - Interrupts and timers
- Part 3: MSP430 LaunchPad Tutorial - Part 3 - ADC
- Part 4: MSP430 LaunchPad Tutorial - Part 4 - UART Transmission
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.
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.
- Comments
- Write a Comment Select to add a comment
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
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.
Have a look at the interrupt tutorial!
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?
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
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
The tutorial was useful. What are all the things should I replace in the above program for serial communication using MSP430F5529..
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.
Please login (on the right) if you already have an account on this platform.
Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: