This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

UART by software in MSP430G2553

Other Parts Discussed in Thread: MSP430G2553

Hi.

I´m using launchpad and microcontroller MSP430G2553, for my aplication I need 4 pins UART.  I have to program 2 pins like UART by software. Is there a code??? help me

  • Hello Viviana,

    You can look at a similar post that used to create a software UART. http://e2e.ti.com/support/microcontrollers/msp430/f/166/p/108181/382093.aspx#382093

    Also, the wiki has similar information.

    An external site also has this implemented with code. http://www.msp430launchpad.com/2010/08/half-duplex-software-uart-on-launchpad.html

    Although these are not the exact chip, you can change the ports as required.

    Thanks,

  • Viviana Monroy said:
     I have to program 2 pins like UART by software. Is there a code???

    The LaunchPad demo code for the other G series MSPs (not the G2553) use a software UART with support of the timer.

    However, this softwar eUART requires the exact same two pins as the hardware UART fo the 2553. So you waste comfort (and a timer) and gain nothing. :)

    Doing a software UART in plain software (not using timer hardware) isn't recommended because of the huge timing errors that surely will happen. It might be good for 300 or 1200Bd but for anything above, the timings likely won't be precise enough. Especially for someone who ha to ask for code for this task (those experienced enough to do it are surely experienced enough to do it without code examples)

  • Viviana Monroy said:
    4 pins UART

    What do you mean by that?

    • A single 4-wire UART; ie, RX, TX, RTS, CTS ?
    • A pair of 2-wire UARTs; ie, Rx1+Tx1; Rx2+Tx2 ? 
    • Or what?

  • thank you.

    I think other option, use 2 microcontroller. It´s not better option but it´s more reliable.

    Thank you so much.

  • a pair of  2 wire UART´s.

    Rx1, Tx1

    Rx2, TX2

  • Viviana Monroy said:
    a pair of  2 wire UART´s.

    f you don't need them at the same time, you may use an external multiplexer chip, like the 74HC4053.

    If both connections have the same baudrate, you can even listen to one side while sending to the other. Else you have to change the baudrate when switching both connections.

    I use this method for the ATMega128, where at programming time, the hardware serial port is connected to the flashing tool while at operation, it is connected to an RS232 connector.

  • thank you so much. 

    I use the code, I solve the problem. :)

  • Hello Viviana,

    might be a bit late, but here is my solution. In my case I have to collect analog data from all analog inputs P1.0-P1.7, (hence the UART pins are not accessible), and transmit to the host device. Thankfully there are two timers in G2553, so one of them with CCR0 can be sacrificed for soft UART operation. The trick is to determine the appropriate TACCR0 value for required baud rate. Below is the code. Just pass the byte to transmit to uartTx(char). BiTcntr = 0 indicates that transmitter is ready for the new character.
    This code is for UART transmitter ONLY. I'm working on Receiver as well. Will post when it's ready.

    /*	Soft UART on TA1-CCR0	*/
    /*	A. Norman	*/
    
    #define	Uchar	unsigned char
    #define TxD	BIT7		//P2.7, XOUT on Launchpad
    #define Baudrate 0x80		//0x680 for 9600; 0x80 for 115200
    
    Uchar buff_Tx[64];
    Uchar *ptr_Tx;
    Uchar BiTcntr;
    Uchar txByte; /* Somwhere in main() */ ptr_Tx = (Uchar *)buff.Tx_Data; /********************************/ void initIO(void); void initTA1(void); void uartTx(Uchar byte); void initIO(void){ P2SEL &= ~TxD; P2SEL2 &= ~TxD; P2DIR |= TxD; P2OUT |= TxD; } void initTA1(void){ TA1CTL = TACLR; TA1CTL = TASSEL_2 + ID_0; TA1CCR0 = Baudrate; TA1CCTL0 |= CCIE; } void uartTx(Uchar byte){ *(ptr_Tx) = byte; BiTcntr = 9; TA1CTL |= MC_1; } #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer1_A0(void){ switch (BiTcntr){ case 9: P2OUT &= ~TxD; //uart operation txByte = *(ptr_Tx); BiTcntr--; break; default: if (txByte & 0x01){ P2OUT |= TxD; //uart operation }else{ P2OUT &= ~TxD; //uart operation } txByte = txByte>>1; BiTcntr--; break; case 0: ptr_Tx++; P2OUT |= TxD; //uart operation TA1CTL &= ~MC_1; // _BIC_SR_IRQ(CPUOFF); // Exit LPM0 Use if needed break; } }

    7433.softUART.c.txt
    /*	Soft UART on TA1-CCR0	*/
    /*	A. Norman	*/
    
    #define	Uchar	unsigned char
    #define TxD		BIT7		//P2.7, XOUT on Launchpad
    #define Baudrate 0x80		//0x680 for 9600; 0x80 for 115200
    
    Uchar buff_Tx[64];
    Uchar *ptr_Tx;
    Uchar BiTcntr;
    /*		Somwhere in main()		*/
    ptr_Tx = (Uchar *)buff.Tx_Data;
    /********************************/
    
    void initIO(void);
    void initTA1(void);
    void uartTx(Uchar byte);
    
    void initIO(void){
        P2SEL &= ~TxD;
        P2SEL2 &= ~TxD;
        P2DIR |= TxD;
    	P2OUT |= TxD;
    }
    
    void initTA1(void){
    	TA1CTL = TACLR;
    	TA1CTL = TASSEL_2 + ID_0;
    	TA1CCR0 = Baudrate;
    	TA1CCTL0 |= CCIE;
    }
    
    void uartTx(Uchar byte){
    	*(ptr_Tx) = byte;
    	BiTcntr = 9;
    	TA1CTL |= MC_1;
    }
    
    #pragma vector=TIMER1_A0_VECTOR
    __interrupt void Timer1_A0(void){
    	switch (BiTcntr){
    	case 9:
    		P2OUT &= ~TxD;				//uart operation
    		txByte = *(ptr_Tx);
    		BiTcntr--;
    		break;
    	default:
    		if (txByte & 0x01){
    			P2OUT |= TxD;			//uart operation
    		}else{
    			P2OUT &= ~TxD;			//uart operation
    		}
    		txByte = txByte>>1;
    		BiTcntr--;
    		break;
    	case 0:
    		ptr_Tx++;
    		P2OUT |= TxD;				//uart operation
    		TA1CTL &= ~MC_1;
    //		_BIC_SR_IRQ(CPUOFF);		// Exit LPM0 Use if needed
    		break;
    	}
    }
    

  • Fantastic work Arsen. Do you by any chance have the receiver code as well? I am working on something similar. But I just can't get it up and running.

  • Hi Alok,

    no, sorry, not yet. I started it though, up to the point when I capture the START bit on P2 ISR. I'm planning to use P2.7 XIN on launchpad. The algorithm in mind is such:

    1. Capture the START bit (1-0 transition), set the bitcount to 9, start the timer. Disable the P2.7 ISR.

    2. On the timer CCR ISR, on every occurrence set the LSB of RxByte to P2.7 value, and shift RxByte left 1. Do bitcount--.

    3. On bitcount==0 you have the full byte. stop the timer. Enable the P2.7 ISR. Use switch/case/default, as it's elegant.

    The CCR0 value should match or be slightly less that the pulse width at selected baud rate. Use Tx example value to stat with. I was also thinking of doing half pulse width shift in the START bit and capture the bit value right in the middle. Then you might want to use CCR1. Please share the code, I'd like to see if it works. (Some might think of it as a waste of a Timer ;)

  • Hey Arsen,

    After a good amount of time searching the internet for software UART solutions that do not use pins 1.1/1.2, I finally stumbled across your code. However, I am struggling a little bit to get it to run. Thus far, I have just taken your code and added a main method. This main method merely contains function calls to your two initialization functions, and then a call to UartTx('H'). Unfortunately, this does not get anything to show up on my putty terminal. I was unsure what you meant by the line of code you said to include "somewhere in main" so I left it out. Is this part of my issue? Any help would be appreciated.

    Thanks
  • Hello Hudson,

    the "somewhere in main" line of code is where the pointer initialized to the buffer of TX data. Come to think of it, there is an error in it! Here is the right way to do it:

    uchar buff_Tx[64];
    uchar *ptr_Tx;
    uchar BiTcntr;Uchar txByte;

    /*      Somwhere in main()      */
    ptr_Tx = (uchar *)buff_Tx;
    /********************************/

    And by "somewhere in main" I mean literally somewhere in main(){...}, could be right where you initialize the IO port pins, or timer. Or even better, it can be initialized right in declaration like this:

    uchar buff_Tx[64];
    uchar *ptr_Tx=(uchar *)buff_Tx;
    uchar BiTcntr;
    uchar txByte;

    and you can skip the commented lines in main.

    IMPORTANT, you would need to find a right value for Baudrate constant line 30, otherwise it's 0, and the timer never kicks in. For that I would transmit 0x55, or 'U', and fine-tune the Baudrate value to have the square-wave as close as possible to similar transmitted from classical COM port. You would need an O-scope for that. For MSP430G2553 at 16 MHz I used 0x680.

    Hit me with your next question!

    Cheers,

    Arsen

    Oh, yeah
    #define uchar unsigned char

  • Arsen,

    Thanks for your reply! I ended up getting the code to work.  My main method is as follows: 

    int main(void) {

    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    DCOCTL = CALDCO_16MHZ;
    BCSCTL1 = CALBC1_16MHZ;
    initIO();
    initTA1();
    _BIS_SR(GIE); //without this nothing works!

    uartTx('H');
    uartTx('U');
    uartTx('D');

    }

    In order to get multiple consecutive transmissions to work, I modified your uartTx method as follows:

    void uartTx(Uchar byte){
    while(BiTcntr != 10); //my addition
    *(ptr_Tx) = byte;
    BiTcntr = 9;
    TA1CTL |= MC_1;
    }

    and changed the case 0 of your interrupt routine as follows:

    case 0:
    ptr_Tx++;
    P2OUT |= TxD; //uart operation
    TA1CTL &= ~MC_1;
    BiTcntr = 10; //my addition
    //_BIC_SR_IRQ(CPUOFF); // Exit LPM0 Use if needed
    break;

    Simply checking if bitcntr is 0 was insufficient, as this would start transmitting the next character before the stop bit had been sent for the previous character.

    Anyways, thanks for your help!  Did you ever end up finishing the receive method that you mentioned? That is the next step for my work.

    - Hudson

  • Thanks for update Hudson! The forum is much more useful with followups on posts, especially with  bug fixes.

    My bad, I omitted the Enable Interrupt (and a few other things)  in main() function.

    As far as "soft receiver", no, did not have a chance, but I got a few ideas you might want to try:

    *: An interrupt (ISR) handler detects start on negative edge and starts a counter. The ISR edge is toggled.

    *: The next edge is detected. (Counter ±threshold) value indicates the number of bits. The value of the bits is the ISR edge polarity.

    I'd start experimenting with receiving 'U' (0x55 or b01010101) shown on the O-scope capture below @9600bps. The bit shifting and other house kipping I'll leave to your imagination.

    A Timer Capture input can be used as well with a different method.

    A similar approach was used in Manchester Code detector, and it works just fine. I used Timer capture input, that somewhat limits the receiver being "soft".

    Arsen

**Attention** This is a public forum