2 arduinos with two wires (clock + data)

Hi,

I need very simple communication to sending data from one arduino to second arduino. Becouse on 2nd A, I'am using VGAX library, I can't use I2C (wire lib is huge), Serial (PORTD is unusable), SoftwareSerial (relay on timers). This vga library using 1880 bytes of RAM.

VGAX library occupied all timers and therefore standard time & delay functions is not avaialbe, only modified one.

So I was wondering to use clock signal from slave A and this clock signal will be connected to interrupt on master A, witch will send data.

But questions are:

  1. how to sync data flow - ie - wait for byte start and not start reading from wrong bit

  2. how to tell, that there is no data (but this is solved by packetreader, so this can be omitted and I can sending zeros)

It's possible to use max 4 pins, but all must be timed from slave A, becouse clock interval will not be same on every tick.

Can anyone help? Thx.

Hi, welcome to the forum.

VGAx : GitHub - smaffer/vgax: VGA library for Arduino UNO

I read that you can do anything in the loop(), as long as no interrupts and no timers are used. That means everything fully in software with pin toggle, and it should not use a fixed high speed clock.
The pins A1...A5 can be used, and perhaps a few digital pins ? If for example 4 pins can be used for data, a lot more data can be transferred.

I can only think of one thing: handshake
That means setting the data pin(s), making a signal high, wait until the receiver makes another signal high, and start over again for the next bit(s).
Perhaps a special start condition has to be added to indicate the start of data.
Do you want two way data ?

I don't know if someone has made this, because I don't know what to call it. Perhaps "free-running asynchronous serial communication with handshake per bit and no clock" or something like that.

Yes, you are right. I can use few analog pins (witch can be used as digital as well) and pins D9-D13 are free).

loop() can be fully used, as is totally unused in library.

I need only one way communication, so your idea with helper signals can be used. I've googled for any existing soloutions but all are using SoftwareSerial or Wire library.

A B
<- CANWRITE
CANSEND ->

<- CLOCK
DATA ->


B pulls PIN CANWRITE up and wait for A to pull up CANSEND pin. When this is done, B starts to sending CLOCK signal for 8 bits. When done, it lower CANWRITE pin and wait for CANSEND to lower too. And starts over.

Maybe this will work :wink:

I think a handshake is needed per bit. Since it is not known how busy the other Arduino is.
That would require an extra signal to indicate the start, or a specific protocol is needed that can identify the first bit.
With 4 signals and data in one direction is should not be very hard.

I don't have the time to make something, because I also want to try this : Writing to FLASH from application. Please test and enjoy :-) - Microcontrollers - Arduino Forum

How much data do you need to sync between Arduino's, at what speed and with what margin of jitter?

If the amount of data is not high then simple slow clocked data that transmits about 1 byte per second would probably be fine. You could use a clock pin, data pin and another pin that is set high/low on the first/last bit only so you know byte boundaries.

             ___                             ___       
First Bit  _|   |___________________________|   |______
             _   _   _   _   _   _   _   _   _   _   _ 
Clock       | |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |
             ___     ___     ___     ___     ___       
Data        |   |___|   |___|   |___|   |___|   |______

I don't understand the use of a clock. Because of the clock the data rate has to be very slow, since the VGAx could be very busy in the interrupts. A free-running handshake per bit can run at high speed.

I have made a first version of data transfer. It uses 4 pins.

The Master (transmits data)

// Toggle with Handshake Communication.
// ------------------------------------
//
// This communication is written for the VGAx code.
// It transfers a byte from a Master Arduino to a Slave Arduino.
// The Slave Arduino is running the VGAx code.
// The Slave code does not use delays, no interrupts,
// and interrupts are not disabled.
// 
// Signals are active HIGH, and default LOW.
// LSB first, bit 0 is the first bit to be send.
//
// Four signal wires plus GND:
//   dat = data (from Master)
//   dtr = data ready (from Master)
//   ack = acknowledge (from Slave)
//   stx = first bit (from Master)
//   GND (connect also both GND of the Arduino boards)
//
// Transfer rate is about 1400 bytes per second for two Arduino Uno boards.
//
// This is the first version, the code might not be fully fail safe at the moment.
//

const int pinDat = A1;
const int pinDtr = A2;
const int pinAck = A3;
const int pinStx = A4;

void setup() 
{
  Serial.begin(9600);
  Serial.println(F("Master"));
  
  pinMode( pinDat, OUTPUT);
  pinMode( pinDtr, OUTPUT);
  pinMode( pinAck, INPUT);
  pinMode( pinStx, OUTPUT);
}

void loop() 
{
  const char text[] = "Hello World\r\n";
  for( int i=0; i<strlen(text); i++)
  {
    int n = ToggleSend( text[i]);
    if( n == 0)
      Serial.println(F("ToggleSend failed"));
  }
}

// ToggleSend
// ----------
// Send a single byte.
// This function waits for the Slave with a timeout,
// and returns after the byte has been send.
// The return value is the number of bytes that are send.
// At this moment only one byte is send.
//
int ToggleSend( const byte data)
{
  unsigned long toggleMillis;
  int error = 0;
  int n = 0;          // number of bytes that are send
  
  digitalWrite( pinStx, HIGH);   // indicate start (HIGH for first bit)
  for( int i=0; i<8 && error == 0; i++)
  {
    digitalWrite( pinDat, bitRead( data, i) == 1 ? HIGH : LOW);
    digitalWrite( pinDtr, HIGH);    // everything is ready, make it high

    // wait for ack to be HIGH
    toggleMillis = millis();
    while( digitalRead( pinAck) == LOW)
    {
      if( millis() - toggleMillis >= 1000UL)
      {
        error = -1;
        Serial.println(F("timeout waiting for ack high"));
        break;
      }
    }
    digitalWrite( pinStx, LOW);  // stx low for other bits
    digitalWrite( pinDtr, LOW);  // everything is ready, make it low.
    
    if( error == 0)
    {
      // wait for ACK to go low.
      toggleMillis = millis();
      while( digitalRead( pinAck) == HIGH)
      {
        if( millis() - toggleMillis >= 1000UL)
        {
          error = -2;
          Serial.println(F("timeout waiting for ack low"));
          break;
        }
      }
    }
  }

  // If an error occured, the byte is probably not send.
  if( error != 0)
    n = 0;
  else
    n = 1;
    
  return( n);
}

The Slave (receives data)

// Toggle with Handshake Communication.
// ------------------------------------
//
// This communication is written for the VGAx code.
// It transfers a byte from a Master Arduino to a Slave Arduino.
// The Slave Arduino is running the VGAx code.
// The Slave code does not use delays, no interrupts,
// and interrupts are not disabled.
// 
// Signals are active HIGH, and default LOW.
// LSB first, bit 0 is the first bit to be send.
//
// Four signal wires plus GND:
//   dat = data (from Master)
//   dtr = data ready (from Master)
//   ack = acknowledge (from Slave)
//   stx = first bit (from Master)
//   GND (connect also both GND of the Arduino boards)
//
// Transfer rate is about 1400 bytes per second for two Arduino Uno boards.
//
// This is the first version, the code might not be fully fail safe at the moment.
//

const int pinDat = A1;
const int pinDtr = A2;
const int pinAck = A3;
const int pinStx = A4;

void setup() 
{
  Serial.begin(9600);
  Serial.println(F("Slave"));
  
  pinMode( pinDat, INPUT);
  pinMode( pinDtr, INPUT);
  pinMode( pinAck, OUTPUT);
  pinMode( pinStx, INPUT);
}

void loop() 
{
  byte data;

  if( ToggleCheck(&data) >= 1)        // read incoming bits and check if a byte is received
  {
    Serial.write( data);
  }

  // Do other things here in the loop().
  // Other code will slow down the transfer rate.
  
}

// ToggleCheck
// ----------
// Receive a single byte.
// This function should be called in the loop() function every time, 
// since it receives bits while being called repeatedly.
// This function is non-blocking, and without waiting.
// The return value is the number of bytes that are received.
// At this moment just one byte is received.
//
int ToggleCheck(byte *pdata)
{
  static byte toggle_Data;                // variable in which the bits are stored to make a byte.
  static byte toggle_Index;               // index of bits
  static boolean toggle_Ready = true;     // ready to read a bit

  int n = 0;

  int toggleDtr = digitalRead( pinDtr);        // read dtr signal first
  int toggleStx = digitalRead( pinStx);
  int toggleDat = digitalRead( pinDat);

  if( toggle_Ready && toggleDtr == HIGH)
  {
    if( toggleStx == HIGH)
    {
      toggle_Index = 0;
      toggle_Data = 0;
    }

    if( toggleDat == HIGH)
      bitSet( toggle_Data, toggle_Index);

    digitalWrite( pinAck, HIGH);
    toggle_Ready = false;

    toggle_Index++;
    if( toggle_Index >= 8)
    {
      toggle_Index = 0;

      // All 8 bits of the data byte have been received.
      // Write to *pdata only if the complete and valid data was received.
      *pdata = toggle_Data;
      n = 1;
    }
  }
  else if (!toggle_Ready && toggleDtr == LOW)
  {
    digitalWrite( pinAck, LOW);
    toggle_Ready = true;
  }
  return( n);
}

The Slave code is to test the communication. For use with VGAx, the Serial functions have to be removed.

Thank's for the code, but I think that clock time from slave to master is important. It's becouse I can not depend on precise timing (ie - you are using millis on master), becouse slave have notning to do, when display is empty, but when i need someting to draw, it's cost time and i can miss some bits.

So for that, timing is realying on slave and master can be driven by interrupt (attached clock pin from slave). It's stopwatch clock displaying on dogs race, so I need faster data transfer :wink:

The millis() on the Master is only a timeout in case some error occurs. You can make it any value for example 10ms or 10s. In my opinion a clock can not be used. The communication does not rely on timing at all, and no bits are missed, because of the handshake. The Slave does never wait for a bit to get high or low. I wrote in the sketch that I can get about 1400 bytes per second, so why do you need faster data transfer ?

trosa, you gave up on me ? I wrote code that does exactly what you need.