What is UART?
UART stands for Universal Asynchronous Receiver/Transmitter. Embedded systems and microcontrollers mostly use UART as a form of device-to-device hardware communication protocol. Among the available communication protocols, UART uses only two wires for its transmitting and receiving ends. UART is a hardware communication protocol that uses asynchronous serial communication with configurable speed. Asynchronous means there is no clock signal to synchronize the output bits from the transmitting device going to the receiving end.
The two signals of each UART device are named:
- Transmitter (Tx)
- Receiver (Rx)
![UART Connection](/images/raspi_uart/uart_bus.jpg)
For UART and most serial communications, the baud rate needs to be set the same on both the transmitting and receiving device. The baud rate is the rate at which information is transferred to a communication channel. In the serial port context, the set baud rate will serve as the maximum number of bits per second (bps) to be transferred. 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 1000000, 1500000 bps are the common baud rate.
In UART, the mode of transmission is in the form of a packet. The piece that connects the transmitter and receiver includes the creation of serial packets and controls those physical hardware lines. A packet consists of a start bit, data frame, a parity bit, and stop bits.
![UART packet](/images/raspi_uart/uart_packet.png)
UART setup on Raspberry Pi
To use the dedicated UART pins on the raspberry pi 1, firstly the two pins have to be re-configured because their default application is for debugging.
To do this, we need to edit two files: /boot/cmdline.txt
and /etc/inittab
.
We can backup these files if you want to return to the default configuration after finishing using UART:
$ sudo cp /boot/cmdline.txt /boot/cmdline.bak
$ sudo cp /etc/inittab /etc/inittab.bak
Now, we can edit file:
$ sudo nano /boot/cmdline.txt
Remove console=ttyAMA0,115200
and kgdboc=ttyAMA0,115200
configuration parameters from the /boot/cmdline.txt
configuration file, save and quit. Continue to edit next file:
$ sudo nano /etc/inittab
Comment the last line on the /etc/inittab
file. Put a #
before T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100
, save and quit.
Now the RXD (GPIO15) and TXD (GPIO14) pins of Raspberry Pi are available for general UART using, last but not least, remember to connect ground pin.
![Raspberry Pi UART](/images/raspi_uart/raspi_uart.jpg)
Code
You can check how to use the UART in my robot vision project, refer to Main.c file for how to use (uart function runs on a separate thread which I create).
Here is the code of uart part:
uart.c:
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include "Uart.h"
int uart0_filestream = -1;
void UART_Init()
{
//-------------------------
//----- SETUP USART 0 -----
//-------------------------
//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):
// 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
// PARENB - Parity enable
// PARODD - Odd parity (else even)
struct termios options;
tcgetattr(uart0_filestream, &options);
options.c_cflag = B115200 | CS8 | CLOCAL | CREAD;// Set baud rate as 115200
options.c_iflag = IGNPAR | ICRNL;
options.c_oflag = 0;
options.c_lflag = 0;
tcflush(uart0_filestream, TCIFLUSH);
tcsetattr(uart0_filestream, TCSANOW, &options);
}
void UART_TX_Char(char tx_buffer)
{
if (uart0_filestream != -1)
{
int count =write(uart0_filestream, &tx_buffer, 1);
if (count < 0)
{
printf("UART TX error\n");
}
}
}
void UART_TX()
{
//----- 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");
}
}
}
int UART_RX()
{
int check = 0;
if (uart0_filestream != -1)
{
// Read up to 255 characters from the port if they are there
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)
{
}
else
{
//Bytes received
rx_buffer[rx_length] = '\0';
printf("%i bytes read : %s\n", rx_length, rx_buffer);
}
}
return(check);
}
void UART_Close()
{
close(uart0_filestream);
}
uart.h
#ifndef __UART_H
#define __UART_H
unsigned char rx_buffer[256];
void UART_Init();
void UART_TX_Char(char a);
void UART_TX();
int UART_RX();
void UART_Close();
#endif