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
4 years ago
Which command do we use to compile the code in the tutorial?
4 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.
4 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!
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?
4 years ago
I have the same problem… You could fix it??
9 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
4 years ago
Tried this. Doesn’t work.
9 years ago
i cant send via tx alwayes i have the “uart tx error ” can any one help me plz
9 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.
9 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…
9 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 years ago
If you are using jessie version of the OS, try
sudo systemctl stop getty.target
This worked for me.
9 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?
9 years ago
how ots possible to read a complete string until a lineending ?
10 years ago
How to build and run this? I’m not getting
10 years ago
Very Nice Post!! Thanks.
10 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?
9 years ago
sudo raspi-config –>advance settings –> serial –> disable–>reboot and it works!
4 years ago
I disabled the serial. But it doesn’t work. When I enable it I receive garbage value like diamond and question mark.
8 years ago
disable serial from preferences gui
10 years ago
it works perfectly
4 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?
4 years ago
where can I get the libraries used for uart?
4 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?
4 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.
4 years ago
How can save recived information in file ?
4 years ago
open another file using fopen, and write into it..
4 years ago
Hi I want to transmit a song through the UART . What changes should I make to the given program to do that?
4 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…
4 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?
4 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! (-:
4 years ago
That’s strange as its not something we’ve found to be needed
4 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
4 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”).
4 years ago
i tried using this programme but it is not working
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.