UART between two Arduinos crashes after certain time

Hello,

I am working on a project, where I am goint to receive commands via RS-422.
There will be three Arduinos communicating with each other, two UNOs and one MEGA.

At this point I have one Arduino UNO talking to one Arduino MEGA and vice versa.
The Uno "simulates" the RS-422 communication, which is read by the MEGA.
(approx 19200 baud, but there are 21 bits transceived at nonstandart, so I cannot simply use implemented UART for this...)
Then the MEGA collets the data and transformes it into a number, which is stored in a uint32_t variable.
After that the MEGA shall send it back to the UNO via serial UART.
The MEGA talks to the UNO via Serial3.

And now there is my problem. After several successive communications the UNO seems to not receive any commands. For testing I am sanding back "<0xffff>" from MEGA to UNO. After approx 8 times the UNO seems to no longer receive any further commands via UART.

When I reduce the sent message to e.g. "<0xff>", it stops after approx 12 times, and after e.g. "<0xffffffff>" already after approx 4 times. So I think on the side of the UNO there must be some problem in code, like buffer full or sth...

Here Arduino UNO code:

#include <digitalWriteFast.h>
// Write Pin
const uint8_t pin = 2;
uint32_t to_be_sent = 0;
// variables for RS422 send simulation
uint32_t timer_begin = 0;
uint32_t next_slot = 0;
const uint8_t len = 21;
uint32_t buf[len];
// variables for serial simulation
uint32_t receivedNumber = 0;
uint32_t _start = 0;
uint32_t _stop= 0;

void setup()
{
  Serial.begin(115200);
  pinModeFast(pin, OUTPUT);
}

void loop()
{
  to_be_sent = random(0x100000UL,0x200000UL); 
  transmitRS422 (to_be_sent);
  delay(200);
  
  if ( Serial.available() )
   {
   processInput();
   }
  //delay(1000);
  //while(1);
}

//###########################################################
//###################  to_be_sent block  ####################

void transmitRS422 (uint32_t tbs)
{
  for ( int i = 0; i < len; i++ )
  { // algorithm for shifting number into single bits in buffer buf
    buf[i] = tbs & ( 0x100000 >> i );
    buf[i] = buf[i] >> ( len - ( i + 1 ) );
  } // end for loop
  ////////////////////////////////////////
  Serial.println(tbs, BIN); // for Debugging
  ///////////////////////////////////////
  timer_begin = micros(); // store time when first '1' shall be sent
  next_slot = timer_begin + 52 ; // store next time slot for next byte (52 us)
  //////////////////////////////
  for ( int i = 0; i < len; i++ )
  {
    while( next_slot > micros() ); // wait for next time slot
    digitalWriteFast2( pin, buf[i] ); // write bit
    next_slot += 52; // store next time slot for next bit to be sent
  } // end for loop
  while( next_slot > micros() );
  digitalWriteFast2( pin, LOW ); 
} // end of transmitRS422

//################# end of to_be_sent block #################
//###########################################################

//###########################################################
//#####################  serial block  ######################

void processNumber (const long n)
{
  Serial.println("Received via serial:");
  Serial.println(n, BIN);
}  // end of processNumber

void processInput ()
{ 
  byte inByte = Serial.read ();

  switch (inByte)
  {

  case '>':
    processNumber (receivedNumber); 
    break;

  case '<': 
    receivedNumber = 0; 
    break;

  case '0' ... '9':
    receivedNumber *= 10;
    receivedNumber += inByte - '0';
    break;

  } // end of switch  
}  // end of processInput

//################## end of serial block ####################
//###########################################################

Here Arduino MEGA code:

#include <digitalWriteFast.h>
// Pins for RS422 communication
const uint8_t PinRead  = 2;
const uint8_t PinWrite = 3;
// 21 bits to send (for testing)
uint32_t to_be_sent = 0x12EFE9;
// variables for RS422 receiving
const uint8_t len = 21;
uint32_t buf_Rx[len];
uint32_t ctr_temp = 0;
uint32_t ctr_len = 21;
uint32_t ctr_buf_Rx[len];
uint32_t timer_begin = 0;
uint32_t next_slot = 0;
uint32_t RS422_TC = 0;


void setup ()
{ 
  pinModeFast(PinRead, INPUT);
  pinModeFast(PinWrite, OUTPUT);
  Serial.begin (115200);
  Serial3.begin (115200);
} // end of setup

void loop ()
{
  while (digitalReadFast2(PinRead) == LOW); 
  receiveRS422 (); // call function as soon '1' detected
  sendSerial (to_be_sent);
}  // end of loop



//###########################################################
//##################  receiveRS422 block  ###################

void receiveRS422 ()
{
  // UFD
  // uint32_t vor_schleife = micros();

  timer_begin = micros(); // store time when first '1' detected
  next_slot = timer_begin + 26; // store next time slot to mid of next byte (26 us)

  for ( int i = 0; i < len; i++ )
  {
    while( next_slot > micros() ); // wait for next time slot
    buf_Rx[i] = digitalReadFast2 ( PinRead ); // read bit
    // ctr_buf_Rx[i] = micros (); // UFD
    next_slot += 52; // store next time slot for next bit to be read
  } // end for loop
  RS422_Rx_bits_to_var(buf_Rx);
  Serial.println("What is received: ");
  Serial.println(RS422_TC, BIN);

  // UFD
  /* uint32_t nach_schleife = micros();
   Serial.print("Verstrichene Zeit fuer gesamten Leseprozess: ");
   Serial.print(nach_schleife - vor_schleife);
   Serial.println(" us.");
   
   for ( int i = 0; i < len; i++ )
   {
   Serial.print("Delay zum Bit-Mittelpunkt nach dem ");
   Serial.print(i);
   Serial.print(". Durchlauf: ");
   Serial.println( ctr_buf_Rx[i] - (timer_begin + 26 + i*52) );
   }
   
   for ( int i = 0; i < len; i++ )
   {
   Serial.print("Nach dem ");
   Serial.print(i+1);
   Serial.print(". Durchlauf: ~");
   Serial.print(buf_Rx[i]);
   Serial.println("~");
   }
   */
}

void RS422_Rx_bits_to_var(uint32_t buf_Rx[])
// This function translates received RS422 command bits
// thru DigitalReadFast2() into a uint32_t variable
{
  RS422_TC = 0;
  for ( int i = 0; i < 21; i++ )
  {
    RS422_TC += ( buf_Rx[i] << ( 20 - i ) );
  }
  // UFD
  // Serial.print("RS422 TC: ");
  // Serial.println(RS422_TC, BIN);
}

//################ end of receiveRS422 block ################
//###########################################################

//###########################################################
//###################  send serial block  ###################
void sendSerial (uint32_t nbr_to_send)
{
  Serial.print ('<');          // send serial-start sign
  //Serial3.print (nbr_to_send); // send the number
  Serial.print (0xffff); // send the number
  Serial.println ('>');        // send serial-stop sign
  Serial3.print ('<');          // send serial-start sign
  //Serial3.print (nbr_to_send); // send the number
  Serial3.print (0xffff); // send the number
  Serial3.println ('>');        // send serial-stop sign
}  // end of sendSerial
//################# end of send serial block ################
//###########################################################

Im happy for any advice! Thank you!

Here is the problem on the Uno end:

  delay(200);
  if ( Serial.available() )
   {
   processInput();
   }

So you are only processing one character every 200 mS, but they are arriving much faster than that. Eventually the buffer fills up. Change to:

  delay(200);
  while ( Serial.available() )
   {
   processInput();
   }

That worked better when I tested it. According to my logic analyzer I am getting framing errors for 21 bit async serial at 19200 baud, so you might want to adjust your timings. Perhaps turn interrupts off while you send the bits.

Also, adding 52 to the "time for next bit" is definitely wrong. That will fail when micros rolls over.

You need to do it by subtraction, see Gammon Forum : Electronics : Microprocessors : millis() overflow ... a bad thing?

Thank you so far! Ill test it on monday.

But you say there will be framing errors. What I have to do is to both receive and transmit (so called telecommand) consisting of 21 bits, e.g.

'0' for idle (unlike UART standard)

start sign: '10'
16 data bits
parity bit
stop sign '01'

e.g.: 10.1100.0111.1011.0011.0.01

Any ideas how to improve my code?

Oh, OK, I didn't spot that you had a 0 for idle. That gets rid of the framing errors.