LAB 6: Serial Communication
Chung-Ta KingNational Tsing Hua University
CS 4101 Introduction to Embedded Systems
Introduction
• In this lab, we will learn– Communication peripherals of MSP430 LaunchPad– How to implement a software UART on MSP430
LaunchPad– How to let MSP430 LaunchPad communicate with
the PC through RS232 interface
Comm. Peripherals in MSP430• Universal Serial Interface (USI):
– A lightweight module handles only synchronous communication: SPI and I2C
– Included in MSP430G2331
• Universal Serial Comm. Interface (USCI):– Handle almost all aspects of the communication– Asynchronous channel, USCI_A: act as a universal
asynchronous receiver/transmitter (UART) to support the usual RS-232 communication
– Synchronous channel, USCI_B: handle both SPI and I²C as either master or slave
– Included in MSP430G2553
Pin Connections
TXD
RXD
#define TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0)#define RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A)P1SEL |= TXD + RXD; // Enable TXD/RXD pinsP1DIR = 0xFF & ~RXD; // Set pins to outputP1OUT = 0x00; // Initialize all GPIO
Use TACCR0
Use TACCR1
RXD pin
TXD pinFor
Receive
ForTransmission
Latch allows samplingat precise time, regardless of ISRlatency
Software UART by Timer_A• Between transmissions, CCx (capture/compare) waits
in the Capture mode for a falling edge on its input. • When a falling edge is detected, TACCRx captures the
count in TAR and an interrupt is requested. CCx is switched to Compare mode, and TACCRx is set to fire an interrupt after 1.5 of the bit period from now.
• The next interrupt occurs and SCCI contains the value of LSB. ISR saves it. Next compare event is set up to occur after a further bit period.
• The above procedure is repeated until all 8 bits of data have been received.
9
Software UART: Transmission
Use Capture/Compare Block 0 (TACCR0)• OUTMOD0: OUT0 signal is defined by OUT bit• OUTMOD2: OUT0 signal is reset when the timer
counts to TACCR0 Use OUTMOD0 to send a 1, OUTMOD2 for 0
OUT0
Software UART: Transmission#pragma vector = TIMER0_A0_VECTOR__interrupt void Timer_A0_ISR(void) { static unsigned char txBitCnt = 10; TACCR0 += UART_TBIT; // Add Offset to TACCR0 if (txBitCnt == 0) { // All bits TXed? TACCTL0 &= ~CCIE; // All bits TXed, disable int txBitCnt = 10; // Re-load bit counter } else { if (txData & 0x01) { // Check next bit to TX TACCTL0 &= ~OUTMOD2; // TX Mark '1’ } else { TACCTL0 |= OUTMOD2; } // TX Space '0' txData >>= 1; txBitCnt--; }}
Software UART: Transmission
• Initialization and preparing the byte to TX ... TACCTL0 = OUT; // Set to output high ... TACCR0 = TAR; // Current count of TA TACCR0 += UART_TBIT; // One bit time TACCTL0 = OUTMOD0 + CCIE; // Set TXD txData |= 0x100; // Add stop bit to TXData txData <<= 1; // Add start bit ...
Software UART: Receive
• Initialization of Capture/Compare Block 1
P1.2
TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, capture on neg edge, Capture mode
// CCIS1 = 0 (default) CCI1A, interrupt
Software UART: Receive
#pragma vector = TIMER0_A1_VECTOR__interrupt void Timer_A1_ISR(void) { static unsigned char rxBitCnt = 8; TACCR1 += UART_TBIT; // Add offset to TACCR1 if (TACCTL1 & CAP) { // On start bit edge TACCTL1 &= ~CAP; // Switch to compare mode TACCR1 += UART_TBIT_DIV_2; // To middle of bit } else { // Sample the next data bit rxData >>= 1; if (TACCTL1 & SCCI){// Get bit from receive latch rxData |= 0x80; } rxBitCnt--; if (rxBitCnt == 0) { // All bits RXed? TACCTL1 |= CAP; } // Switch to capture mode}
Sample Code (msp430g2xx3_ta_uart9600)
• Software UART, using Timer_A, 9600 baud, echo, full duplex, 32kHz ACLK– Main loop readies UART to receive one character
and waits in LPM3 with all activity interrupt driven.
– ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = default DCO, external watch crystal required
– TACCR0 and TACCR1 may interrupt at any time and in an interleaved way
Sample Code (msp430g2xx3_ta_uart9600)
#include "msp430g2553.h“#define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0)#define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A)#define UART_TBIT_DIV_2 (1000000 / (9600 * 2))#define UART_TBIT (1000000 / 9600)unsigned int txData; // UART internal TX variable unsigned char rxBuffer; // Received UART character
void TimerA_UART_init(void);void TimerA_UART_tx(unsigned char byte);void TimerA_UART_print(char *string);
Sample Code (msp430g2xx3_ta_uart9600)
void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1OUT = 0x00; // Initialize all GPIO P1SEL = UART_TXD + UART_RXD; // Use TXD/RXD pins P1DIR = 0xFF & ~UART_RXD; // Set pins to output __enable_interrupt();
Sample Code (msp430g2xx3_ta_uart9600)
TimerA_UART_init(); // Start Timer_A UART TimerA_UART_print("G2xx2 TimerA UART\r\n"); TimerA_UART_print("READY.\r\n"); for (;;) { // Wait for incoming character __bis_SR_register(LPM0_bits); // Echo received character TimerA_UART_tx(rxBuffer); }}void TimerA_UART_print(char *string) { while (*string) TimerA_UART_tx(*string++);}
Waken up byTimer_A1_ISR
20
Sample Code (msp430g2xx3_ta_uart9600)
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, continuous mode}void TimerA_UART_tx(unsigned char byte) { while (TACCTL0 & CCIE); // Ensure last char 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}
21
Sample Code (msp430g2xx3_ta_uart9600)
#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 int txBitCnt = 10; // Re-load bit counter } else { if (txData & 0x01) { TACCTL0 &= ~OUTMOD2; // TX Mark '1’ } else { TACCTL0 |= OUTMOD2;} // TX Space '0‘ txData >>= 1; txBitCnt--; }}
22
Sample Code (msp430g2xx3_ta_uart9600)
#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)) { case TA0IV_TACCR1: // TACCR1 CCIFG - UART RX TACCR1 += UART_TBIT; // Add Offset to CCRx if (TACCTL1 & CAP) { // On start bit edge TACCTL1 &= ~CAP; // Switch to compare mode TACCR1 += UART_TBIT_DIV_2; // To middle of D0 } else { // Get next data bit rxData >>= 1;
23
Sample Code (msp430g2xx3_ta_uart9600)
if (TACCTL1 & SCCI) { // Get bit from latch rxData |= 0x80; } rxBitCnt--; if (rxBitCnt == 0) { // All bits RXed? rxBuffer = rxData; // Store in global rxBitCnt = 8; // Re-load bit counter TACCTL1 |= CAP; // Switch to capture __bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR) } } break; }}
Wake up main loop
Setting PC for Serial Comm.
• In the Debug perspective of CCS IDE, click [View] -> [Other…] and, in the Show View window, click the + next to Terminal.
• Select Terminal below that and click OK.
Setting PC for Serial Comm.
• A Terminal pane will appear on your screen. Click the Settings button in the Terminal pane and make the selections (set the serial communication setting)
Basic Lab
• Modify the full-duplex sample code to a half-duplex UART that receives characters 0 or 1 from the PC. Turn on the green LED if a 1 is received, the red LED if a 0 is received, and no LED for other characters. Use 4800 baud, 8-bit of data, and 2 stop bits.
Bonus
• Temperature Sensing System– MSP430 reads temperature from ADC every second and
compare reading with the one sensed in previous second.– If the current temperature is higher, turn on the red LED
and send HI to PC– If the current temperature is lower, turn on the green LED
and send LO to PC– If the sensed temperature is equal to the first one turn off
both LEDs and send IN to PC
• Hint:– Use Timer_A alternatively for timing 1 sec and UART
Sample Code for USCI_A0
• Echo a received character using 9600 UART and DCO-driven SMCLK running at 1MHz– Use RX ISR– USCI_A0 RX interrupt triggers TX Echo– Baud rate divider with 1MHz = 1MHz/9600 =
~104.2
31
Sample Code for USCI_A0
#include "msp430g2553.h"void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 = CALBC1_1MHZ; // Set DCO to 1MHz DCOCTL = CALDCO_1MHZ; P1SEL = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD P1SEL2 = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD UCA0CTL1 |= UCSSEL_2; // SMCLK UCA0BR0 = 104; // 1MHz 9600 UCA0BR1 = 0; // 1MHz 9600 UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1 UCA0CTL1 &= ~UCSWRST; // Initialize USCI IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt // Enter LPM0, interrupts enabled __bis_SR_register(LPM0_bits + GIE); }
32
Sample Code for USCI_A0 // Echo back RXed character,
// confirm TX buffer is ready first#pragma vector=USCIAB0RX_VECTOR__interrupt void USCI0RX_ISR(void) { // USCI_A0 TX buffer ready? while (!(IFG2&UCA0TXIFG)); UCA0TXBUF = UCA0RXBUF; // TX -> RXed character}
Basic Lab• Emulate UART by Timer
– Fill up the sample code– Send “Hello World” to the PC from MSP430 LanuchPad in
the main loop• Hints
– TXByte can be seen as the data buffer, where we store the character we want to send. We use ASCII code.
– You need to set the Bit Time correctly.
send[]={0x48,0x49,0x0A,0x08,0x08};for (i=0;i<5;i++) { TXByte = send[i]; Transmit();}