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.

Bit banding code for uart

Other Parts Discussed in Thread: MSP430G2553

Is there any reference code available for bit banding uart. I am using rx,Tx & Gnd only.
I am using Rx,Tx & Gnd only.

1. Data can rx/tx simultaneously on both uart, so rx procedure has to be in ISR.

2. Tx should be ideally high so can I put a 10K pull up on tx line or use internal pull up

  • Hi, 

    you should start with either searching the forum for question like this, or googling. In google using "msp430 bit bang uart", i got the following link:

    http://nboddula.blogspot.de/2012/11/msp430-using-usi-for-uart-i2c.html

    another option would not purely bit banging but using the timer module. We have several examples for this, e.g. the msp430g2xx3_ta_uart9600.c from MSP430G2553 example code.

  • I think you meant bit banging. Bit banding is different. MSP430 cam do bit banging but cannot do bit banding.

    TI has lots of examples to do "software UART" or "Timer UART". But I am not aware of any TI example that can transmit and receive simultaneously. That seems to be what you want; and it can be done with the help of a Timer. As Leo suggested, search the internet and you may be able to find an example. Or, you can write one yourself. (If everyone searches the internet to find the wheel, wheel would never be invented ;)

  • I have serached some reference from internet & trimmed the code for my requirement.

    I have made a small algo for this. Can anyone look at it if this is correct. 

    Meanwhile I am writing the code for it.

    void uart_configure(void)
    {
        rx_pin_Input__FallingEdgeInterrupt__NoPullUp__NoPullDown
        tx_pin_Output_High
    }
    
    
    void rx_pin_ISR(void)
    {
        clear_isr_flag
        disable_interrupt
        
    /* communication start */    
        rx_start = 1;
    }
    
    
    
    void uart_tx(unit8_t data)
    {
    
    // start bit
        tx_pin = 0;      
        __delay_us(OneBitDelay);
        
    //data    
        for(cnt = 0 ; cnt < 8 ; cnt++)
        {
            if((data >> cnt) & 0x01)
            {
                tx_pin = 1;
            }
            else
            {
                tx_pin = 0;
            }
            __delay_us(OneBitDelay);
        }
        
    //stop bit    
        tx_pin = 1;      
        __delay_us(OneBitDelay);
        
    }
    
    
    
    uint8_t uart_rx(void)
    {
    /* initially data is rECeived here */    
        while(0 == rx_start);
        rx_start = 0;
        
    // IMP: Added so that pin can be sampled in mid of bit duration    
        __delay_us(OneBitDelay);
        __delay_us(OneBitDelay/2);         
        
    /* data */    
        for(cnt = 0 ; cnt < 8 ; cnt++)
        {
            if(rx_pin_high)
            {
                data = data | (1 << cnt);
            }
            __delay_us(OneBitDelay);
        }
        
    /* stop bit */    
        if(rx_pin_high)
        {
            __delay_us(OneBitDelay/2)
            return data;
        }
        else
        {
            __delay_us(OneBitDelay/2)
            return 0;
        }    
        
    }
    
    
    
    void main(void)
    {
        rx_start = 0;
        uart_configure();
        
        while(1)
        {
            data = uart_rx();
    
    /* tx the byte as sson as received */
            uart_tx(data);
    
    /* reenable rx pin interrupt */
            enable_rx_pin_isr
        }
            
    }

  • Here is some half-duplex uart code. I also have an assembly language version.

    // UART PROCESSING
    
    // #include  <signal.h>
    // #include  <io.h>
    #include <msp430.h>
    #include <legacymsp430.h>
    #include <string.h>
    
    #include "delay.h"
    #include "uart.h"
    #include "utils.h"
    
    static int bittime;
    static int parity;		// 0 == No parity, 1 == Odd parity, 2 == Even parity
    //static int bitSum;			// Sum of 1's bits in character (Rx parity not implemented)
    
    #define OUTBUFSIZE	32	// Code must change if this is not a power of 2
    #define OUTBUFSIZEMASK (OUTBUFSIZE-1)
    static struct {
    	unsigned int	p;		// intex of oldest entry in buffer
    	unsigned int	q;		// index of next empty slot in buffer
    	unsigned int	ch;		// character being transmitted
    	unsigned int	bitCount;
    	char	waiting;
    	char	buf[OUTBUFSIZE];
    } txData;
    
    #define NRX 20			// Maximum receive string length
    static struct {
    	unsigned int 	bitCount;
    	unsigned int 	ix;
    	unsigned int	ch;
    	unsigned int	numCh;	// Number of characters expected in mode 2
    	unsigned int	mode;	// See below
    	unsigned int	termCh;	// Message termination character (mode 1)
    	char	buf[NRX+1];		// Leave room for a string terminator; a zero.
    } rxData;
    /*
    	mode	Function
    	  0		Expecting one character
    	  1		Expecting a message terminated with <termCh> character.
    	  2		Expecting a message consisting of <numCh> characters
    */
    
    interrupt (TIMERA0_VECTOR) Timer_A0 (void)
    {
    int ch;
    	CCR0 += bittime;		// Schedule time of next interrupt
    	if (CCTL0 & CCIS0)		// CCIS0 is set by rxReady; selects input from CCI0B or P2.2 (Rx)
    	{	// Receive processing
    		if (CCTL0 & CAP)
    		{	// Capture mode - start bit edge detected
    			CCTL0 &= ~ CAP;			// Switch to compare mode
    			CCR0 += bittime / 2;	// The rising edge of the start pulse is at the end.
    		}
    		else
    		{	// Compare mode - compare occurs at the middle of each data bit.
    			rxData.ch >>= 1;
    			if (CCTL0 & SCCI)		// Is the received bit a 1?
    			{
    				rxData.ch |= 0x80;	// Yes
    				//bitSum++;			// Parity ignored for now
    			}
    			rxData.bitCount--;
    			if (rxData.bitCount == 0)
    			{	// All bits received
    				if (rxData.mode == 0)
    				{// mode == 0 : expecting a single character.
    					CCTL0 &= ~ CCIE;			// Disable CC0 interrupts
    					rxData.buf[0] = rxData.ch;
    					_BIC_SR_IRQ(CPUOFF);		// Return to normal mode.
    				}
    				else if (rxData.ix < NRX)
    				{
    					rxData.buf[rxData.ix++] = rxData.ch;
    					if (((rxData.mode == 1) && (rxData.ch == rxData.termCh)) ||
    						((rxData.mode == 2) && (rxData.ix == rxData.numCh)))
    					{	// Message received
    						CCTL0 &= ~ CCIE;
    						_BIC_SR_IRQ(CPUOFF);
    					}
    					else
    					{	// Message not yet received.
    						// Switch back to capture mode and look for the next start bit.
    						CCTL0 |= CAP;
    						rxData.bitCount = 8;
    					}
    				}
    				else
    				{	// Buffer overrun
    					CCTL0 &= ~ CCIE;			//	Disable CC0 interrupts
    					_BIC_SR_IRQ(CPUOFF);		// Return to normal mode.
    				}
    			}
    		}
    	}
    	else
    	{	// Transmit processing
    		if (txData.bitCount == 0)
    		{
    			if (txData.p == txData.q)
    			{	// Output buffer empty
    				CCTL0 &= ~ CCIE;		// Done with transmission, disable interrupts
    				_BIC_SR_IRQ(CPUOFF);
    				if (txData.waiting)
    				{
    					//_BIC_SR_IRQ(CPUOFF);	// Wake up waitForMsg()
    					txData.waiting = 0;
    				}
    				else
    					rxReady(0);				// Prepare to receive a single character
    			}
    			else
    			{
    				txData.bitCount = 10;
    				ch = txData.buf[txData.p];		// Get the next character
    				// Add mark stop bit and shift left to add space start bit.
    				txData.ch = (ch | 0x100) << 1;	// Parity not implimented
    				txData.p = (txData.p + 1) & OUTBUFSIZEMASK;
    				CCR0 = TAR + bittime;
    				CCTL0 = OUTMOD0 + CCIE;
    			}
    		}
    		else
    		{
    			if (txData.ch & 1)
    				CCTL0 &= ~OUTMOD2;	// Switch to "Set" output mode - Mark
    			else
    				CCTL0 |= OUTMOD2;	// Switch to "Reset" output mode - Space
    			txData.ch >>= 1;
    			txData.bitCount--;
    		}
    	}
    }
    
    void rxReady(int mode)
    {	// Get ready to receive a character
    /*
    	mode	Function
    	  0		Expecting one character
    	  1		Expecting a message terminated with <termCh> character.
    	  2		Expecting a message consisting of <numCh> characters
    */
    	rxData.ch = 0;		// Maybe not necessary but seems prudent
    	rxData.mode = mode;
    	rxData.ix = 0;
    	rxData.buf[0] = 0;
    	//bitSum = 0;			// Parity ignored
    	if (parity)
    		rxData.bitCount = 8;	// Ignore parity for now
    	else
    		rxData.bitCount = 8;
    	//		 Capture on falling edge
    	//			    Capture input on CCI0B (P2.2)
    	//						Outmode "Set"
    	//								Capture mode
    	//										Enable interrupt
    	CCTL0 = CM1 + CCIS0 + OUTMOD0 + CAP + CCIE;
    }
    
    char getCh(void)
    {
    char ch;
    // rxReady() must be invoked prior to this
    	if (rxData.bitCount == 0)
    	{
    		ch = rxData.ch;
    		rxData.ch = 0;
    		return ch;
    	}
    	else
    		return 0;
    }
    
    
    void waitForMsg(char *prompt, char *msg, char mode, char terminationCh, char numCh)
    {
    /*
    	Wait for a string of at most NRX characters.
    	mode		termCh	numCh
    	  0	- 	invalid
    	  1		  ch		NA		- string terminated by <teminationCh>
    	  2		NA		< NRX	- Returns exactly <numCh> characters
    */
    	txData.waiting = 1;
    	sendMsg(prompt, 0);
    	rxData.termCh = terminationCh;
    	rxData.numCh  = numCh;
    	_BIS_SR(CPUOFF);		// Sleep until message is transmitted
    	rxReady(mode);			// Switch to receive mode and wait for message
    	_BIS_SR(CPUOFF);				// Sleep until termination character is received.
    	rxData.buf[rxData.ix] = 0;		// Add string terminator
    	strcpy(msg, rxData.buf);
    	rxData.buf[0] = 0;
    	rxData.ch = 0;
    }
    
    int txBusy(void)
    {
    	if (CCTL0 & CCIS0)
    		return 0;	// CCIS0 set by rxReady
    	else
    		return 1;
    }
    
    void waitForTx(void)
    {
    	while(1)
    	{
    		volatile int busy = txBusy();
    		if (!busy)
    			break;
    	}
    	delayMilliseconds(2);
    }
    
    static int chOdd(char ch)
    {	// returns True if odd number of bits in character
    int i, n;
    	for (i = n = 0; i < 8; i++)
    	{
    		if (ch & 1)
    			n++;
    		ch >>= 1;
    	}
    	return n & 1;
    }
    
    void txByte(int ch)
    {
    int p;
    // Transmit a single character.
    	if (parity == 0)	// global var
    	{	// No parity
    		txData.bitCount = 10;
    		// Add mark stop bit and shift left to add space start bit.
    		txData.ch = (ch | 0x100) << 1;
    	}
    	else
    	{	// This implements 8 data bits plus parity
    		if (chOdd(ch) ^ (parity & 1))
    			p = 0x300;							// Add parity bit
    		else
    			p = 0x200;
    		// Add mark stop bit, parity bit and shift left for space start bit.
    		txData.ch = (ch | p) << 1;
    		txData.bitCount = 11;
    	}
    	CCR0 = TAR + bittime;
    	// Mode 1 - "Set". The output is set when the timer counts to TACCR0.
    	CCTL0 = OUTMOD0 + CCIE;
    }
    
    
    void sendMsg(char *msg, int nChars)
    {
    /*
    	Buffered uart output.
    	Note: 1) Parity is not implemented.
    		2) rxReady(0) is not invoked until after all characters have been transmitted.
    		3) 32 characters maximum
    */
    char ch, firstCh=0;
    int tp, p, q, k;	// number of characters transmitted
    
    	if (nChars == 0)
    		nChars = strlen(msg);
    	while (1)
    	{	// Wait for the buffer to empty
    		dint();
    		p = txData.p;
    		q = txData.q;
    		eint();
    		if (p == q)
    		{
    			delayMilliseconds(2);	// Wait for last character to be transmitted.
    			break;
    		}
    		delayMilliseconds(1);
    	}
    
    	firstCh = *msg++;	// get the first character
    	dint();	// Disabling interruptes in the middle of a character is probably ng.
    	for (k = 1; k < nChars; k++)
    	{
    		tp = (txData.q + 1) & OUTBUFSIZEMASK;
    		if (tp == txData.p)
    			break;			// output buffer full
    		else
    		{
    			ch = *msg++;
    			txData.buf[txData.q] = ch;
    			txData.q = tp;
    		}
    	}
    	eint();
    	txByte(firstCh);	// Send the first char to get things started
    }
    
    void initUart(int p, int baudrate)
    {// 0 == No parity, 1 == Odd parity, 2 == Even parity
    unsigned int x;
    
    	parity = p;
    	bittime = TARGET_FREQ / baudrate;
    	x = TARGET_FREQ - (bittime * baudrate);
    	if (x > (baudrate/2))
    		bittime += 1;
    }
    
    void send5Baud0x33(void)
    {
    int bt;
    
    	bt = bittime;
    	IE1 &= ~WDTIE;			// Disable WDT interrupts
    	TACTL |= ID0|ID1;		// Change timer frequency to 250 KHz (divide by 8). This assumes a 2 MHz clock
    	bittime = 50000;		// 0.2 seconds
    	txByte(0x33);
    	TACTL &= ~(ID0|ID1);	// Switch back to normal
    	bittime = bt;
    	IE1 |= WDTIE;
    }
    
    
    7356.uart.h

  • >Data can rx/tx simultaneously
    There are many examples but to learn what really is going on:

    1. UART data byte is 10bits, a pause or non active period is a high signal.
       so the start bit will always go from high to low.

    2. Reading Rx is always harder as you don't know when the signal will go low, and then it does
       you have to read the next 8bits at  exact moment starting with 1.5 bitrate from the falling edge of the start-bit
       as you should read the state ~mid-bit.

    3. bit-banging this while the MCU is doing something else can be problematic if it already have other ISR that hog  the mcu a little to long at times.

  • Tony Philipsson said:
    ...

    3. bit-banging this while the MCU is doing something else can be problematic if it already have other ISR that hog  the mcu a little to long at times.

    Utilizing the Timer Capture/Compare capability make this task a lot easier to handle. (But it still has its limits.)

**Attention** This is a public forum