Most tutorials discuss about serial communication at a later stage as it might involve some more complexity.
I prefer to introduce it briefly here since I believe it's the easiest way to verify / debug the code execution.
We all have a PC, right? Let's use it to see what's happening on the Launchpad!
Serial communication can happen with different protocols, here we will discuss the RS232 kind of serial communication which is the easiest to interface with all the widely used PC operating systems.
Microcontrollers normally don't have a RS232 interface, instead they have a TTL UART which basically works the same except it does not provide any high level protocol feature, nor it boosts the signal to reach high distances with a decent speed.
As already anticipated in another post, the launchpad, similarly to most of the dev boards, includes an FTDI interface that emulates a serial over the USB connection.
From a software standpoint, on the connected PC, this can be treated as a normal serial port.
When deploying a project with a microcontroller, if the serial connection to a pc is still needed, a FTDI converted cable is needed (they cost around 8-10$).
Some processors from the MPS430 family include the USCI option, which provides, amongst other protocols, a hadrware TTL UART.
We will discuss this one today, even if it is possible to emulate a software serial using the GPIO and an internal timer.
Serial communication is defined with a few parameters :
- Baud rate (speed) [2400,9600,19200...115200]
- Byte length [7 or 8]
- Parity [even , odd, none, mark, space]
- stop bit [1,1.5,2]
All these parameters are related to the low level (physical) protocol, so they do apply to the TTL UART as well.
Instead we will not have any flow control option.
All the standard baud rates were defined using a 32.768 Hz Oscillator, therefore some of them may became unreliable when using a different frequency (unless it is a multiple of 32.768 Hz).
Also, having a reliable oscillator is key in achieving high quality and fast serial connections, for this kind of job the external low frequency oscillator may help a lot.... but we will manage also without.
In a real project, if the components that need to exchange data are not too far away and can control the exact baud rate, higher frequencies might help to achieve faster transfer rates... but for this an I2C or SPI connection may be more suitable.
Did you manage to upload your code to the launchpad? If you did, it means that the serial communication worked smoothly.
Registers
As usual all the configuration is done via a set of registers, this is what the User guide reports :
The first register UCAxCTL0, USCI_Ax (x is normally 1, unless more than 1 USCI is available in the specific MCU) is used to set parity, stop bits, synchronous / asynchronous mode, data length, little/big endian etc...
When the value is set to 0 (default, all bits to zero) the configuration will be the most common one : 8,N,1 asynchronous LSB first.
If you need a different settings, check the user guide for details.
The UCAxCTL1 Control Register 1 is used to select which clock system is used to generate the needed baud rate.
This is set with the two highest bits :
- 00 = UCLK
- 01 = ACLK
- 10 , 11 = SMCLK
The register is used also for managing breaks, address transmission and other functions, we will not discuss them here.
Now, once we have the reference clock and we want to generate a specific baud rate, we need to divide the clock frequency by setting the prescaler (divider).
UCAxBR0 and UCAxBR1 are used to set the divider : The 16-bit value of (UCAxBR0 + UCAxBR1 × 256) forms the prescaler value.
Common values are shown in the picture below
In order to reduce errors the UCAxMCTL register is used to fine tune the modulation by using an oversampling technique (requires a high frequency BRCLK >=1MHz).
Finally when all the parameters are properly set up the UART is initialized :
And then eventually the interrupt is enabled
Note that a different Interrupt is available for RX and TX
If it looks a bit complex... it's because it is complex, but luckily libraries are available online.
Next step will be to create a UART_setup function that uses the information in this post, then transmit and receive functions will be created.
Transmit and receive are quite symple : to transmit data is written to a UART TX register once it is ready to transmit (an interrupt flag can be checked for that).
Similarly to read data it's enough to read a UART RX register when the rx interrupt is raised.
A sample program
We are going to use the Hardware UART, this requires the two jumpers RXD and TXD on the launchpad to be set horizontally instead of vertically.
#include <msp430g2553.h>
void main(void)
{ // stop the watchdog
WDTCTL = WDTPW + WDTHOLD; // allow debugging
// configure the CPU clock (MCLK)
// to run from DCO @ 16MHz and SMCLK = DCO / 4
BCSCTL1 = CALBC1_16MHZ; // Set DCO
DCOCTL = CALDCO_16MHZ;
BCSCTL2= DIVS_2 + DIVM_0; // divider=4 for SMCLK and 1 for MCLK
// set the pin mode 3 for pins 1 & 2 of port 1 (Uart mode)
P1SEL |= BIT1 + BIT2; // low bit = 1 for pin 1 and 2
P1SEL2 |= BIT1 + BIT2; // high bit = 1 for pin 1 and 2
// configure the UART
UCA0CTL0 = 0; //UART mode, No parity, LSB first, 8 data, 1 stop
UCA0CTL1 = UCSSEL_2; //use SCLK
UCA0BR0 = 0x1A; //lower byte of UCBR0. 26dec
//(4MHz / 9600 baud) see table 15-5
UCA0BR1 = 0x0; //upper byte of UCBR0.set to 0
UCA0MCTL = UCBRF_1 + UCBRS_0 + UCOS16; //sets UCBRFx to 1,
// UCBRSx tto 0 , UCOS16=1
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI **
UC0IE |= UCA0RXIE; // Enable USCI_A1 RX interrupt
_EINT(); // global enable interrupts
while (1); // process is managed by the interrupt vector
}
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
UCA0TXBUF=UCA0RXBUF; // echo TX = RX
}
This is just an example program that configures the UART at 9600,8,N,1 and echoes any incoming char using the interrupt vector triggered by the RX signal.
The first instruction is used to disable the watchdog, this is a good idea to enable the debugger to stop anytime the code.
Then the MCLK and SCLK clocks are set to 16MHz and 4MHz respectively.
The hardware UART RXD and TXD pins are on P1.1 and P1.2 (MSP430G2253, might be different on other devices, check the specific Datasheet), however their default configuration is to function as GPIO pins, so we need to SELect the mode 3 for them, which corresponds to UART functions.
We normally need to set the direction for them, but this is not necessary if we select the UART mode, direction will be set automatically (table 16 of the datasheet).
Finally we need to setup the uart.
We want it to run using SMCLK as clock generator, which is configured to run at 4MHz, therefore we check the values in table 15-5 corresponding to the 4MHz BRCLK.
We notice that error rate is optimal at 9600 baud for this frequency and that the divider should be set to 26, RSx = 0 RFx = 1, UCOS16 = 1. All that is set in the UCA0MCTL register :
UCA0MCTL = UCBRF_1 + UCBRS_0 + UCOS16;
At this point we can reset the uart as we finished our configuration, then we can enable the RX interrupt and finally we can globally enable interrupts.
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
Defines a function whose address is specifically set to match the address of the UART RX interrupt vector, meaning this function is called each time the RX interrupt is triggered.
In this function we just echo in the TX buffer whatever we read in the RX buffer