Serial C And The Raspberry Pi
Written by Harry Fairhead   
Monday, 29 August 2016
Article Index
Serial C And The Raspberry Pi
Linux Presents A Problem
Setting up
Send and Recieve
Polling for data

Programming a serial interface using C is becoming increasingly important as embedded programming for the IoT takes off. Many small devices use a serial connection,  Find out how easy Linux makes accessing the serial interface.



The serial port is one of the oldest of ways of connecting devices together, but it is still very, very useful. Most machines, even very small machines, still have a serial interface somewhere - the Raspberry Pi has two!

A serial port provides a way of connecting devices together and provides a reasonably fast communication channel that can be used over a larger distance than most other connections such as USB. However, today its most common and important use is in making connections with small computers and simple peripherals. In this article the Raspberry Pi will be used an example, but the software approach works on any machine that runs Linux or Unix. 

But first, what is serial?

Serial Protocol

The serial protocol is very simple - it has to be because it was invented in the days when it was generated using electromechanical components, motors and the like.

It was invented to make early teletype machines work and hence you will often find abbreviations such as TTY used in connection with it. As the electronic device used to work with serial is called a Universal Asynchronous Receiver/Transmitter, the term UART is also often used. 

The earliest standards are V24 and RS232. Notice, however, that early serial communications worked between plus and minus 24V and later ones ±12V. Today's serial communications work at logic, or TTL levels 0 to 5V or 0 to 3.3V. This voltage difference is a problem we will return to later. What matters is that, irrespective of the voltage, the protocol is always the same.

For the moment let's concentrate on the protocol. 

As already mentioned the protocol is simple. The line rests high and represents a zero. When the device starts to transmit it first pulls the line low to generate a start bit. The width of this start bit sets the transmission speed - all bits are the same width as the start bit. After the start bit there are a variable number, usually seven or eight, data bits, an optional single parity bit, and finally one or two zero stop bits. 

Originally the purpose of the start bit was to allow the motors etc to get started and allow the receiving end to perform any timing corrections. The stop bits were similarly there to give time for the motors to come back to their rest position. In the early days the protocol was used at very slow speeds - 300 baud, i.e. roughly 300 bits per second, was considered fast enough. 

Today the protocol is much the same but there is little need for multiple stop bits and communications is often so reliable that parity bits are dispensed with. Transmission speeds are also higher - typically 9600 or 115200 baud.

To specify what exact protocol is in use, you will often encounter a short form 9600 8 data bits no parity one stop bit as 9600 8n1.  

You can see the letter A (01111101) transmitted using 8n1 in this logic analyzer trace: 


The first low is the start bit, then the eight dots show the ideal sampling positions for the receiver. The basic decoding algorithm for receiving serial is to detect the start of the start bit and then sample the line at the center of each bit time. notice that the final high on the right is the stop bit.

For a serial connection to work it is essential that the transmitter and the receiver are set to the same speed, data bits and parity. Serial interfaces most often fail because they are not working with the same settings. 

A logic analyzer with a serial decoder option is an essential piece of equipment if you are going to do anything complicated with serial interfacing. 

What is a baud?

Baud rate refers to the basic bit time. That is, 300 baud has a start bit that is 1/300s wide. For 9600 this means a bit is 1/9600 wide or roughly 104 microseconds. At 115200 baud a bit is 1/115200 or roughly 8.6 microseconds. 

Notice baud rate doesn't equate to speed of sending data because there is an overhead in stop, start and perhaps parity bits to include in the calculation.


A simple serial interface has a transmit pin Tx and a receive pin RX. That is, a full serial interface uses two wires for two-way communications. 

Typically you connect the Tx pin on one device to the Rx pin on the other and vice versa. The only problem is that some helpful manufacturers label the pins by what they should be connected to not what they are and you have to connect Rx to Rx and Tx to Tx - not really helpful. You generally need to check with a scope, logic probe or meter which pin is which if you are in any doubt. 

In addition to the Tx and Rx pins a full serial interface also has a lot of control lines. Most of these were designed to help with old fashioned teleprinters and they are not often used. For example, RTS - Request To Send is a line that it used to ask permission to send data from the device at the other end of the connection, CTS - Clear To Send is a line that indicates that it is okay to send data and so on. Usually these are set by the hardware automatically when the receive buffer is full or empty. 

You can use RTS and CTS as a hardware flow control. There is also a standard software flow control involving sending XON and XOFF characters to start and stop the transmission of data. 

For most connections between modern devices you can ignore these additional lines and just send and receive data. If you need to interface to something that implements a complex serial interface you are going to have to look up the details and hand-craft a program to interact with it. 

For the rest of this chapter we are going to work with Tx and Rx and ignore additional status and signaling lines. 

Modern system on a chip type devices like the Pi usually have one or more serial devices or UARTs built in. The Pi has two, a full function UART and a mini-UART. The difference is the size of the buffers and support for features. The mini-UART has one big problem in that it is tied to the system clock and, as this varies to deal with the demands of the processor, the mini-UART's baud rate changes. You can fix the system clock to a set frequency, but overall this is not a good idea. 

For this reason we will concentrate of the full UART, but the principles are the same for any UART.

There is a problem with making the connection to the Pi's RX and TX pins in that devices work at different voltages.  

PC-based serial ports usually use +13 to -13 and all RS232-compliant ports use a + to - voltage swing which is completely incompatible with the Pi and most other microprocessors which work at 5V or 3.3V.

If you want to connect the Pi to a PC then you need to use a TTL to RS232 level converter. In this case it is easier to use the PC's USB port as a serial interface with a USB to TTL level serial level converter. All you have to do is plug the USB port into the PC, install a driver and start to transmit data. 

The full UART is brought out onto pin 8 TX and pin 10 RX, corresponding to GPIO 14 and GPIO 15 in mode ALT0. At the moment these are set to ALT0 when Linux boots up, but there are discussions about changing this in which case you will have to explicitly set both GPIO lines to ALT0 to use the serial interface. 



Remember when you connect the Pi to another device TX goes to the other device's RX and RX goes to the other device's TX pin. Also remember that the signaling voltage is 0 to 3.3V. 

Last Updated ( Thursday, 01 December 2016 )