MSP430 LaunchPad: my 9600 Baud Serial Connection

I wanted to create a 9600 asynchronous serial connection with my TI LaunchPad.
I started my development from the source code of the example program that I found in it (temp. sensor with serial connection and leds modulation) but I wanted three more things: a faster link (9600 which is four times greater), a mspgcc4 compatibility (the free-software compiler that I’m using) and a CPU working at 16 MHz (instead of 1 MHz of the example).

The task is not very difficult and I carried it in a completely free environment (Ubuntu + MSPGCC + mspDebug).

Introduction

First of all, the asynchronous serial communication is a way to send and receive data over a link, without the need of a clock signal. In its simplest implementation we have the transmission of 10 symbols: a starting 0 (start bit), eight bits of data and an ending 1 (stop bit).
From this we can add a parity bit (and other things…) to aim to a more strong/error-free connection but that’s not our case of study.

To allow a communication between two units we have to set the same “communication speed” parameter, which impose the time duration of each bit. Its unit is the BAUD: the maximal number of symbols each second.
For example 9600 BAUD means that every symbol needs to be 1/9600 seconds long (otherwise we cannot meet the desired top speed).

void Transmission(void)

As in the software example of TI, the serial transmission is made by putting the 8 bits to send in a variable (TXByte) and then calling the function void transmission().

This function prepares the transmission adding a Start Bit and a Stop Bit to the data that we want to send. It also actives the interrupt of the TimerA, the timing device inside the MSP430 that is used to create a good and compliant serial signal.

With Bitime we set the number of cycles of the timer between each interruption. This is done by adding this value to the TimerA configuration register CCR0.

The main program is blocked inside this function until the transmission is completed.

interrupt(TIMERA0_VECTOR) uart(void)

This function is responsible for changing the output of the UART according to the data bit to send. It checks the number of the bits already sent (BitCnt) and if the communication is not terminated.

Configurations

As stated before, we set up the internal oscillator at 16 MHz (=MSCKL = SMCLK).
The TimerA is working in continuous mode, incremented at the frequency of SMCLK divided by 8 (Timer Clock).

Bitime is derived from the Timer Clock speed and the Communication speed.
The relation is:

BAUD = Timer Clock / Bitime

In the example we have Bitime = 52, which is ( Timer Clock / BAUD ) = ( (1 MHz / 8 ) / 2400).
In our case I changed both the Clock and the BAUD, so the new Bitime is (16 MHz / 8 ) / 9600 = 209.

    –> Actually 209 didn’t worked… I changed to 250, but I don’t know why…

Source code


#include
#include

// leds
#define LED_R BIT0
#define LED_G BIT6

// software UART
#define TXD BIT1
#define RXD BIT2

// BAUD * Bitime = TimerA adding frequency
// @1Mhz Bitime = ( 1MHz / 8 ) / 2400 = 52
// @16Mhz Bitime = ( 16MHz / 8 ) / 9600 = 209
#define Bitime 250

unsigned int TXByte; // byte to send
unsigned char BitCnt; // bit counter

void initClocks(void);
void initIO(void);
void initTimerUart(void);
void Transmit();
static void __inline__ delay(register unsigned int n);

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

initClocks();
initIO();
initTimerUart();

__bis_SR_register(GIE); // General Interrupts Enable

while(1){

TXByte = 0xAA; // let's send 10101010
Transmit();
TXByte = 0x48; // let's send H
Transmit();
TXByte = 0x49; // let's send I
Transmit();
delay(30000);

}
return 0;
}

void initTimerUart(){
CCTL0 = OUT; // TXD Idle as Mark (OUT = 1)
TACTL = TASSEL_2 + MC_2 + ID_3; // SMCLK/8, continuos mode
}

interrupt(TIMERA0_VECTOR) uart(void)
{
CCR0 += Bitime; // Add Transmission Offset to CCR0

if (TACCTL0 & CCIS0){ // TX on CCI0B?

if ( BitCnt == 0){
TACCTL0 &= ~ CCIE; // All bits TXed, disable interrupt
} else {

CCTL0 |= OUTMOD2; // TX Space
if (TXByte & 0x01) CCTL0 &= ~ OUTMOD2; // TX Mark

TXByte = TXByte >> 1; // next bit
BitCnt --;
}
}
}

// Function Transmits Character from TXByte (Mark Bit = "1" and Space Bit = "0")
void Transmit()
{

BitCnt = 0xA; // 10 bits (8 data + start bit + stop bit)

if (CCR0 != TAR) CCR0 = TAR; // synch CCR0 to TAR

CCR0 += Bitime; // Some time till first bit

TXByte |= 0x100; // Add mark stop bit to TXByte
TXByte = TXByte << 1; // Add space start bit

CCTL0 = CCIS0 + OUTMOD0 + CCIE; // TXD = mark = idle

while ( CCTL0 & CCIE ) delay(5); // Wait for TX completion
}

void initClocks(void)
{
BCSCTL1 = CALBC1_16MHZ; // Set range (MSCKL = SMCLK = 16MHz)
DCOCTL = CALDCO_16MHZ;
}

void initIO(void)
{
P1SEL |= TXD + RXD; // use pins for the UART
P1DIR |= TXD + LED_R; // set TXD as output
P1OUT = LED_R; // all outputs to 0, except Red led
}

// Delay Routine from mspgcc help file
static void __inline__ delay(register unsigned int n)
{
__asm__ __volatile__ (
"1: \n"
" dec %[n] \n"
" jne 1b \n"
: [n] "+r"(n));
}

Lascia un Commento

Fill in your details below or click an icon to log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Log Out / Modifica )

Foto Twitter

You are commenting using your Twitter account. Log Out / Modifica )

Foto di Facebook

You are commenting using your Facebook account. Log Out / Modifica )

Connecting to %s

Follow

Get every new post delivered to your Inbox.