Take the 2-minute tour ×
Raspberry Pi Stack Exchange is a question and answer site for users and developers of hardware and software for Raspberry Pi. It's 100% free, no registration required.

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?

share|improve this question
    
+1 Interesting question. –  Jivings Nov 4 '12 at 18:18
add comment

5 Answers

up vote 3 down vote accepted

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.

share|improve this answer
    
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 '13 at 8:18
add comment

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.

share|improve this answer
add comment

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.

share|improve this answer
add comment

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.

share|improve this answer
add comment

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.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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