AD

Friday, 1 September 2017

Soft UART - A UART software implementation for Raspberry Pi


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.

6. References

2 comments:

  1. Hi Adriano,

    Works great on a Rpi 3 @ 9600 bps.

    I wonder if there is a way to load several modules to have
    more than one soft UART on different pins, like...

    /dev/ttySOFT0
    /dev/ttySOFT1
    ...

    I'mn no C wizard but tried to increase the "#define N_PORTS" in
    module.c to 2 and ls -l /dev/tty* shows two ports but
    when trying to open /dev/ttySOFT1 in minicom the Pi just hangs.

    I'm aware that the Pi have limited resources but since 9600 bps
    works fine even when all 4 cores are under 100% load (tested
    with stress utility) it will probably work fine with more than
    one soft UART if using lower speeds like 300/1200/2400 bps.

    Also wan't to say thanks for sharing your code!

    ReplyDelete
    Replies
    1. Hi Christer,

      It is good to know that you are making good use of the code.

      Unfortunately I haven't developed the module in a way that would enable it to provide more than one UART. The #define you've changed came from another project I used as a starting point.

      It is possible to modify the module to do what you described, but it would require more than just changing some parameters.

      Feel free to contribute to the project if you are interested.

      Kind regards,

      Adriano Marto Reis.

      Delete