Jump to content
43oh

FR5969 UART Bluetooth


Recommended Posts

Hi guys, new around here and I am also a beginner (my only experience so far is withat needs your help to implement a UART interface for the FR5969. This is modified from an example from http://longhornengineer.com/projects/code/msp-430-launch-pad/uart-and-fifos/ that was implemented for the G2553. I tried to get it to work but can't seem to receive anything on my phone(Using BlueTerm). I am not sure if I missed anything out, or made a mistake and would like you guys to help me.

#include "msp430.h"
#include "uart.h"

#define LED BIT0
#define RXD BIT6
#define TXD BIT5


volatile unsigned int tx_flag;			//Mailbox Flag for the tx_char.
volatile unsigned char tx_char;			//This char is the most current char to go into the UART

volatile unsigned int rx_flag;			//Mailbox Flag for the rx_char.
volatile unsigned char rx_char;			//This char is the most current char to come out of the UART

/*uart_init
* Sets up the UART interface via USCI
* INPUT: None
* RETURN: None
*/
void uart_init(void)
{
	P2SEL0 |= RXD + TXD;					//Setup the I/O
	//P2SEL1 |= RXD + TXD;

    P1DIR |= LED; 						//P1.0 red LED. Toggle when char received.
    P1OUT |= LED; 						//LED off

	UCA1CTLW0 |= UCSSEL_2; 				//SMCLK
										//8,000,000Hz, 9600Baud, UCBRx=52, UCBRSx=0, UCBRFx=1
	UCA1BR0 = 52;                  		//8MHz, OSC16, 9600
	UCA1BR1 = 0;                   	 	//((8MHz/9600)/16) = 52.08333
	UCA1MCTLW = 0x10|UCOS16; 			//CBRFx=1,UCBRSx=0, UCOS16=1
	UCA1CTLW0 &= ~UCSWRST; 				//USCI state machine
	UCA1IE |= UCRXIE ; 					//Enable USCI_A1 RX interrupt

	rx_flag = 0;						//Set rx_flag to 0
	tx_flag = 0;						//Set tx_flag to 0

	return;
}

/*uart_getc
* Get a char from the UART. Waits till it gets one
* INPUT: None
* RETURN: Char from UART
*/
unsigned char uart_getc()				//Waits for a valid char from the UART
{
	while (rx_flag == 0);		 		//Wait for rx_flag to be set
	rx_flag = 0;						//ACK rx_flag
    return rx_char;
}

/*uart_gets
* Get a string of known length from the UART. Strings terminate when enter is pressed or string buffer fills
* Will return when all the chars are received or a carriage return (\r) is received. Waits for the data.
* INPUT: Array pointer and length
* RETURN: None
*/
void uart_gets(char* Array, int length)
{
	unsigned int i = 0;

	while((i < length))					//Grab data till the array fills
	{
		Array[i] = uart_getc();
		if(Array[i] == '\r')				//If we receive a \r the master wants to end
		{
			for( ; i < length ; i++)		//fill the rest of the string with \0 nul. Overwrites the \r with \0
			{
				Array[i] = '\0';
			}
			break;
		}
		i++;
	}

    return;
}

/*uart_putc
* Sends a char to the UART. Will wait if the UART is busy
* INPUT: Char to send
* RETURN: None
*/
void uart_putc(unsigned char c)
{
	tx_char = c;						//Put the char into the tx_char
	UCA1IE |= UCRXIE ; 					//Enable USCI_A1 TX interrupt
	while(tx_flag == 1);				//Have to wait for the TX buffer
	tx_flag = 1;						//Reset the tx_flag
	return;
}

/*uart_puts
* Sends a string to the UART. Will wait if the UART is busy
* INPUT: Pointer to String to send
* RETURN: None
*/
void uart_puts(char *str)				//Sends a String to the UART.
{
     while(*str) uart_putc(*str++);		//Advance though string till end
     return;
}

#pragma vector = USCI_TX_VECTOR_		//UART TX USCI Interrupt
__interrupt void USCI0TX_ISR(void)
{
	UCA1TXBUF = tx_char;				//Copy char to the TX Buffer
	tx_flag = 0;						//ACK the tx_flag
	UCA1IE = 0; 						//Turn off the interrupt to save CPU
}

#pragma vector = USCI_RX_VECTOR			//UART RX USCI Interrupt. This triggers when the USCI receives a char.
__interrupt void USCI0RX_ISR(void)
{
	rx_char = UCA1RXBUF;				//Copy from RX buffer, in doing so we ACK the interrupt as well
	rx_flag = 1;						//Set the rx_flag to 1

	P1OUT ^= LED;						//Notify that we received a char by toggling LED
}
 

For more information I have this in my main program

WDTCTL = WDTPW + WDTHOLD; 			//Stop WDT
    PM5CTL0 &= ~LOCKLPM5;			// Disable the GPIO power-on default high-impedance mode to activate
    				                // previously configured port settings
    CSCTL1 = DCOFSEL0 + DCOFSEL1;               // 8 MHz DCO (8 MHz is FRAM speed limit);Set DCO to 8Mhz

    uart_init();				//Initialize the UART connection

    __enable_interrupt();		        //Interrupts Enabled

I am also using a HC-05 Bluetooth module and have crossed the RXD and TXD.

Thank you very much in advance.

Link to post
Share on other sites

Hi @@mrinverter,

 

There are a few things that jump out at me:

 

1. Your GPIO setting looks incorrect to me. You are using P2.5 + P2.6 for UCA1TXD/RXD. However, looking at the FR5969 datasheet http://www.ti.com/lit/gpn/msp430fr5969 on p. 88 table 6-52 I see this for the pin setup:

 

post-34694-0-12116900-1412362190_thumb.jpg

 

You need to have P2SEL1 bit 5 and 6 set to 1, and P2SEL0 bit 5 and 6 set to 0. Right now, it looks like your code does the opposite:

P2SEL0 |= RXD + TXD;    //Setup the I/O
//P2SEL1 |= RXD + TXD;

So switch which line is commented out.

 

2. You are now using FR5969. This device has an eUSCI module (enhanced USCI) rather than USCI that was present on G2553. There are a few differences (for more detail please see the USCI to eUSCI migration guide http://www.ti.com/lit/pdf/slaa522).

 

One thing is the interrupt vector is different on eUSCI so this needs to be changed. It should be the USCI_A1_VECTOR, and you should also modify the ISR to have a switch statement to handle and respond to the correct values for UCA1IV because this is different. You may want to look at some FR5969 code examples for a demonstration of this.

 

Another thing is the baud rate generation. The eUSCI module provides a few more bits to get you better granularity and accuracy for generating baud rates - please check the FR5xx/6xx user's guide http://www.ti.com/lit/pdf/slau367 Table 21-5 for a list of recommended settings to generate different baud rates, and note the slight difference - you should change your code to match this (notably UCBSx = 0x49).

 

There may be other things to change, but hopefully these tips will help!

Regards,

Katie

Link to post
Share on other sites

I started typing a reply about checking for USART/USI/USCI differences and suggesting looking at the MSP430Ware examples. (Nowhere near as detailed as Katie's, of course.)

 

However, then I checked the spec pages and saw they were both USCI. I didn't even notice the subtle eUSCI change! I guess that reinforces the point. It's usually the first thing I struggle with and starting from a working example usually speeds things up for me. Going back to the USART on an AFE253 was particularly painful recently.

Link to post
Share on other sites

Alright I have taken the advice and tried to understand how to use the eUSCI Interrupt Vectors, however I find it hard to understand and have instead made it worse.

Was wondering if anyone can help me with this?

Or perhaps point me to something easier to understand, thanks.
 

#include "msp430.h"
#include "uart.h"

#define RXD BIT6
#define TXD BIT5

volatile unsigned int tx_flag = 0;			//Mailbox Flag for the tx_char.
volatile unsigned char tx_char;			//This char is the most current char to go into the UART

volatile unsigned int rx_flag = 0;			//Mailbox Flag for the rx_char.
volatile unsigned char rx_char;			//This char is the most current char to come out of the UART

/*uart_init
* Sets up the UART interface via USCI
* INPUT: None
* RETURN: None
*/
void uart_init(void)
{
	// Configure GPIO
	P2SEL1 |= RXD | TXD;                    // USCI_A1 UART operation
	P2SEL0 &= ~(RXD | TXD);

    // Configure USCI_A1 for UART mode
    UCA1CTLW0 = UCSWRST;                      // Put eUSCI in reset
    UCA1CTLW0 |= UCSSEL__SMCLK;               // CLK = SMCLK
    // Baud Rate calculation
    // 8000000/(16*9600) = 52.083
    // Fractional portion = 0.083
    // User's Guide Table 21-4: UCBRSx = 0x04
    // UCBRFx = int ( (52.083-52)*16) = 1
    UCA1BR0 = 52;                             // 8000000/16/9600
    UCA1BR1 = 0x00;
    UCA1MCTLW |= UCOS16 | UCBRF_1;
    UCA1CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
    UCA1IE |= UCRXIE;                         // Enable USCI_A1 RX interrupt

    __bis_SR_register(LPM3_bits | GIE);       // Enter LPM3, interrupts enabled

    UCA1IFG = ~(UCRXIFG + UCTXIFG);			//Clear Flags

	return;
}

/*uart_getc
* Get a char from the UART. Waits till it gets one
* INPUT: None
* RETURN: Char from UART
*/
unsigned char uart_getc()				//Waits for a valid char from the UART
{
		while(!(UCA1IFG & UCRXIFG));		 //Wait for rx_flag to be set
		rx_flag = 0;						//ACK rx_flag
	    return rx_char;
}

/*uart_gets
* Get a string of known length from the UART. Strings terminate when enter is pressed or string buffer fills
* Will return when all the chars are received or a carriage return (\r) is received. Waits for the data.
* INPUT: Array pointer and length
* RETURN: None
*/
void uart_gets(char* Array, int length)
{
	unsigned int i = 0;

	while((i < length))					//Grab data till the array fills
	{
		Array[i] = uart_getc();
		if(Array[i] == '\r')				//If we receive a \r the master wants to end
		{
			for( ; i < length ; i++)		//fill the rest of the string with \0 nul. Overwrites the \r with \0
			{
				Array[i] = '\0';
			}
			break;
		}
		i++;
	}

    return;
}

/*uart_putc
* Sends a char to the UART. Will wait if the UART is busy
* INPUT: Char to send
* RETURN: None
*/
void uart_putc(unsigned char c)
{
	tx_char = c;								//Put the char into the tx_char
	UCA1IE |= UCRXIE; 							//Enable USCI_A1 TX interrupt
	while(!(UCA1IFG & UCTXIFG));				//Have to wait for the TX buffer
	tx_flag = 1;								//Reset the tx_flag
	return;
}

/*uart_puts
* Sends a string to the UART. Will wait if the UART is busy
* INPUT: Pointer to String to send
* RETURN: None
*/
void uart_puts(char *str)				//Sends a String to the UART.
{
     while(*str) uart_putc(*str++);		//Advance though string till end
     return;
}

#pragma vector = USCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void) {
	switch(__even_in_range(UCA1IV, USCI_UART_UCTXCPTIFG)) {
    	case USCI_NONE: break;
    	case USCI_UART_UCRXIFG:
    		rx_char = UCA1RXBUF;						//Copy from RX buffer, in doing so we ACK the interrupt as well
    		rx_flag = 1;								//Set the rx_flag to 1
    		break;
    	case USCI_UART_UCTXIFG:
    		UCA1TXBUF = tx_char;						//Copy char to the TX Buffer
    		tx_flag = 0;								//ACK the tx_flag
    		__bic_SR_register_on_exit(CPUOFF);       	// Exit LPM0 on reti
    		break;
    	case USCI_UART_UCSTTIFG: break;
    	case USCI_UART_UCTXCPTIFG: break;
  }
}
Link to post
Share on other sites

I'm not entirely sure what you're doing with the UART once you have it set up. I can't see any code listed above that actually sends or receives anything. Apologies if I'm stating the obvious, but I'd suggest that you do the following:

  • Take some sample code (whether TI's or zeke's) in its entirety and get that running.
  • Debug it. Set breakpoints. Try to work out what it's doing.
  • Strip it down so it has only what you need.
  • Get something really simple going. (e.g. when you press the onboard button it sends "Hello" to your phone.)
  • Work slowly from there, testing each simple step.

I find borrowing and then understanding other people's code (along with reading "MSP430 Microcontroller Basics") is the best way to learn.

Link to post
Share on other sites

Hi Fred,

Apologies for the lack of information provided, I have debugged and tried various configuration and am fairly sure the issue with this is that I do not fully understand how the interrupts work
(I can't seem to find good documentation I can understand.) What happens in the main is fairly simple:

 

  • uart_puts sends a string of character; this can be used to output a message
    (e.g. uart_puts((char *)"Welcome"); // Prints a welcome message)
  • uart_getc gets a character input, this can be used as a trigger
    (e.g. unsigned char c = uart_getc(); //Retrieves input character; c can then trigger a preset condition based on input)
  • uart_putc does the same thing as uart_puts but prints a single character instead
  • uart_gets does the same thing as uart_getc but get a whole string of character instead

I have tested this before on an F2274 and it has worked. Anyways thanks for the advice, I'll keep it in mind.
Also, thank you Zeke for providing your source code; I'll see how I can implement it.

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...