1.9Mbit/s data transfer - Arduino to arduino

I was thinking today about how to speed up the data transfer on a project I have been working on. I thought about connecting PortD of one arduino to PortD of the other and using the whole port to transfer data, like in LCDs etc. When I got home I wrote some pretty simple code and tested it out. I was pretty surprised at how excellent the speed is.

I consistently get ~1.928Mbit/s (10,000,000 bytes in 41.5s), timed over various time periods, which is pretty damn nice. So I thought I'd share :slight_smile:

MASTER

#include <avr/io.h>

byte byte_to_send = B01010101;

void setup()
{
  DDRD = B11111111;
  PORTD = B00000000;
  DDRB = (DDRB | B00000001);
  PORTB = (PORTB ^ B00000001);
 
}

void loop()
{
  if(!(PINB&B00000001))
  {
    PORTD = byte_to_send;
   PORTB = (PORTB | B00000001);
   while(PINB&B00000001){}
   PORTB = (PORTB ^ B00000001);
  }
 }

SLAVE

[#include <avr/io.h>

long Byte_counter = 0L;
byte Data_read;
long Show_light_at = 10000000L;

void setup()
{
  DDRD = B00000000;
  PORTD = B00000000;
   DDRB = (DDRB ^ B00000001);
  PORTB = (PORTB ^ B00000001);
    digitalWrite(9,LOW);
}

void loop()
{
  if(PINB&B00000001)
  {
    Data_read = PIND;
   Byte_counter++;
   DDRB = (PORTB | B00000001);
   __asm__("nop\n\t");__asm__("nop\n\t");
   DDRB = (DDRB ^ B00000001);
  }
  if(Byte_counter > Show_light_at)
  { pinMode(9,OUTPUT); 
    digitalWrite(9,HIGH);
 }
}

In terms of connections PortD of master goes to PortD of slave. Digital pin 8 is connected between arduinos and has a pull down resistor of about 11k Ohms. Also a led is connected to digital pin 9 so I can time it.

The way I wanted it to work was the master sets the port, sets the write bit high and goes into a while loop. The slave then sees the write bit high, saves the port data, and toggles the write bit low, throwing the master out of it's while loop to add another byte to the port.

Port D is obviously a bad option for arduinos, I thought I might turn it into 4 data pins (to bypass any important hardware), just sending nibbles, a chip select (so that you can address a bunch of slaves, if you use a 595 then for 8 pins you could address a ton of slaves) and a write pin.

I plan on optimizing it a bit over the next week or so to make it, you know, actually useful. Just thought I'd post up the preliminary to get some ideas

if you execute this code you will brick your arduino board

No you are safe running this. What happens is that the Arduino, on reset, looks at the serial port first to see if any program needs downloading. Only when it sees nothing will it then go and execute the code in your sketch. Of course you need to disconnect any hardware attached to these pins first that might interfere with the data transfer.

Anyway good work. :wink:

Ah cool, I'll remove the disclaimer :wink:

Cool stuff!

Thanks AlphaBeta

I was wondering if I could get some input on the protocol side of things. I'm making it with these aspects in mind:

  1. Slave has control over the timing, so is free to do other cycle intensive tasks and read data when it suits. Also no interrupts should be used on the slave side of things.
  2. High data transfer rate
  3. Able to use the same data and read lines for multiple slaves using a chip select line

At the moment the master just hangs while waiting for the slave, I might implement an interrupt of a falling edge of the read line, however interrupts eat a lot of cycles (about 55 in and out I've read, 18 by modifying the arduino code) so it might not be worth it.

Another issue is that the slave sets the read line low and then kills two cycles to allow for the master to actually check the line, I have no idea how many cycles are necessary and just took a guess. With an interrupt on the master pin the nops might not be necessary, but again I'm not sure if it's really worth it.

Working with nibbles I thought it might be possible to use two read lines between the arduinos, sort of a "Finished, now you go" line for each one. The master could loads a nibble, write his line low, the slave reads it writes his line low, the master loads the second nibble, writes his line high, the slave reads it, writes his line high.

Oh the other thing I was thinking was to use the Chip select line going high as a signal for the slave to read the data lines for some common data (register address, number of bytes to send etc, since we can program both slave and master the possibilities are fairly endless)

The end goal is to create a nice little library for using communicating with a slave arduino with as little strain as possible on the slave. I think since atmegas are so cheap it's worth investigating them as purpose built peripherals.

Hey, hi
I m also a newbie here. Can u plz just tell me what your project was really about that transfer of data and also mention if u tried going wireless. :stuck_out_tongue:

I was looking for a way to transmit lots of data quickly between arduino, without using the SPI hardware. As for the project I was simply using one arduino to do display computations and another arduino as a dedicated led multiplexer. In this situation the slave has time critical code so I was trying to get the master to wait for the slave.

I found out today that you can get much faster data transfer using SPI so I've shifted things around and atm I'm playing with writing a small script based around the SPI hardware that still allows the slave to pause the data transfer (I think a single extra pause wire should do the trick). The arduino supports 4Mbit/s data transfer as an SPI slave and also has a small hardware buffer built in so it's much more ideal.

I'm not sure why I would want to go wireless though.

edit: Oh and I moved the shift registers off the SPI to the MSPIM instead

SPI on an arduino should shift out at 8Mhz (using SPI2X register) :slight_smile:

True however the maximum speed for an arduino acting as a SPI slave is 4Mhz

In SPI Slave mode, the control logic will sample the incoming signal of the SCK pin. To ensure
correct sampling of the clock signal, the minimum low and high periods should be:
Low periods: Longer than 2 CPU clock cycles.
High periods: Longer than 2 CPU clock cycles.