39

Ok, I have one uart interface (TXD GPIO 14, RXD GPIO 15). I want at least one more uart interface.

Possible solutions:

  • Bit banging: Use two unrelated spare GPIOs. I understand that timing is a problem on a standard linux. Would it be reliable with very low baudrate?

  • Switching: RPI decides when to talk to which device. Using e.g. CD4066BC.

  • spi to 2 x uart bridge: Didn't find a suitable part (availability, price, dil package)

  • usb to uart: Expensive

Are there other options? I'm inclined to switching, if it can be done. What would you advise?

1

11 Answers 11

14

A USB UART, such as FTDI, isn't really expensive. All your other options sound like they will cost you more in parts and time than the ~$13 it might cost you, and be unreliable or slow. Just go for the fast and trouble-free option, such as:

http://www.dfrobot.com/index.php?route=product/product&product_id=147#.UOamLG-sh8E

Sparkfun sells one too. In fact, maybe you can just pull one out of some old USB device or buy one from a junk store that doesn't know what it does.

I messed with an SPI to UART adapter for an Arduino project, there was no existing library so I wrote my own. In the end it worked ok, but if I could have just dropped in a $15 part I would have. In fact given the time it cost me I should have just got a mega with 4 serial ports.

Alternatively if you want lots of serial ports you could look at RS485 serial, which is similar to 232 (though not compatible), which supports multi-drop, ie several interfaces over the one line.

2
  • 2
    This is also easies option from software point of view. FTDI has Linux driver support out of the box. All other option will require painstaking driver work.
    – Ber
    Mar 20, 2013 at 8:18
  • 1
    The cp2102 is my favorite usb uart chip. A quick amazon search reveals them for $6.99 (edit actually $1.50) with a cable included! Can't beat that!
    – benathon
    Apr 6, 2015 at 8:37
8

The Raspberry Pi 4 supports up to 4 UART interfaces now that need to be enabled by means of an device tree overlay. You can find how to do this and which Pins are used here for now:

https://www.raspberrypi.org/forums/viewtopic.php?t=244827

The RPi foundation is still preparing the documentation for this.

6

I found what you are looking for: an I2C/SPI slave to UART/IrDA/GPIO bridge.

They come in single and dual version (so 1 or 2 extra UARTs). They (NXP) also (for the other side in case needed) have I2C/SPI master to UART/IrDA/GPIO bridges.

More information can be found about these chips here and the master counterpart.

Maxim also has chips that do the exact same thing.

2
6

If you decide to skip adding extra hardware and just go the bit-banging route, this isn't as difficult as some picture it.

First off, your communication thread must go realtime:

#include<sched.h>

struct sched_param param;               
param.sched_priority = sched_get_priority_max(SCHED_FIFO);
if( sched_setscheduler( 0, SCHED_FIFO, &param ) == -1 )
{
        perror("sched_setscheduler");
        return -1;
}

From now on, your thread will not be pre-empted for 950ms out of each second*, unless it returns control willingly (through sched_yield(), or usleep()) in timely manner, which will not make it pre-empted ever. With 850MHz CPU your bit-banging loop will be running idle most of the time even at fastest speeds.

Now unfortunately the requirement to return control from time to time means while your thread is sleeping, whatever your "opposing party" sends, would be lost forever. But for that purpose you could use transmission control. Either allocate some more GPIO for CTS line which you pull down before yielding and back up upon restoring control:

  bcm2835_gpio_write(CTS_PIN, LOW);
  usleep(10);
  bcm2835_gpio_write(CTS_PIN, HIGH);

or (IMHO preferably) use XON/XOFF transmission control - send the XOFF character over RS232 before sleeping, XON after you resume operation. The default ASCII codes for these are '\x13' for XOFF/"stop sending" and '\x11' for XON/"resume sending".

Of course your remote device must obey these. If it doesn't, some data will be lost.

4

USB to UART bridges are cheap and readily available, but have really lousy timing characteristics. Newark sells an "Embedded Pi" board which has an STM32F ARM processor that you can write bare-metal code on. That chip has three UARTs on it, and I think they can go pretty fast; if you were to use one to communicate with the Raspberry Pi that would leave two available for other purposes. Disclaimer: I've bought one of these boards, but have as yet simply used the Raspberry Pi itself to handle by I/O needs directly.

If you want lots of slower UARTs, the STM32F on the Embedded Pi board could probably handle a fair number, especially if you're willing to write some Arm assembly language. If there are two groups of 16 I/O pins available on a single board it might be possible to have 16 simultaneous software UARTs all working at once at a pretty decent baud rate (have a periodic interrupt at 3x or 5x the baud rate which stores 16-bit latched values from the receive port to a buffer, and outputs 16-bit precomputed values from a buffer to the transmit port; if you do this, then provided the average servicing time for the software UARTs isn't too great, it won't matter if there is an occasional worst-case hit (e.g. all sixteen ports receiving a byte simultaneously).

This approach can actually work out remarkably efficiently for receiving, since the "common case" code doesn't even have to look at individual UARTs. Suppose that you're sampling data at 5x, and the last 47 bytes of the buffer are duplicated immediately preceding it. Assuming data is written to the buffer in ascending order, you can then check whether any byte has been fully received on any of the 16 channels by simply saying:

bytes_ready = (armed_flag & data[rxptr] & ~data[rxptr-47] & ~data[rxptr-46] & ~data[rxptr-45] & ~data[rx_ptr-44]);

If bytes_ready is zero, no data has been received. Otherwise, if e.g. bit 2 of bytes_ready is set, that means that a received data byte may be found in bit 2 of data[rx_ptr-40], data[rx_ptr-35], data[rx_ptr-30], etc. Once one grabs the data, clear bit 2 of armed_flag and arrange for it to get re-set after about 44 samples.

This approach will require a bit of work on those samples where a byte of data is fully received (and potentially a lot of work if all 16 channels have a byte of data arrive at once) but on most samples the amount of work will be very slight. If one had 64 I/O pins, one could handle up to 32 UARTs using this approach without adding any extra work to the "common" case.

1

A microcontroller like a Picaxe could take serial data in on one pin and output serial data on a certain pin appropriately. This would effectively give you more serial outputs if you were prepared to have to tell the Picaxe which pin to output on. It could also do the same, but in reverse, so it could receive serial data from multiple devices and send it to the Raspberry Pi. Another option could be to make connected devices require a qualifier. This means that Device 1 would have to receive the data 'd1', for example before it will listen to further data on the serial line. Device 2 could have 'd2' as its qualifier. This would mean that to say 'hello' to Device 1, you'd just have to send 'd1hello' on the UART line.

Picaxes are fairly cheap, you can get them over at http://www.techsupplies.co.uk/ and they come in numerous sizes with different numbers of pins and so on.

1

If the communication to the several UART slave devices does not need to occur in parallel, you could share the one available UART port between them. You could use transistors to enable only the RxD/TxD connections to the device you currently wish to talk to. These transistors can be controlled by other Raspberry Pi GPIO pins.

1

I had the same problem. I need connect to 2-4 GSM modules and I found hardware solution: http://www.instructables.com/id/SPI-to-4-x-UART-Bridge-MULTIUART/

This solution are base on PIC24FJ64GA306. You can replace PIC with Atmel mcu, but You must create new PCB :)

1

I'm using SC16IS752 IC which is SPI to 2xUART converter. It works well with Raspbian Stretch.

It is a bit more expensive than FTDI chip, but there are two uarts and I don't have to use precious USB port.

1

For any projects in which USB UART is not an option, additional UARTs must be implemented through the GPIO pins, and using a lower-powered Raspberry Pi (e.g., Pi Zero) other than the version 4, which is now equipped with 4 serials, adding extra serial interfaces could be done by using soft_uart. The module can convert any two of the digital pins into a soft serial interface (e.g., /dev/ttySOFT0).

Because UART is software-based, the communication needs to be undertaken in a low baud rate. Although the README suggests it to be 4800. I found a value lower and equal to 2400 is relatively stable.

Installing this requires compiling the module from source, it is suggested that user update Raspbian up to date and install kernel headers by

apt-get install raspberrypi-kernel-headers

to ensure the kernel version matches with the header version.

-2

Another solution is to move up to a PI4 apparently you can enable multiple uart pins on that one (did it myself) You can google the info up, it is mostly a config setting to enable the additional uart pins.

https://www.raspberrypi.org/forums/viewtopic.php?t=244827

This explains it. Apparently the new gpio pins in the pi4 basically allow to add 3 additional uart ports via the config.txt, for further details on how to set it up, check the link.

1
  • For a good answer you should explain how to setup it otherwise you risk to get downvotes.
    – Ingo
    Apr 28, 2020 at 10:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.