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;
	//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)
		printf("Error - Unable to open UART.  Ensure it is not in use by another application\n");
	//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
			//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 -----

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:


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


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.

  • rmarin

    it works perfectly

  • mollymalone

    I’m trying to use this code for a College project, I have stopped the UART console comms by removing ttyAMA0 references from /boot/cmdline.txt and /etc/inittab, but when I run the tx code I got stuck on “Error – Unable to open UART. Ensure it is not in use by another applicationn”, is there any suggestion on this?


    Very Nice Post!! Thanks.

  • Sandy Miranda

    How to build and run this? I’m not getting

  • Marcel

    how ots possible to read a complete string until a lineending ?

  • Shameel Mohamed

    It’s not working for me.
    I tried the same program in raspberry pi running raspbian os, I am getting an error like “expected initializer before ‘open'”. How can I solve this?

  • Dale

    If you are using jessie version of the OS, try

    sudo systemctl stop getty.target

    This worked for me.

  • Entropia

    I followed this tutorial but quickly ran into problems. The problem was that for every eight bytes that I received the first got lost. I did remove UART console logins as per the instructions at the start of the page but it turns out that inittab needed modifying too (remove the getty ttyAMA0 respawning). So if you have problems similar to mine, check inittab!

    See full discussion here: https://www.raspberrypi.org/forums/viewtopic.php?f=33&t=134752

  • Thomas Fodor

    I don’t understand. You don’t use WiringPi, OR BCM2835. Instead you include 3
    libraries and comment they are for UART. I’m not criticizing you, I am just
    frustrated with trying to figure out how to use the UART on the Pi, while every
    single source I find not only uses different methods, but uses completely
    different libraries. Why? I am completely stagnant.

  • We tend to try and use standard generic Linux C libraries whenever possible so our knowledge and code is as portable as possible. Its not necessarily the easiest approach in all circumstances, but an upside is it removes the problems of relying on less “standard” 3rd party libraries that may one day no longer be well maintained etc. For us that’s really important and worth a bit of extra work or complexity at times, but not all may agree…

  • MArwen DHahri

    i cant send via tx alwayes i have the “uart tx error ” can any one help me plz

  • Maurice Garcia

    Wanted to update this a how to test. If you are using PI model 3, you need to do 2 things.

    1.Do not use /dev/ttyAMA0 this is assign to bluetooth, use /dev/ttyS0.
    2.You need to disable serial via the GUI. I did not research how to do this via CLI.

    minicom -b 115200 -o -D /dev/ttyS0
    sudo chmod a+rw /dev/ttyS0

  • martijn

    sudo raspi-config –>advance settings –> serial –> disable–>reboot and it works!

  • Adika Bintang Sulaeman

    I have a problem with this example. Everything works OK, i.e. open(), write(), but a problem comes when I try to read() (note: on the Receiving Bytes section). I printf() the errno value and the string of errno as well, and it is said that “errno: 11, string: Resource temporarily unavailable”. Does anybody here know what’s wrong with this?

  • Rose White

    disable serial from preferences gui