Jump to content
mpigsley

Hardware UART & Two Servos

Recommended Posts

I'm fairly new to specifically MSP430 development, so any help here is appreciated!

I'm trying to send data to and from a Raspberry Pi connected over hardware UART. This I've tested and works. I'm also trying to run two servos on the MSP430 and the basic code I have for them has been tested and also works. 

 

The problem occurs when I try to put them together as my timer setup must clash somewhere. It seems to me that the serial communication is all set on TA0 while the other timer is set to TA1. I don't understand why this would prevent the UART from sending and receiving.

 

Edit: I'm using the MSP430G2553 

int main(void){
  WDTCTL = WDTPW + WDTHOLD;                            // Stop watchdog timer
  init_servos();
  init_UART();
  _BIS_SR(GIE);                                        // Enable CPU interrupts

  while(1){                                            // Wait for incoming character
    _BIS_SR(LPM0_bits);                                // Enter low poser mode
    if (rxBuffer == 'a') {
      P1OUT |= BIT0;
    }
  }
}

void init_UART() {
  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 = UART_TXD + BIT0;                             // TX and LED1 to Output

                                                       // Configures Timer_A for full-duplex UART operation
  TA0CCTL0 = OUT;                                      // Set TXD Idle as Mark = '1'
  TA0CCTL1 = SCS + CM1 + CAP + CCIE;                   // Sync, Neg Edge, Capture, Int
  TA0CTL = TASSEL_2 + MC_2;                            // SMCLK, start in continuous mode
}

void init_servos() {
  P2SEL |= BIT0 | BIT1;
  P2DIR |= BIT0 | BIT1;

  // Duty Cycle (585 - 675 - 765)
  TA1CCTL0 = OUTMOD_7;                                 // reset/set (0)
  TA1CCTL1 = OUTMOD_7;                                 // reset/set (1)
  TA1CTL = TASSEL_2 + MC_1;                            // SMCLK, up mode
  BCSCTL1 = 0x84;                                      // CLK Info
  
  TA1CCR0 = 675;                                       // Duty Cycle (2.0)
  TA1CCR1 = 675;                                       // Duty Cycle (2.1)
}

void TimerA_UART_print(char *string) {                 // Prints a string using the Timer_A UART
  while (*string)
    TimerA_UART_tx(*string++);
}

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
}

#pragma vector = TIMER0_A0_VECTOR                      // Timer_A UART - Transmit Interrupt Handler
__interrupt void Timer_A0_ISR(void) {
  static unsigned char txBitCnt = 10;
  TA0CCR0 += UART_TBIT;                                // Add Offset to CCRx

  if (txBitCnt == 0) {                                 // All bits TXed?
    TA0CCTL0 &= ~CCIE;                                 // All bits TXed, disable interrupt
    txBitCnt = 10;                                     // Re-load bit counter
  }
  else {
    if (txData & 0x01)
      TA0CCTL0 &= ~OUTMOD2;                            // TX Mark '1'
    else
      TA0CCTL0 |= OUTMOD2;                             // TX Space '0'
  }
  txData >>= 1;                                        // Shift right 1 bit
  txBitCnt--;
}

#pragma vector = TIMER0_A1_VECTOR                      // Timer_A UART - Receive Interrupt Handler
__interrupt void Timer_A1_ISR(void) {
  static unsigned char rxBitCnt = 8;
  static unsigned char rxData = 0;

  switch (TA0IV) {                                     // Use calculated branching
    case TA0IV_TACCR1:                                 // TACCR1 CCIFG - UART RX
         TA0CCR1 += UART_TBIT;                         // Add Offset to CCRx
         if (TA0CCTL1 & CAP) {                         // Capture mode = start bit edge
           TA0CCTL1 &= ~CAP;                           // Switch capture to compare mode
           TA0CCR1 += UART_TBIT_DIV_2;                 // Point CCRx to middle of D0
         }
         else {
           rxData >>= 1;
           if (TA0CCTL1 & 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
             TA0CCTL1 |= CAP;                          // Switch compare to capture mode
             _BIC_SR_IRQ(LPM0_bits);                   // wake up from low power mode.
           }
         }
         break;
   }
}

Share this post


Link to post
Share on other sites

Oh sorry, it's G2553

Ok, definitely confused and obviously don't have all your code here.  What is "void TimerA_UART_print(char *string) {                 // Prints a string using the Timer_A UART" ?

Sounds like you snagged some Software UART code that uses Timer_A (there's your conflict right there) instead of the actual UART hardware (called USCI_A).

Share this post


Link to post
Share on other sites

For the sake of brevity, here's some of my code for driving the hardware USCI_A0 UART port:

void uart_init()
{
        // Init USCI
        // Assumes SMCLK = MCLK/1 (16MHz)

        IFG2 &= ~(UCA0TXIFG | UCA0RXIFG);

        UCA0CTL0 = 0x00;
        UCA0CTL1 = UCSSEL_2 | UCSWRST;

        // 115200 @ 16MHz UCOS16=1
        //UCA0BR0 = 8;
        //UCA0BR1 = 0;
        //UCA0MCTL = UCBRS_0 | UCBRF_11 | UCOS16;

        // 9600 @ 16MHz UCOS16=1
        UCA0BR0 = 104;
        UCA0BR1 = 0;
        UCA0MCTL = UCBRS_0 | UCBRF_3 | UCOS16;



        // G2xxx series
                #ifdef __MSP430_HAS_TB3__  // G2xx4 & G2xx5 series
                P3SEL |= BIT4 | BIT5;
                P3SEL2 &= ~(BIT4 | BIT5);
                #else                      // G2xx3 series
                P1SEL |= BIT1|BIT2;  // USCIA
                P1SEL2 |= BIT1|BIT2; //
                #endif
        #endif

        UCA0CTL1 &= ~UCSWRST;
}

void uart_print_str(const void *str)
{
        char *strptr = (char *)str;
        int i=0, j;

        j = strlen(strptr);
        for (; j; j--) {
                UCA0TXBUF = strptr[i];
                while (UCA0STAT & UCBUSY) ;
                i++;
        }
}

You will need to adjust the UCA0BR0 and UCA0BR1 along with UCA0MCTL values to reflect the fact that you're running your chip at 1MHz, not 16MHz like I am.  Look at the MSP430x2xx User's Guide for the lookup table of values: http://www.ti.com/lit/ug/slau144j/slau144j.pdf page 424.

 

Also be sure to #include <string.h> so you have access to the strlen() function, used in the uart_print_str() function.

Share this post


Link to post
Share on other sites

Ok, definitely confused and obviously don't have all your code here.  What is "void TimerA_UART_print(char *string) {                 // Prints a string using the Timer_A UART" ?

Sounds like you snagged some Software UART code that uses Timer_A (there's your conflict right there) instead of the actual UART hardware (called USCI_A).

 

You're right, there's that TimerA_UART_tx() function I missed. It is editied in to the original post.

Since there is dedicated UART hardware, does this mean I can remove that dependency on TimerA for bi-directional serial comm? It looks like you did just that in the code snippet.

 

You will need to adjust the UCA0BR0 and UCA0BR1 along with UCA0MCTL values to reflect the fact that you're running your chip at 1MHz, not 16MHz like I am.  Look at the MSP430x2xx User's Guide for the lookup table of values: http://www.ti.com/lit/ug/slau144j/slau144j.pdf page 424.

 

Also be sure to #include <string.h> so you have access to the strlen() function, used in the uart_print_str() function.

 

Great! I'll look into this and see where I get. Thank you!

Share this post


Link to post
Share on other sites

You're right, there's that TimerA_UART_tx() function I missed. It is editied in to the original post.

Since there is dedicated UART hardware, does this mean I can remove that dependency on TimerA for bi-directional serial comm? It looks like you did just that in the code snippet.

 

 

Great! I'll look into this and see where I get. Thank you!

Yes :)  Also if I'm not mistaken, at least using the MSP430G2 LaunchPad, software UART should (in theory) work but you have to switch the UART jumpers up top to "SW" mode... in any case just make sure they're set to "HW" mode (jumpers facing left-right) and use the USCI_A peripheral instead.

Share this post


Link to post
Share on other sites

Yes :)  Also if I'm not mistaken, at least using the MSP430G2 LaunchPad, software UART should (in theory) work but you have to switch the UART jumpers up top to "SW" mode... in any case just make sure they're set to "HW" mode (jumpers facing left-right) and use the USCI_A peripheral instead.

 

I'll do just that. Thank you for your prompt help!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...