Serial Repeater

I made a cnc where an Arduino is controlling the motors. It works very fine with GRBL flashed to the Arduino. It receives and send serial communication via USB to and from my PC. No problems.

I would like to run my GRBL Arduino (uno rev3) from another Arduino (uno r2) – my control Arduino. The control Arduino should do a number of things but also be able to repeat serial communication from PC to GRBL Arduino. I connected GRBL Arduino's D0 and D1 to my Control Arduino D7 and D8 intending to use SoftwareSerial on these pins. rx->tx, tx->rx

I can't make my Arduinos talk to each other. This is the parts of my code, which should do the job. What I sent from my PC is shown at the LCD. And the initial “Ready ...” arrives at my PC. So the loop is running OK. Can anybody figure out whats wrong.

#include <SoftwareSerial.h>
#define rxPin 7
#define txPin 8
...
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
...
void serialRepeater(){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Serial repeater");
  Serial.begin(9600);
  Serial.println("Ready ...");
  while (!Serial) 
  mySerial.begin(9600);
  mySerial.print("$");
  while (mode==3) {    
    if (mySerial.available()>0){
      serData=mySerial.read();
      Serial.write(serData);
      lcd.print(serData);
    }
    if (Serial.available()) {
      serData=Serial.read();
      mySerial.write(serData);
      lcd.print(serData);
      Serial.write(serData);
    }
    if (Button(btnReverse)) {
      while (Button(btnReverse)) {}
      mode=0;
    }
  }  
  lcd.clear();
  mainmenu();
}
 
void loop() {
   mode=3; 
   serialRepeater();
}

Just got a hole through.

I minimized the code. Now it looks like this:

void serialRepeater(){
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Serial repeater");
  Serial.begin(9600);
  Serial.println("Ready ...");
  mySerial.begin(9600);
  mySerial.listen();
  while (mode==3) {    
    while (mySerial.available()){
      Serial.write(mySerial.read());
    }
    while (Serial.available()>0) {
      mySerial.write(Serial.read());
    }
    if (Button(btnReverse)) {
      while (Button(btnReverse)) {}
      mode=0;
    }
  }  
  lcd.clear();
  mainmenu();
}

Only problem now is, that it looses characters if message is long.

  while (!Serial) 
  mySerial.begin(9600);

Why?

snippets-r-us.com is down the internet a ways. Here, we get to see ALL of your code.

Yes "while (!Serial) " is indeed the error. It must be an error I made when I was copying code from an example. I'm not used to program in C, so my eyes just didn't catch it.
Now my only problem is, that when GRBL dump current settings, the text becomes more and more erroneous. Here's an example of the dump:

$0 = 200.000 (steps/mm x)
$1 = 200.000 (steps/mm y)
$2 = 200.000 (steps/mm z)
$3 = 50 (microseconds step pulse)
$4 = 250.000 (mm/min default feed rate)
$ = 5000 (m/indeaul sekrae)
$ =0.00(m/ac sgmnt
7  20 ste prtiner msk bnay  100100
8  1.00 aceleatoninmmse^2
9  005 (crnrig untin dvitin n m)
'x=vlu' o etpaamte o jst'

And the failures are not at the same positions each time.todup uren sttigs
o


And the failures are not at the same positions each time.

The problem is in this code I think as it promotes deadlock

  while (mode==3) {    
    while (mySerial.available()){   <<<<<<<<<<
      Serial.write(mySerial.read());
    }
    while (Serial.available()>0) {  
      mySerial.write(Serial.read());
    }
    if (Button(btnReverse)) {
      while (Button(btnReverse)) {}
      mode=0;
    }
  }

If serial is getting data constatntly the second loop gets no time

try to replace it with

while (mode==3) 
{    
  if (mySerial.available()) Serial.write(mySerial.read());
  if (Serial.available()>0) mySerial.write(Serial.read());
  if (Button(btnReverse) == HIGH)   // more explicit
  {
    while (Button(btnReverse) == HIGH ) ;  // wait for release
    mode=0;
  }
}

Now the code check both directions alternatingly

There must be a more fundamental problem with SoftwareSerial.
I made the tightest possible loop to see how much could be received flawlessly.

This code

    while (1==1) {
      while (mySerial.available()) Serial.write(mySerial.read());
      while (Serial.available()) mySerial.write(Serial.read());
    };

is better than this code:

    while (1==1) {
      if (mySerial.available()) Serial.write(mySerial.read());
      if (Serial.available()) mySerial.write(Serial.read());
    };

Errors begin after approximately 175 characters.
For example:

$0 = 200.000 (steps/mm x)
$1 = 200.000 (steps/mm y)
$2 = 200.000 (steps/mm z)
$3 = 50 (microseconds step pulse)
$4 = 250.000 (mm/min default feed rate)
$5 = 250.000 (mm/min default ee rae)
$ =0.00(m/ac sgmnt
7  20 stp or ivet msk bnay  10000)
8  1.00 acelraioni m/se^2
9  005 (orerig untin evaton n m)
$x=ale'tose praete o jst'$ t dmpcuren sttng
k

Here the errors start at the line beginning with $5.

Do you send anything while receiving? I'm asking because the SoftwareSerial disables interrupts while sending out characters but the reception of characters is depending on a timely handling of an external interrupt. You cannot use SoftwareSerial for sending and receiving characters simultaneously. The hardware serial is able to do that. You might want to change to a Mega, it has 4 hardware serial interfaces.

No, I'm not sending and receiving by SoftwareSerial at the same time. In my test I send a $-sign to the GRBL-Ardiono, and then it respond with a dump of current settings ad shown on this page: Home · grbl/grbl Wiki · GitHub

AllanB:
There must be a more fundamental problem with SoftwareSerial.
I made the tightest possible loop to see how much could be received flawlessly.

This code

    while (1==1) {

while (mySerial.available()) Serial.write(mySerial.read());
      while (Serial.available()) mySerial.write(Serial.read());
    };



is better than this code:


while (1==1) {
      if (mySerial.available()) Serial.write(mySerial.read());
      if (Serial.available()) mySerial.write(Serial.read());
    };

What does "better" mean in this context? The two version differ primarily in the earlier handling of reads from the hardware serial which implies a write to the SoftwareSerial. You're telling that a write does not happen. In this case the two versions act almost identical. What happens if you take out the second if line and write the necessary command to the SoftwareSerial before entering the while loop?

while (1==1) {
      while (mySerial.available()) Serial.write(mySerial.read());  <<<<<<<<<<< this line can deadlock 
      while (Serial.available()) mySerial.write(Serial.read());  <<<<<<<<<<<<< preventing this to execute which may encounter a buffer overflow....
    };

Sometimes people put a delay(1) in these tight loops to give the serial port time to process.

Have you tried higher baudrates BTW?

@Pylon better in this context is that more data and fewer faults. There's approximately 400 bytes of data received by SoftwareSerial. In best cases I faults begins after 174 bytes. In worst cases I only receive 70 bytes.
@robtillaart I have tried using different baud-rates, then I don't receive anything. I cant change the rate of the GRBL Arduino. If I use delays, I lose data.
I seems that I got to collect the data from SoftwareSerial as quick as possible.
I have tried to collect the data received by the SoftwareSerial connection in a String in my while loop and then write them back to the computer via Serial. That gave me only 100 bytes out of 400.
My conclusion is that I got to buy a Mega end skip SoftwareSerial.

Do you have a scope? If yes, you could activate the debug feature of SoftwareSerial (line 35-37 of SoftwareSerial.cpp) and get pulses on debug pins when the serial data is being read. This allows you to check the timing of the software implementation and maybe get a sense for what's going wrong.