If you are running Raspbian or similar then the UART will be used as a serial console.  Using a suitable cable, such as the TTL-232R-3V3-WE, you can connect it to your PC and using some simple terminal software set to 115200-8-N-1 use the command line interface to the Raspberry Pi in the same way as if you we're using a keyboard and screen connected to it.  However that's no use if you want to use the UART interface for your own application running on the RPi.

Turning off the UART functioning as a serial console

See here.

Using The UART In Your C Code

(This is based on the example code given here).

Update from Maurice Garcia in the comments – If you are using PI model 3 do not use /dev/ttyAMA0 this is assigned to bluetooth, use /dev/ttyS0. 

Headers required

#include <stdio.h>
#include <unistd.h>			//Used for UART
#include <fcntl.h>			//Used for UART
#include <termios.h>		//Used for UART
Setting Up The UART

	//-------------------------
	//----- SETUP USART 0 -----
	//-------------------------
	//At bootup, pins 8 and 10 are already set to UART0_TXD, UART0_RXD (ie the alt0 function) respectively
	int uart0_filestream = -1;
	
	//OPEN THE UART
	//The flags (defined in fcntl.h):
	//	Access modes (use 1 of these):
	//		O_RDONLY - Open for reading only.
	//		O_RDWR - Open for reading and writing.
	//		O_WRONLY - Open for writing only.
	//
	//	O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
	//											if there is no input immediately available (instead of blocking). Likewise, write requests can also return
	//											immediately with a failure status if the output can't be written immediately.
	//
	//	O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.
	uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);		//Open in non blocking read/write mode
	if (uart0_filestream == -1)
	{
		//ERROR - CAN'T OPEN SERIAL PORT
		printf("Error - Unable to open UART.  Ensure it is not in use by another application\n");
	}
	
	//CONFIGURE THE UART
	//The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
	//	Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
	//	CSIZE:- CS5, CS6, CS7, CS8
	//	CLOCAL - Ignore modem status lines
	//	CREAD - Enable receiver
	//	IGNPAR = Ignore characters with parity errors
	//	ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for bianry comms!)
	//	PARENB - Parity enable
	//	PARODD - Odd parity (else even)
	struct termios options;
	tcgetattr(uart0_filestream, &options);
	options.c_cflag = B9600 | CS8 | CLOCAL | CREAD;		//<Set baud rate
	options.c_iflag = IGNPAR;
	options.c_oflag = 0;
	options.c_lflag = 0;
	tcflush(uart0_filestream, TCIFLUSH);
	tcsetattr(uart0_filestream, TCSANOW, &options);
Transmitting Bytes

	//----- TX BYTES -----
	unsigned char tx_buffer[20];
	unsigned char *p_tx_buffer;
	
	p_tx_buffer = &tx_buffer[0];
	*p_tx_buffer++ = 'H';
	*p_tx_buffer++ = 'e';
	*p_tx_buffer++ = 'l';
	*p_tx_buffer++ = 'l';
	*p_tx_buffer++ = 'o';
	
	if (uart0_filestream != -1)
	{
		int count = write(uart0_filestream, &tx_buffer[0], (p_tx_buffer - &tx_buffer[0]));		//Filestream, bytes to write, number of bytes to write
		if (count < 0)
		{
			printf("UART TX error\n");
		}
	}
Receiving Bytes

Because O_NDELAY has been used this will exit if there are no receive bytes waiting (non blocking read), so if you want to hold waiting for input simply put this in a while loop


	//----- CHECK FOR ANY RX BYTES -----
	if (uart0_filestream != -1)
	{
		// Read up to 255 characters from the port if they are there
		unsigned char rx_buffer[256];
		int rx_length = read(uart0_filestream, (void*)rx_buffer, 255);		//Filestream, buffer to store in, number of bytes to read (max)
		if (rx_length < 0)
		{
			//An error occured (will occur if there are no bytes)
		}
		else if (rx_length == 0)
		{
			//No data waiting
		}
		else
		{
			//Bytes received
			rx_buffer[rx_length] = '\0';
			printf("%i bytes read : %s\n", rx_length, rx_buffer);
		}
	}
Closing the UART if no longer needed

	//----- CLOSE THE UART -----
	close(uart0_filestream);

Using minicom on the UART

Install minicom:

sudo apt-get install minicom

Running minicom:

minicom -b 115200 -o -D /dev/ttyAMA0

To test the UART is working you can simply link the TX and RX pins to each other and verify minicom receives what you type.

Troubleshooting UART Problems

The above code works (we've used it for TX and RX). If you can't get to to work for you and you've been through the steps to release the UART from being used for the console try the following:

Permissions

This command will set read and write access permissions for all users on the UART – it shouldn't be needed but can be used just to be sure there is not a permissions problem:


sudo chmod a+rw /dev/ttyAMA0
Baud Rate Error

Try using a slower BAUD rate (or a single 0xFF byte which only has the start bit low) and see if it works.  We had a problem using 115k2 baud rate where our microcontroller communicating with the RPi could hit 113636baud or 119047baud.  113636baud had the lowest error margin so we used it and TX from the RPi being received by the microcontroller worked fine.  However when transmitting to the RPi nothing was ever received. Changing the microcontroller to use 119047baud caused RX to work. We then tested the RPi transmitting a byte of 0x00 and measured the low state on a scope we got 78uS, showing an actual baud rate of 115384 from the RPi (8bits + the start bit all low).  This was odd as 113636baud still had to lower error margin but that was the finding.

Are you over or under clocking the RPi? If so do you need to adjust the baud rate to compensate for this?

General UART Programming Resources

http://www.tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html





USEFUL?
We benefit hugely from resources on the web so we decided we should try and give back some of our knowledge and resources to the community by opening up many of our company’s internal notes and libraries through mini sites like this. We hope you find the site helpful.

Please feel free to comment if you can add help to this page or point out issues and solutions you have found, but please note that we do not provide support on this site. If you need help with a problem please use one of the many online forums.