1. Introduction
I am working on a personal project that requires two serial ports on a Raspberry Pi board. I used the embedded serial port plus a USB dongle for a while, but then I started wondering if there was a way of implementing a UART through one of the spare GPIO pins.
I searched the subject for a while and found many people wanting a software-based serial port on a Raspberry Pi. However, I could not find any ready-to-use solution - at least not in the way I wanted.
So I decided to create my own solution. For those who are not interested in the rest this article, here is the link:
2. Research
As I said, I searched for some ready-to-use solution. I found some examples of bit banging, but I wanted a kernel module able to emulate a TTY device. That would enable me to use this device with any application, such as minicom or gpsd.
I found the project RpiSoft-UART, which provides a character device able to transmit and receive data almost in the same way as a UART does. It still does not implement a TTY interface. For example, it does not allow changing the baud rate without reloading the module.
I also found the article Writing a Linux Kernel Module — Part 2: A Character Device. It is an excellent article describing how to implement a character device. It helps to understand the ideas behind the code written for RpiSoft-UART RpiSoft-UART.
Another interesting source of information was chapter TTY Drivers of the book Linux Device Drivers, 3rd Edition by Greg Kroah-Hartman, Alessandro Rubini, Jonathan Corbet. It explains how to implement a TTY device in details. It is outdated, as the TTY module structures have changed since the kernel 3.10. But it is still a good reading.
In the end, I found the project raspicomm-module. It is a kernel module for the RaspiComm extension board for Raspberry Pi. The hardware provides additional serial ports for a Raspberry Pi board, and the kernel module provides the software interfaces to the hardware as a TTY device. That helped to figure out the parts that were missing in the other references.
3. Implementation
In the end of the day, implementing a kernel module is a matter of filling the correct boilerplate - there are certain functions that the kernel expects to find in the module.
I tried to keep the implementation as simple as possible. There are three two important files:
- module.c: Implements the interface between the module and the kernel (by filling the boilerplate).
- raspberry_soft_uart.c: Implements the bit banging itself. A high-resolution timer is set according to the desired baud rate. Every time the timer goes off, a bit is written and/or read to/from the GPIO pins.
raspberry_gpio.c: Implements the interface between the module and the GPIO, more or less as WiringPi.
4. Testing
The easiest way of testing it is connecting the selected Soft UART pins to the embedded UART pins. It would be like this:
GPIO 17 (pin 11) --- RXD0 (pin 8)
GPIO 27 (pin 13) --- TXD0 (pin 8)
There are more instructions on how to test it using minicom at
5. Conclusion
My kernel module seems to work more or less as expected. I noticed that there are some communication errors in the reception, especially when the baud rate is faster than 4800 bps or when the CPU usage is high. The transmission works just fine.
I am not sure of what could be done to improve the reception, but I am open to suggestions.