Easily manage I/O on a remote Arduino using two wires and the ExtraCore library

I’m always running out of the good pins in my Arduino projects. PWM pins are in particularly scarce supply and I sometimes even find myself short on analog inputs. Tricks like using shift registers or software PWM help, but they have limitations that aren’t always easy to work around.

The open source ExtraCore library on GitHub helps you use a second Arduino compatible to nearly double your pin count. You can stop scratching your head over how to get all the functionality you need once you go beyond “blinky LED” type projects. You can just pop in a second Amtega328 based board.

  • Lets you read or write to every pin on the extra board as easily as the onboard pins.
  • Adds 6 PWM outputs instantly.
  • Communication only takes 2 wires (A4->A4, A5->A5)

When Tim Malcom wanted to make a giant interactive bagpipe sculpture for Maker Faire he ended up using 3 Arduinos and two of them were talking over a two wire interface. This was one of the intended missions of the ExtraCore, but Tim had to do all his own code. Now if he wanted to farm out I/O to a second Arduino he could have it working in just a few minutes with this library, or use it as a jumping off point for something more complex.

You will need the Wire and EasyTransferI2C libraries in your Arduino libraries folder. The included examples will connect two Arduinos and blink pin 13 in time as well as run one PWM output and show you how to read remote inputs. The client example is meant to run as is for most projects. The manager is where your own code would run.

Here some of the code from the manager side.

#include <ExtraCore.h>
#include <Wire.h> // You don't need to call Wire or EasyTransferI2C directly, just include them.
#include <EasyTransferI2C.h>
ExtraCore extraCore;
void setup()
  pinMode(13, OUTPUT); //set local pin13 to output.
  extraCore.beginManager();//begin Manager role.
  extraCore.setPinIOstate(6, OUTPUT);//set remote pin to output.
  extraCore.setPinIOstate(13, OUTPUT);//set remote pin to output.
  extraCore.setTriStateValue(3, TRUE);//sets remote pin to INPUT with pullup resistor active.
void loop()
  extraCore.setAnalogOutput(6, 127);//Turns on remote PWM
  extraCore.setDigitalOutput(13, HIGH);//Turns one remotes Digital 13 pin
  extraCore.sendConfig();//send the current I/O setting to the remote to execute.
  int r2 = extraCore.getDigitalReading(2);

As you can see using the remote pins is pretty similar to using the local pins. One exception is using high-impedence mode on an input pin. You need to specifically call setTriStateValue(pin, state). Setting this to true will both set the remote pin to input and digitalWrite(pin, HIGH). Setting it to false will only clear the pullup by setting digitalWrite(pin, LOW), but won’t change the input state of the pin.

Fritzing Diagram of setup the works with example code. This will allow you to see pin 13′s flashing in time, a PWM LED light and dim and see the reading on D2 go on and off.


Diagram of example code setup.


The library is meant to get you up and running quickly by adding more ports easily. If you need timing resolution greater than about 20 milliseconds you should roll your own. Keep all your timing critical stuff local to the manager board and you should be fine.

The libraries use the built in i2c in hardware. If you call Serial.print in your sketch too often it will cause the i2c communications to fail. You can get a few debug messages out, but if you run into problems try disabling Serial.print* commands.

If your outputs aren’t working, but sure you set the pin state to output. Just like local pins they default to input.



Manager Methods
void beginManager();
Start sending and receiving data as the manager.

void setPinIOstate(pin, boolean);
Set the desired INPUT/OUTPUT state of a pin.

void setDigitalOutput(pin, boolean);
Set the desired HIGH, LOW output state of a pin.

void setAnalogOutput(pin, pwm);
Set the desired PWM (0-255) state of a pin. Ignored if not PWM cabable.

void setTriStateValue(int, boolean);
Set the pullup resistor to TRUE/FALSE. True will automatically set the pin to INPUT.

boolean getDigitalReading(pin);
Get the last known digital reading from the remote.

int getAnalogReading(pin);
Get the last known analog reading from the remote.

void sendConfig();
Send the current desired state of all the pins to the remote.
This is required to for changes to take effect.

Client methods:
void beginClient();
begin sending and recieving as client.

boolean getPinIOstate(pin);
Get the desired IO state for a pin.

boolean getOutputValue(pin);
Get the desired digital output value for a pin.

boolean getTriStateValue(pin);
get the desired pullup resistor value for a pin.

int getAnalogValue(pin);
Get the desired PWM output for a PWM pin.

void setDigitalReading(pin, value);
Set the digital reading from the remote for a pin.

void setAnalogReading(pin, value);
Set the Analog reading for pin.

void sendData();
Send the currently known pin readings to the manager.
This is required for updates to take effect.

boolean isDataNew();
Returns true if new data has arrived since the last time it was checked.

Posted in Arduino | 6 Comments

6 Responses to Easily manage I/O on a remote Arduino using two wires and the ExtraCore library

  1. [...] of pins for whatever project you have in mind. All these require extra components, though. Enter the ExtraCore library for Arduino, a software library that turns two or more Arduinos into a multi-core microcontroller with more [...]

  2. Geoff says:

    Have you investigated stringing more than 2 arduinos together?

    • dustinandrews says:

      I haven’t done any hands on experiments, but you can chain i2c. So you can do at least several. I used a dual master setup in this code because I wanted the return data to be interrupt driven on the master. You would have to go single master and have the master poll the clients.

  3. GR0B says:

    Looks interesting, might have to test it out with my boards.

  4. [...] Easily manage I/O on a remote Arduino using two wires and the ExtraCore library [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

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>