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

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/serial0", 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");
		}
	}
Transmit string function
	uart_tx_string("Hello2");


//************************************
//************************************
//********** UART TX STRING **********
//************************************
//************************************
void uart_tx_string (string tx_string)
{
	if (uart0_filestream != -1)
		write(uart0_filestream, (char*)tx_string.c_str(), tx_string.length());		//Filestream, bytes to write, number of bytes to write
}
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/serial0

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:

UART Name

The SoCs used on the Raspberry Pis have two built-in UARTs, a PL011 and a mini UART.

/dev/serial0 is a symlink which always refers to the primary UART (if enabled). This is the UART assigned to the Linux console (which depends on the Raspberry Pi model).

/dev/serial1 is a symlink which always refers to the secondary UART (if enabled).

/dev/ttyS0 refers to the mini UART (Primary UART on RPi’s with wireless/Bluetooth module, e.g. RPi3, RPi Zero W)

/dev/ttyAMA0 refers to the PL011 (Primary UART on RPi’s without wireless/Bluetooth module)

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

Comments

  1. Leo

    3 years ago

    Which command do we use to compile the code in the tutorial?

  2. taha

    3 years ago

    Hello, I am using this code to send and receive data using a RPI and an Arduino. The write function works but the read doesn’t work, I get as a result rx_buff = 0, and sometimes it is -1 and it says that the resource temporarily unavailable.

    When using minicom, I can receive and send perfectly, but with this code the read has a problem. I tried using other macros for the c_oflag but it doesn’t really make a change.

    If someone had this problem before or can help me it would be really great.

    Thanks in advance.

  3. Ben Nguyen

    3 years ago

    Is it possible to plug the usb cable to the PI (via hub), with the TTL side going to another device?

    For example, how would you setup the pi to interrupt whenever data is sent by the other device? All the examples I’ve seen (C programs based on the WiringPi library) don’t seem to use interrupts!

  4. Adika Bintang Sulaeman

    8 years ago

    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?

    1. cisco

      3 years ago

      I have the same problem… You could fix it??

  5. mgarcia01752

    8 years ago

    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

    1. neha hule

      3 years ago

      Tried this. Doesn’t work.

  6. MArwen DHahri

    8 years ago

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

  7. Thomas Fodor

    8 years ago

    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.

    1. Adam

      8 years ago

      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…

  8. Entropia

    8 years ago

    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

  9. Dale

    8 years ago

    If you are using jessie version of the OS, try

    sudo systemctl stop getty.target

    This worked for me.

  10. Shameel Mohamed

    8 years ago

    Hi,
    Thanks for this very useful post.
    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?

  11. Marcel

    8 years ago

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

  12. Sandy Miranda

    9 years ago

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

  13. BASAK

    9 years ago

    Very Nice Post!! Thanks.

  14. mollymalone

    9 years ago

    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?

    1. martijn

      8 years ago

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

    2. neha hule

      3 years ago

      I disabled the serial. But it doesn’t work. When I enable it I receive garbage value like diamond and question mark.

    3. Rose White

      7 years ago

      disable serial from preferences gui

  15. rmarin

    9 years ago

    it works perfectly

  16. peter

    3 years ago

    I seem to be missing a bit of background. Is the UART hardware on the raspberrypi? I am trying to use another program that has, in the past, let me use pins 15 and 16 as TX/RX, – and do it via the device /dev/ttyAMA0. Does that mean I am not using the UART or, if it is hardware, is there a parrameter somewhere that can point “the UART” at those pins?

  17. Klemen Krajnc

    3 years ago

    where can I get the libraries used for uart?

  18. Krishna

    3 years ago

    How many UART connections can be made in the Pi..?? I want to use 2 UART ports..one for a GSM Module and other for GPS module. Is it possible to use both the modules with two UART connections?

  19. Matlo

    3 years ago

    “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”

    This actually is a bad idea as it will consume all available CPU time. Use a call to poll or select instead.

  20. oscar

    3 years ago

    How can save recived information in file ?

    1. rasppiLover

      3 years ago

      open another file using fopen, and write into it..

  21. jose

    3 years ago

    Hi I want to transmit a song through the UART . What changes should I make to the given program to do that?

  22. Miralay

    3 years ago

    Hi,

    we have one problem for about Rs232

    example I want give or take 1 data Pi to PC, I can send to PC no problem but I cant take Pc to Pi any data… if I send 30 times or 40 times after I can send PC to Pi… then it be normaly… but if I push caracter from keyboard after lock serial com… after I send again 30 or 40 times data then open again… after normaly…

    I tried resister then I use max3232 but no change… only I have problem for Pi to PC send wire…

    example some example I have from internet “Pi serial com. to ardiuno” but this not work…

    I will wait your helps …

    thanks a lot…

  23. Valter Espindola

    3 years ago

    HI there, I am trying to control serial stick bit (via CMSPAR) on raspberry pi B. No luck so far… any hints on this one?

  24. auzias

    3 years ago

    I used it and it works perfectly. However, as for me at least, I need to “sudo chmod a+rw /dev/ttyAMA0” at each every singel reboot.
    Thanks a lot! Nice tutorial! (-:

    1. Adam

      3 years ago

      That’s strange as its not something we’ve found to be needed

    2. auzias

      3 years ago

      Agreed ! I didn’t understand neither.
      And after some more tests I got just 8 bytes by reading a 25 bytes packets sent from an arduimu v3. I still don’t know why.
      What is read:
      0xBE F6 65 8C
      What I expect is something like :
      0xFE FE for the beginning of the packet

    3. Alex

      3 years ago

      For those with similar problems: you may want to add your user to the “dialout” group (sudo usermod -aG dialout USERNAME), verify with groups command.
      This will allow you to access the UART device without changing its permissions, since the every member of the dialout group is allowed to do so by default (see output of “ls -l /dev/ttyAMA0”).

    1. Stevem84

      3 years ago

      One of the UARTS is driven from the GPU clock which is variable and can cause problems as the baud rate will then vary. You can fix this by preventing the GPU clock from varying at the expense of power consumption.

Comments

Your email address will not be published. Required fields are marked *