ArduiPi Protocol Specification

This post present the protocol specification between Raspberry Pi and Arduino of the ArduiPi board.

The protocol will be the same and independant of the communication channel used. If you are on this page, this means that you probably already know the goal of the ArduiPi project. If not please refer on the post that present this project on this blog.

The communication could be done by three ways

  • Using Serial Port, this is not my favorite one because I like to use the serial for doing something else.
  • Using SPI, better but once again not my favorite because you need 4 wires and need a “chip select”, so another Rasbperry I/O. Also it is synchronous, so you can’t send back results immediatly, but it is cool and fast.
  • Using I2C, really simple to implement, lot of devices can take place on i2c and just need 2 wires.

This is beta API documentation the accorded driver on Raspberry Pi and Arduino Firmware are working but may not be stable yet 

Arduino Port Mapping

At this step, you need to know that Arduino pins that you can see on the arduino board are mapped to physical Arduino ports that may not have the same name into the Arduino chip. Here below the port mapping definition :

Arduino 328 ports Mappings

Remember, Arduino has 3 main ports named PORTB, PORTC, PORTD where

  • PORTD is digital pin 0 (PD0) to 7 (PD7), PD0 and PD1 are used by serial communication
  • PORTB is digital pin 8 (PB0) to 13 (PB5), PB6 and PB7 are reserved for external crystal
  • PORTC is analog pin A0 (PC0) to A6 (PC5), PC6 is reserved for reset pin

Protocol Communication

The communication is done by sending one or more byte to Arduino, then Arduino can immediatly do the action such of controlling a port and if needed return data such as analog value for example.

The communication is done as follow

  • A command byte : what we wand to control (port, port pin, pwm, ….)
  • Data Value, what value we want to set on action. This value can be :
    • Data byte Or
    • Data word

Somme overhead could be added depending on protocol used. For example to communicate with i2c we need to add before the device address (which is part of the i2c protocol)

On ArduiPi the arduino i2c slave address is defined to 0x2a and it is connected to i2c bus 0 of the Raspberry Pi or i2c bus 1 for the Raspberry Pi Revision 2. So we can issue the linux i2c command i2cset and i2cget to set or get information.

Each i2cset or i2cget commmand should begin with the following parameters :
-y 0 0x2a
-y to avoid prompt from the command line tool i2cset ot i2cget
0 refers to i2c bus 0 (so 1 for Raspberry Revision 2)
0x2a refers to i2c slave address (here the arduino)

If i2cget or i2cset command use a word instead of a byte for the last parameter, the command should end by w to indicate the value is a word value.

To simplify the project, I’m writing a program to replace i2cget and i2cset command that could also be used to communicate with spi. The program is called ardupi and this is the preliminary command line syntax

pi@pi02:raspberry# ./arduipi --help
Usage is: arduipi [options] [protocol] [mode] [-d device] [-a address] [-t data]
  --<D>evice   : device name, i2c or spi (default /dev/i2c-1)
  --<a>ddress  : i2c device address (default 0x2A)
  --<d>data    : data to send
protocol is:
  --<I>2c      : set protocol to i2c (default)
  --<S>pi      : set protocol to spi
mode is:
  --<s>et value: set value (byte or word type determined by data size)
  --<g>etbyte  : get byte value
  --<G>getword : get word value
  --<q>uick    : i2c quick check device
  --ac<k>      : i2c check if device sent ack
Options are:
  --ma<x>speed : max spi speed (in KHz)
  --dela<y>    : spi delay (usec)
  --<b>its     : spi bits per word
  --<l>oop     : spi loopback
  --cp<H>a     : spi clock phase
  --cp<O>l     : spi clock polarity
  --<L>sb      : spi least significant bit first
  --<C>s-high  : spi chip select active high
  --<3>wire    : spi SI/SO signals shared
  --<N>o-cs    : spi no chip select
  --<R>eady    : spi Ready
  --<v>erbose  : speak more to user
<?> indicates the equivalent short option.
Short options are prefixed by "-" instead of by "--".

You can communicate with i2c communication with classic i2c program and/or arduipi program. The sample that are in the following table can be run on Raspberry Pi Revision 2. If you are using Revision 1 change all i2cget and i2cset command -y 1 to -y 0 (Revision 1 use i2c bus 0, not 1). arduipi program autodetect revision and adjust correct i2c bus if not specified.

Protocol Definition

Command Byte

The command will always refers to the port where we want to make action. You have the possibily to talk to the Arduino using either the AVR name or Arduino name depending on what is your preference.

The following present the command list used by ArduiPi

Command Byte ValueRefers toNotation
0x00 to 0x12
or in decimal
0 to 18
Digital Pin 0 to 18
Note that Digital Pin 14 to 18 refers to analog pin A0 to A5 when used as digital
0xa0 to 0xa5Analog Pin 0 to 5Arduino
0x1bPort BAVR
0x1cPort CAVR
0x1dPort DAVR
0x2bPort B DDRAVR
0x2cPort C DDRAVR
0x2dPort D DDRAVR
0xe0Ping Command-

Basic Command

Return the ping value.
Examples :
arduipi -g -d 0xe0
i2cget -y 1 0x2a 0xe0
0xe0Any byte value
ex : 33 or 0xAA
Set Ping Value
Set the value to be returned by the above ping command.
The value can be decimal or hexadecimal (prefixed by 0x)
Examples :
arduipi -s -d 0xe0aa
i2cset -y 1 0x2a 0xe0 0xaa

Command for Port Manipulation

0x01b or
0x01c or
Get Port - Get the given Port value.
Examples (Get Port C Value) :
arduipi -g -d 0x1c
i2cget -y 1 0x2a 0x1c
0x01b or
0x01c or
[00-FF]Set Port - Set the given Port to the following given hex value.
Examples (Set Port B Value to 0xa5) :
arduipi -s -d 0x1ba5
i2cset -y 1 0x2a 0x1b 0xa5
0x02b or
0x02c or
Get Port Direction - Get all pins direction of given Port in one shot. Each bit in the data value determine the pin mode as :
0 = Input
1 = Output
Examples (Get Port B DDR Value) :
arduipi -g -d 0x2b
i2cget -y 1 0x2a 0x2b
0x02b or
0x02c or
[00-FF]Set Port Direction - Configure all pins of given Port in one shot as input and/or output. Each bit in the data value determine the pin mode as :
0 = Input
1 = Output
Examples (Set Port D DDR Value to 0xf0) :
arduipi -s -d 0x2df0
i2cset -y 1 0x2a 0x2d 0xf0
0x01b or
0x01c or
0[0-7]Get Port Pin - Get the given port pin. Each bit in the data value determine the pin mode as :
0 = Low
1 = High
Examples (Get Port B pin 2 Value) :
arduipi -g -d 0x1c02
i2cget -y 1 0x1c 0x1c 0x02
0x01b or
0x01c or
[0-7][0-1]Set Port Pin - Set or clear the given Port pin. Each bit in the data value determine the pin mode as :
0 = Low
1 = High
Examples (Set Port D pin 4 Value to 1) :
arduipi -s -d 0x1d41
i2cset -y 1 0x1c 0x1d 0x41
0x00 to 0x12Get Digital Pin - Get the given digital pin value.
0 = Low
1 = High
Examples (Get digital pin 5 value) :
arduipi -g -d 0x05
i2cget -y 1 0x1c 0x05
0x00 to 0x12[0-1]Set Digital Pin - Set or clear the given digital pin given by item byte.
0 = Low
1 = High
Examples (Set digital pin 8 to High) :
arduipi -s -d 0x0801
i2cset -y 1 0x1c 0x08 0x01
0x00 to 0x120xDDGet Digital Pin Mode - Get the given digital pin mode. Return is as :
0 = Input
1 = Output
2 = Input with pullup
Examples (Get digital pin 3 mode) :
arduipi -g -d 0x03dd
not possible with i2cget
0x00 to 0x120xD[0-2]Set Digital Pin Mode - Set the given digital pin mode.
0 = Input
1 = Output
2 = Input with pullup
Examples (Set digital pin 4 to Input Pullup) :
arduipi -s -d 0x04d2
i2cset -y 1 0x2a 0x04 0xd2

Command for Analog Pins/Ports

In this group the command are used to control analog Pins/Ports

0xa[0-5]Get Analog Value
Get analog value for the analog arduino pin given by command byte (A0 to A5).
Examples :
arduipi -G -d 0xa5
i2cget -y 1 0x2a 0xa5 w

Command for PWM Duty Cycle Pins/Ports

In this group the command are used to control PWM Pins/Ports

3,5,6,9,10 or 110xEE[00-FF]Set PWM Duty Cycle
Set PWM value for the arduino pin given by command byte.
Examples (Set PWM duty cycle of pin 9 to 50%) :
arduipi -s -d 0xa5
i2cget -y 1 0x2a 0xa5 w
  • PWM frequencies are tied together in pairs of pins. If one in a pair is changed, the other is also changed to match:
    • Pins 5 and 6 are paired on timer0
    • Pins 9 and 10 are paired on timer1
    • Pins 3 and 11 are paired on timer2

Note that theese functions will have side effects on anything else that uses timers:

  • Changes on pins 3, 5, 6, or 11 may cause the delay() and millis() functions to stop working. Other timing-related functions may also be affected.
  • Changes on pins 9 or 10 will cause the Servo library to function incorrectly.

Thanks to macegr of the Arduino forums for his documentation of the PWM frequency divisors. His post can be viewed here