//****************************************************************************** // MSP430G2xx3 Demo - Timer_A, Ultra-Low Pwr UART 9600 Echo, 32kHz ACLK // // Description: Use Timer_A CCR0 hardware output modes and SCCI data latch // to implement UART function @ 9600 baud. Software does not directly read and // write to RX and TX pins, instead proper use of output modes and SCCI data // latch are demonstrated. Use of these hardware features eliminates ISR // latency effects as hardware insures that output and input bit latching and // timing are perfectly synchronised with Timer_A regardless of other // software activity. In the Mainloop the UART function readies the UART to // receive one character and waits in LPM3 with all activity interrupt driven. // After a character has been received, the UART receive function forces exit // from LPM3 in the Mainloop which configures the port pins (P1 & P2) based // on the value of the received byte (i.e., if BIT0 is set, turn on P1.0). // ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = default DCO // //* An external watch crystal is required on XIN XOUT for ACLK *// // // MSP430G2xx3 // ----------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // | | // | CCI0B/TXD/P1.1|--------> // | | 9600 8N1 // | CCI0A/RXD/P1.2|<-------- // // D. Dang // Texas Instruments Inc. // December 2010 // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10 //****************************************************************************** #include "msp430g2553.h" //------------------------------------------------------------------------------ // Hardware-related definitions //------------------------------------------------------------------------------ #define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0) #define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A) //------------------------------------------------------------------------------ // Conditions for 9600 Baud SW UART, SMCLK = 1MHz //------------------------------------------------------------------------------ #define UART_TBIT_DIV_2 (1000000 / (9600 * 2)) #define UART_TBIT (1000000 / 9600) //------------------------------------------------------------------------------ // Global variables used for full-duplex UART communication //------------------------------------------------------------------------------ unsigned int txData; // UART internal variable for TX unsigned char rxBuffer; // Received UART character //------------------------------------------------------------------------------ // Function prototypes //------------------------------------------------------------------------------ void TimerA_UART_init(void); void TimerA_UART_tx(unsigned char byte); void TimerA_UART_print(char *string); //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ 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; // Timer function for TXD/RXD pins P1DIR = 0xFF & ~UART_RXD; // Set all pins but RXD to output P2OUT = 0x00; P2SEL = 0x00; P2DIR = 0xFF; __enable_interrupt(); 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); // Update board outputs according to received byte if (rxBuffer & 0x01) P1OUT |= 0x01; else P1OUT &= ~0x01; // P1.0 if (rxBuffer & 0x02) P1OUT |= 0x08; else P1OUT &= ~0x08; // P1.3 if (rxBuffer & 0x04) P1OUT |= 0x10; else P1OUT &= ~0x10; // P1.4 if (rxBuffer & 0x08) P1OUT |= 0x20; else P1OUT &= ~0x20; // P1.5 if (rxBuffer & 0x10) P1OUT |= 0x40; else P1OUT &= ~0x40; // P1.6 if (rxBuffer & 0x20) P1OUT |= 0x80; else P1OUT &= ~0x80; // P1.7 if (rxBuffer & 0x40) P2OUT |= 0x40; else P2OUT &= ~BIT2; // P2.2 if (rxBuffer & 0x80) P2OUT |= 0x80; else P2OUT &= ~BIT4; // P2.4 // Echo received character TimerA_UART_tx(rxBuffer); } } //------------------------------------------------------------------------------ // Function configures Timer_A for full-duplex UART operation //------------------------------------------------------------------------------ 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, start in continuous mode } //------------------------------------------------------------------------------ // Outputs one byte using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_tx(unsigned char byte) { while (TACCTL0 & CCIE); // Ensure last char got 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 } //------------------------------------------------------------------------------ // Prints a string over using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_print(char *string) { while (*string) { TimerA_UART_tx(*string++); } } //------------------------------------------------------------------------------ // Timer_A UART - Transmit Interrupt Handler //------------------------------------------------------------------------------ #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 interrupt txBitCnt = 10; // Re-load bit counter } else { if (txData & 0x01) { TACCTL0 &= ~OUTMOD2; // TX Mark '1' } else { TACCTL0 |= OUTMOD2; // TX Space '0' } txData >>= 1; txBitCnt--; } } //------------------------------------------------------------------------------ // Timer_A UART - Receive Interrupt Handler //------------------------------------------------------------------------------ #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)) { // Use calculated branching case TA0IV_TACCR1: // TACCR1 CCIFG - UART RX TACCR1 += UART_TBIT; // Add Offset to CCRx if (TACCTL1 & CAP) { // Capture mode = start bit edge TACCTL1 &= ~CAP; // Switch capture to compare mode TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0 } else { rxData >>= 1; if (TACCTL1 & SCCI) { // Get bit waiting in receive latch rxData |= 0x80; } rxBitCnt--; if (rxBitCnt == 0) { // All bits RXed? rxBuffer = rxData; // Store in global variable rxBitCnt = 8; // Re-load bit counter TACCTL1 |= CAP; // Switch compare to capture mode __bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR) } } break; } } // Definizioni relative all'hardware // ------------------------------------------------------------------------------ # define UART_TXD 0x02 / / TXD su P1.1 ( Timer0_A.OUT0 ) # define UART_RXD 0x04 / / RXD su P1.2 ( Timer0_A.CCI1A ) // ------------------------------------------------------------------------------ // Condizioni di 9600 Baud SW UART , SMCLK = 1MHz // ------------------------------------------------------------------------------ # define UART_TBIT_DIV_2 ( 1000000 / ( 9600 * 2) ) # define UART_TBIT (1000000/9600) // ------------------------------------------------------------------------------ // Variabili globali utilizzati per la comunicazione UART full-duplex // ------------------------------------------------------------------------------ unsigned int txData ; / / UART variabile interna per TX unsigned char rxBuffer ; / / carattere UART Ricevuto // ------------------------------------------------------------------------------ // funzione prototipi // ------------------------------------------------------------------------------ void TimerA_UART_init(void); void TimerA_UART_tx(unsigned char byte); void TimerA_UART_print(char *string); // ------------------------------------------------------------------------------ // main ( ) // ------------------------------------------------------------------------------ void main ( void) {     WDTCTL = WDTPW + WDTHOLD ; // Stop watchdog timer     DCOCTL = 0x00 ; / / Set DCOCLK a 1MHz     BCSCTL1 = CALBC1_1MHZ ;     DCOCTL = CALDCO_1MHZ ;     P1OUT = 0x00 ; / / inizializzare tutte le GPIO     P1SEL = UART_TXD + UART_RXD ; / funzione Timer per pin TXD / RXD     P1DIR = 0xFF & ~UART_RXD ; / / Imposta tutti i pin , ma RXD all'uscita     P2OUT = 0x00 ;     P2SEL = 0x00 ;     P2DIR = 0xFF ;     __enable_interrupt () ;     TimerA_UART_init ( ) ; / / Avvio Timer_A UART     TimerA_UART_print ( " G2xx2 TimerA UART \r\ n" ) ;     TimerA_UART_print ( " READY.\r\n" ) ;     for (;;)     {         // Attesa per il personaggio in arrivo( INCOMING CARACTER)         __bis_SR_register ( LPM0_bits );         // Aggiorna Uscite in secondo byte ricevuto    // Update board outputs according to received byte if (rxBuffer & 0x01) P1OUT |= 0x01; else P1OUT &= ~0x01; // P1.0 if (rxBuffer & 0x02) P1OUT |= 0x08; else P1OUT &= ~0x08; // P1.3 if (rxBuffer & 0x04) P1OUT |= 0x10; else P1OUT &= ~0x10; // P1.4 if (rxBuffer & 0x08) P1OUT |= 0x20; else P1OUT &= ~0x20; // P1.5 if (rxBuffer & 0x10) P1OUT |= 0x40; else P1OUT &= ~0x40; // P1.6 if (rxBuffer & 0x20) P1OUT |= 0x80; else P1OUT &= ~0x80; // P1.7 if (rxBuffer & 0x40) P2OUT |= 0x40; else P2OUT &= ~BIT2; // P2.2 if (rxBuffer & 0x80) P2OUT |= 0x80; else P2OUT &= ~BIT4; // P2.4         // Echo ricevuto il carattere         TimerA_UART_tx ( rxBuffer ) ;     } } / / ------------------------------------------------ ------------------------------ / / Funzione configura Timer_A per il funzionamento UART full-duplex / / ------------------------------------------------ ------------------------------ void TimerA_UART_init(void) {     TACCTL0 = OUT ; / / Set TXD Idle come Mark = '1 '     TACCTL1 = SCS + CM1 + CAP + CCIE ; / / Sync, Neg Edge, Capture , Int     TACTL = TASSEL_2 + MC_2 ; / / SMCLK , avviare in modalità continua } / / ------------------------------------------------ ------------------------------ / / Uscite di un byte usando l' UART Timer_A / / ------------------------------------------------ ------------------------------ vuoto TimerA_UART_tx ( byte unsigned char ) {     while ( TACCTL0 & CCIE ) ; / / Assicurarsi ultimo carattere ottenuto TX'd     TACCR0 = TAR ; / / Stato attuale del contatore TA     TACCR0 += UART_TBIT ; / / Un po 'di tempo fino al primo bit     TACCTL0 = OUTMOD0 + CCIE ; / / Set TXD su EQU0 , Int     TxData = byte ; / / Carico variabile globale     TxData |= 0x100 ; / / Aggiungere mark bit di stop per TxData     TxData <<= 1; bit / / Aggiungere inizio space } / / ------------------------------------------------ ------------------------------ / / Stampa una stringa sopra utilizzando la UART Timer_A / / ------------------------------------------------ ------------------------------ TimerA_UART_print void ( char * string ) {     while ( *string ) {         TimerA_UART_tx ( *string++) ;     } } / / ------------------------------------------------ ------------------------------ / / Timer_A UART - Transmit Interrupt Handler / / ------------------------------------------------ ------------------------------ #pragma vector = TIMER0_A0_VECTOR __interrupt void Timer_A0_ISR(void) {     static unsigned char txBitCnt = 10;     TACCR0 += UART_TBIT ; // Aggiungi Differenza CCRX     if ( txBitCnt == 0 ) { // Tutti i bit TXed ?         TACCTL0 & = ~CCIE ; // Tutti i bit TXed , disabilitare interrupt         txBitCnt = 10; / / ricaricare contatore di bit     }     else {         if ( txData & 0x01 ) {           TACCTL0 & = ~OUTMOD2 ; // TX Mark '1 '         }         else {           TACCTL0 |= OUTMOD2 ; // TX Spazio '0 '         }         txData >>= 1 ;         txBitCnt--;     } } / / ------------------------------------------------ ------------------------------ / / Timer_A UART - Receive Interrupt Handler / / ------------------------------------------------ ------------------------------ #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)) { // Use calculated branching case TA0IV_TACCR1: // TACCR1 CCIFG - UART RX TACCR1 += UART_TBIT; // Add Offset to CCRx if (TACCTL1 & CAP) { // Capture mode = start bit edge TACCTL1 &= ~CAP; // Switch capture to compare mode TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0 } else { rxData >>= 1; if (TACCTL1 & SCCI) { // Get bit waiting in receive latch rxData |= 0x80; } rxBitCnt--; if (rxBitCnt == 0) { // All bits RXed? rxBuffer = rxData; // Store in global variable rxBitCnt = 8; // Re-load bit counter TACCTL1 |= CAP; // Switch compare to capture mode __bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR) } } break; } }