Arduino and Raspberry Pi Serial Communication

Today’s the last day of my summer holiday, and I had some free time on my hands. So I decided to see if I could get my Arduino Uno and Raspberry Pi to talk to each other. It turned out the task was even easier than my previous Pi to RS-232 project – all that was needed between the two devices was some jumper wire and two 1 kOhm resistors to form a voltage divider between Arduino TX pin and Pi RX pin – Arduino understands Pi’s 3.3V signal levels just fine so Pi TX to Arduino RX needed no voltage shifting at all.

IMPORTANT UPDATE! It turns out that the RX pin on the Arduino is held at 5V even when that pin is not initialized. I suspect it is due to the fact that the Arduino is programmed via these same pins every time you flash it from Arduino IDE, and there are external (weak) pullups to keep the lines to 5V at other times. So the method described below may be risky – I suggest either add a resistor in series to the RX pin, or use a proper level converter (see this post for details how to accomplish that). And if you do try the method below, never connect the Pi to Arduino RX pin before you have already flashed the program to Arduino, otherwise you may end up with a damaged Pi!!!

Setting Raspberry Pi up for serial communications

In order to use the Pi’s serial port for anything else than as a console, you first need to disable getty (the program that displays login seen) by commenting the serial line out of Pi’s /etc/inittab:

1:2345:respawn:/sbin/getty 115200 tty1
# Line below commented out
# 2:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100
3:23:respawn:/sbin/getty 115200 tty3
4:23:respawn:/sbin/getty 115200 tty4
5:23:respawn:/sbin/getty 115200 tty5
6:23:respawn:/sbin/getty 115200 tty6

If you don’t want the Pi sending stuff over the serial line when it boots, you can also remove the statements console=ttyAMA0,115200 and kgdboc=ttyAMA0,115200 from /boot/cmdline.txt. You’ll need to reboot the Pi in order for the changes to take effect.

If you have a 3.3V compatible serial adapter in your computer (or a MAX3232 and normal RS-232 adapter, in which case see my tutorial on building one), it’s a good time to try out if everything is working on the Pi side. Install minicom (sudo apt-get install minicom) and attach is to serial terminal:

minicom -b 9600 -o -D /dev/ttyAMA0

Then open Putty or similar serial terminal on PC side. Everything you type into minicom should appear in the serial terminal on PC side, and characters typed to serial terminal should appear on minicom.

Connecting Arduino Uno to Raspberry Pi

There’s basically two ways to link the Arduino to the Pi. Easier route would be to just plug Arduino into the Pi via USB. The USB to serial bridge should be automatically recognized and be available at /dev/ttyACM0. But if you want to do it the hard way like I did, you can also connect the Pi GPIO pins (seen on the right, 3.3V not needed this time) to Arduino:

  1. Connect grounds of both devices (triple check first that they are the grounds!)
  2. Connect Pi TX to Arduino RX (series resistor recommended, only connect after flashing, never flash with Pi connected!)
  3. Connect Arduino TX to Pi RX via a voltage devider

As a voltage divider, I used a 1 kOhm resistor between the Arduino TX and Pi RX, and another 1 kOhm between Pi RX and ground. That way, the 5V Arduino signal voltage is effectively halved. Connect the resistor ladder first, and then the Pi RX between the two resistors, so there’s at no point a voltage over 3.3 volts that could damage the Pi! You can see the connection in action here.

Communication between Pi and Uno

For RaspPi side, I’d recommend minicom (see the command-line above) for testing, and pySerial (sudo apt-get install python-serial) for interaction. Using Python, you can easily make the Pi do lots of interesting things when commands are received from Arduino side. Here’s a simple ROT-13 application that works with the GPIO serial interface:

#!/usr/bin/env python

import serial
import string

rot13 = string.maketrans( 
    "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz", 
    "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")

test=serial.Serial("/dev/ttyAMA0",9600)
test.open()

try:
    while True:
		line = test.readline(eol='\r')
		test.write(string.translate(line, rot13))
		
except KeyboardInterrupt:
    pass # do cleanup here

test.close()

For the Arduino, you can you the serial capabilities of Arduino environment. Here’s a simple program that echoes back everything that is sent from Pi to Arduino:

void setup() {
  Serial.begin(9600);
}

void loop() {
  int incomingByte;
  
  if(Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();

    // echo
    Serial.write(incomingByte); 
  }
}

Note that you shouldn’t use these programs together, or nothing happens (and you won’t see anything either) – Pi side programs can be tested with a PC serial adapter and Putty, and Arduino side programs with minicom running in the Pi.

That’s it for this time. Now that I have the two things communicating, I think I’ll do something useful with the link next. Maybe a simple Arduino “HDMI shield” using RaspPi!

34 Comments or trackbacks to Arduino and Raspberry Pi Serial Communication

Julian:
September 23, 2012 at 12:49

Do you know if it’s actually safe to program the Arduino while it’s connected to the Raspberry Pi like this? As this happens via the TX/RX pins, you get 5V on the RX pin of the Arduino, thus 5V on the TX pin of the Raspberry Pi.

But anyways, did the same thing and my Raspberry Pi still works ;)

reply

jokkebk says:
September 23, 2012 at 22:27

Extremely observant note! I had not realized this. And actually, when I measured, the pin is at 5V even when the pin is set as input and no internal pullup! I suspect it has a weak external pullup due to the double function as programming interface.

After noticing this, the method described in this article doesn’t seem so good anymore. A series resistor (I don’t know if 1k would still work) might be a good idea, or a proper level conversion buffer.

Thanks for pointing it out, I updated the text above to include a warning.

reply

Ian says:
November 8, 2012 at 18:21

I prefer the Seeeduino – it can be switched between 3.3 & 5v.

reply

Josh Hawley says:
November 27, 2013 at 19:51

Couldn’t you just put a diode in there since you only need it to travel in one direction anyway?

reply

Joonas Pihlajamaa says:
December 9, 2013 at 23:15

Yeah that might be a useful way to protect the RaspPi TX pin. Nice tip!

reply

Liomred:
September 28, 2012 at 22:39

Just FYI only RX0 is at 5v on the Mega from my own testing, RX 1-3 seem to be neutral

reply

Mark:
October 9, 2012 at 13:20

I struggle already several hours but i can not get it working. Yesterday it works once, but today only output works. I know that the serial interface is OK, because i can see boot information and can login. Done disable items in /etc/inittab and /boot/cmdline.txt What i am forgotten to do? And there is something strange with readline, this command does not accept arguments? Maybe wrong version or so? Do you have an idea?

reply

jokkebk says:
October 9, 2012 at 13:29

First, hopefully you read the warning I added last week, as the Arduino programming can put 5 volts to RX, so having a MAX3232 or a level converter chip between the Arduino and Pi is preferred, or at least a series resistor (1k may work, haven’t tried that).

Second, make sure you don’t have flow control on anywhere, as it seems the Pi UART doesn’t have that.

Also note, that the Arduino-side example and Pi-side example cannot be connected together – instead, you can test the Pi-side Python script with Putty terminal on PC side, and Arduino side echo with minicom or similar on Pi side.

Strange that serial library doesn’t have the eol-parameter, it might be a different version. I cannot help you there much – Putty sends only \r and not \n on newline, so unless that parameter is there, readline() never returns, because it’s waiting for \n forever.

reply

Mark says:
October 10, 2012 at 4:15

Putty sends only \r and not \n on newline, so unless that parameter is there, readline() never returns, because it’s waiting for \n forever. <== That's the problem, with hyperterminal it works well. But why that parameter does not work with my Raspbian installation? Can i do somewhere a version check or so?

reply

jokkebk says:
October 10, 2012 at 9:21

Considering the python serial library is installed with “apt-get install python-serial”, you can probably use the apt commands to check version number. You might want to check pySerial home page for installation instructions: http://pyserial.sourceforge.net/index.html

reply

butch:
October 30, 2012 at 3:48

I am a linux/debian/wheezy newbie
I followed above instructions.
I have tried several times with putty and minicom to do serial over ttyAMA0. All I get is:

Unable to open connection to : (blank)
Unable to open serial port

Any help would be appreciated.

reply

jokkebk says:
October 30, 2012 at 23:45

Hmm, unfortunately I don’t have my Pi at hand.. You could first try to not disable serial login (leave inittab as it is) and connect from PC to the Pi with Putty, using 115200 as the baud rate. If serial terminal doesn’t work “out of the box”, it’s probably either an operating system issue (different device name, settings, etc.) or there might be some issue with your PC serial port (or USB-serial converter or whatever you use). RaspPi forums probably can also offer more help!

reply

Edd:
December 7, 2012 at 14:42

Hi, I have tried the above but am reciving the text bellow when i try and send messages using minicom to the terminal. Any ideas?
Thanks
Edd

:*»j*ªÚÊôÖÕö«4ÚêúËÕ4úF))QÚQÊJ*˺ԺªÊz»jû«5T)©hÒÑÓô)¨m:
ÊJªº*»êÊJÊzjûy=Rûë«ö6ö66Ö6VõËj´Õô[û{Õ:ªª:zû+kkûÛTÚ

ºúËmõÊzú³TÚ*j꺪*ë::*»êÊJÊz«µýIMIH£¡i¦¢ÒRZR¤¤´JKÒÒm«í»ªÚªzµýKj::*ë::*»êÊJÊzkµý»ôê*:ªÊjtT*Êz[µýËêJýÉz

reply

jokkebk says:
December 7, 2012 at 15:01

I’ve seen the same happen when I’ve had invalid flow control (there should be none, no RTS/CTS or XON/XOFF, IIRC) or other connection settings (parity, speed, etc.) – on the positive side, getting garbage has usually resulted in working connection in a few minutes after I’ve fixed the settings.

reply

Charles Linquist:
December 9, 2012 at 23:25

I am trying to make an Ethernet serial bridge out of the Pi. I loaded minicom and have the serial port of the Pi working. I then typed in “minicom -b 9600 -o -D /dev/ttyAMA0″ I didn’t disable the startup screen, and I can login, etc. just fine over RS-232.
Then, I used Putty to login with the same name/pw over SSH. That, of course works also. While the serial port does echo my keystrokes, I see nothing in the Putty window when I type into the serial port, and when I type into Putty, I see nothing on the serial side. What am I doing wrong? I did notice that the serial port is not running at 9600 baud – it is actually running at 115Kbaud.

reply

Finn says:
December 24, 2012 at 3:14

I take you are doing right.
As the OS is a linux, you are quite simple doing 2 seperate sessions, Linux being a real multiuserenvirpnment.
//finn

reply

jokkebk says:
December 27, 2012 at 15:33

Only one program (I think) can use the ttyAMA0 serial device at a time, so if you fire up minicom on the Pi side (e.g. from a SSH session), you’ll need to disable the login on ttyAMA0 first and reboot, otherwise it might not work or work in strange ways (e.g. you can send characters but getty will receive them…).

Once you have login disabled and minicom running, just use the same settings (baud rate) for Putty on your PC. Characters won’t echo on either side without additional settings, but everything you type on one end will show up in the other – things typed in minicom should show in Putty and vice versa.

Baud rate can be set differently on both sides, but it will only work properly if it’s the same.

Also, note that if you run the Pi headless, you use one Putty to open SSH connection to Pi and run minicom there, and /another/ Putty to open _serial_ connection to COMxx to the Pi. :)

reply

Finn:
December 24, 2012 at 3:21

Forgot to mention that you probably might shut off the echo in tty, ala
stty -echo
//finn

reply

Mathew:
January 14, 2013 at 23:06

I have the arduino set up so that it is powered by the pi (pi 5V>uno Vin;pi GND>uno GND). do i have to connect the two grounds when i have it like this, and can i connect the 1 kohm resistor to the arduino GND instead of the pi’s GND, since they are essentially the same thing?

reply

jokkebk says:
January 22, 2013 at 9:38

No, you don’t need to have several GND->GND connections when powering the Arduino from Pi. Actually in some cases several ground paths may be bad. And likewise, 1 kohm can be connected to Arduino GND, too.

reply

Ricky:
January 20, 2013 at 8:56

I happened to encounter similar issue. I tried to connect my Hackberry board to arduino UNO via serial port. Hackberry is 3.3V in both RX and TX pin. I came up with the same workaround as yours.

But it may be not safe to use arbitrary resistors to step down voltage. The inner resistors of RX pin varid when connected to power. You may end up blow up your board and mislead others.

reply

jokkebk says:
January 22, 2013 at 9:36

Yes, that’s why there’s the warning in the very first chapter. Using resistors as voltage divider should be safe, but the problem of course is that RaspPi TX pin (Arduino RX) is only 3.3V voltage divider cannot be used.

In any case, I’ll add a link to a later post containing the use of a level shifter with Arduino.

reply

konkurs 2013:
April 12, 2013 at 1:03

Appreciating the persistence you put into your site and in depth information you offer.
It’s good to come across a blog every once in a while that isn’t the same
unwanted rehashed information. Fantastic read! I’ve bookmarked your site and I’m including your
RSS feeds to my Google account.

reply

junaid:
March 6, 2014 at 16:50

in place of raduino i am connecting raspberry pi and now i am communicating between two pi via RX TX but while running the code if i am sending 1 then i am receiving 9 or some garbage value like @ $ like this. can any one help me with that??
thank you so much

reply

Joonas Pihlajamaa says:
March 6, 2014 at 18:09

Different line control settings might be the culprit (e.g. no parity in one end, parity in other), or then some end or another is making noise on the line.

reply

Leave a Reply

Your e-mail address will not be published.


five × 9 =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>