Arduino<->Arduino Software Serial only 3 bytes at once?

Hi,

I was just testing serial communication between two Arduinos (Pro Mini and Diecemilla, Arduino 1.0.1 IDE). Using Software Serial the connection is no problem, bytes gets transmitted.

However, using this code:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

void setup()  
{
  // Open serial communications and wait for port to open:
  Serial.begin(57600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  Serial.println("Goodnight moon!");
  // set the data rate for the SoftwareSerial port
  mySerial.begin(4800);
  delay(100);
  mySerial.println("Hello, world?");
}

void loop() // run over and over
{
  if (mySerial.available())
    Serial.write(mySerial.read());
  if (Serial.available())
    mySerial.write(Serial.read());
}

all what gets through is a maximum of 3 bytes (chars). So if I send "abcdefg" on one side, "abc" is received.

Is that a bug or normal behaviour? If the later, how to write code to bypass this problem?

My final goal is not to communicate between two Arduinos, this is only a testcase for a needed 8E2 (next problem :drooling_face:) serial communication...

Best Regards,
Carsten

However, using this code...

Are you using that same code on both Arduinos?

  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

Do you have a Leonardo? If not, get rid of this.

  mySerial.begin(4800);
  delay(100);
  mySerial.println("Hello, world?");

Why are you delaying? Do you expect that delay() to have some magical properties? It doesn't. The begin() method doesn't return until the SoftwareSerial instance is ready to send data. Sitting around doing nothing for a while doesn't accomplish anything.

Describe exactly the connections between the two Arduinos, and between the Arduinos and the PC(s).

Hi,

Are you using that same code on both Arduinos?

Yes.

Do you have a Leonardo? If not, get rid of this.

No Leo, however it does change nothing.

Why are you delaying? Do you expect that delay() to have some magical properties? It doesn't.

I don't belive in magic, however, due to some timing differences (or whatever, I don't know exactly, so maybe I can call it magic then ;-)) the sign of life println("Hello, world?"); does not come trough without the delay()...

The Boards are connected Common Ground, RX and TX crossed with short patch cables. No errors, just the problem that no more than 4 (3 chars and Lineend or 4 chars w/o CR) are transmitted when sending a whole line. The println("Hello, world?") suggests that it is not a problem in sending but in receiving. I also tested this with a simple "parser" returning a whole line by println() when a "A" was received.

I am using the Arduino IDE Serial Monitor to send the line. Using putty.exe shows no loss when sending byte for byte, but also transmits only 3byte (plus CR) when set to linemode...

Carsten

I don't belive in magic, however, due to some timing differences (or whatever, I don't know exactly, so maybe I can call it magic then ;-)) the sign of life println("Hello, world?"); does not come trough without the delay()...

Doesn't make sense, unless the delay() is necessary for the other end to wake up and get ready. Possible.

The Boards are connected Common Ground, RX and TX crossed with short patch cables.

I see you remembered the most important part - the ground. Good.

Some things I'd suggest changing:
Move the Serial.print() statement after initializing the SoftwareSerial instance.
Use the same baud rate for the HardwareSerial instance (Serial) and the SoftwareSerial instance (mySerial - lousy name).
Put different sketches on the two devices. Each should send an initial string that is not the same.

I experimented a bit more. The connection is stable.

Sending with myserial.print("") works and gets all bytes through. So it has something to do with the sending or the receiving from the hardware serial.

Quite strange. Testing further now...

Carsten

Using the SoftwareSerial and the hardware serial at the same time may get you into trouble. The hardware serial is sending and receiving characters with interrupts (after the reception of a character the interrupt is triggered, so the character can be copied to the buffer, similar for the sending side), while the SoftwareSerial is just using an interrupt for the reception of the start bit. After that it's using delay loops (not delay()!) to look for the following bits. If a receiving or sending interrupt of the hardware serial is still running while the RX pin of the SoftwareSerial interface is activated, that interrupt is delayed till the former interrupt handler has finished it's work. That delay is propagated to all following bits, resulting in possible errors. The more traffic you have on the hardware serial the more likely an error is. Because you have tied the SoftwareSerial and hardware serial together by code (receiving on one and sending to the other) errors in the same recurring pattern are quite likely. The higher the baud rate the more likely the little delay from the former interrupt routine is causing errors.

calli:
all what gets through is a maximum of 3 bytes (chars). So if I send "abcdefg" on one side, "abc" is received.

Maybe you need to specify how much the Serial.print() needs to print.
If you take a look at this:

Best regards
Anders

I can't say what it was. After some time it started working, even with the old test sketches. Since the beginning I disassembled the hardware some times, tried different ways etc. so that I can't nail it down to a hardware or similar problem. maybe it was a some mixup in the libraries, but atm I don't have time to recreate the old configurations.

Carsten

Hi

well, had the same issue and tried to solve it the whole afternoon :drooling_face:

The solution : the Software serial have to run faster than the Hardware serial ( e.g. for example : 1200 for HW and 2400 for SW )...

Great tip! Thats probably also the reason why it worked one time :stuck_out_tongue_closed_eyes:

Carsten

Hi, people, I'm getting a similar problem.

I'm triying to control a brake pedal with a linear actuator. I have the next configuration.

One arduino Nano is reading an incremental encoder (from the linear actuator) by interruptions and sending the value of the counter to an Arduino UNO, every 20 ms.

The arduino UNO reads the value with the recvWithEndMarker()[/b] function, proposed by @Robin2 at this great post about Serial communication , every 20 ms (I tried with both arduinos at 20 ms, but the problem persist)
When the counter is one or two digits there is no problem, the communication behaves stable, but when the counter is 3 digits long sometimes the UNO receives only two digits, as you can see in the next sample (crt for current position, tgt for target position).
** **B_pos(crt: 89, tgt: 123), B_err:34 B_pos(crt: 90, tgt: 123), B_err:33 B_pos(crt: 92, tgt: 123), B_err:31 B_pos(crt: 93, tgt: 123), B_err:30 B_pos(crt: 93, tgt: 123), B_err:30 B_pos(crt: 94, tgt: 123), B_err:29 B_pos(crt: 95, tgt: 123), B_err:28 B_pos(crt: 97, tgt: 123), B_err:26 B_pos(crt: 98, tgt: 123), B_err:25 B_pos(crt: 98, tgt: 123), B_err:25 B_pos(crt: 99, tgt: 123), B_err:24 B_pos(crt: 100, tgt: 123), B_err:23 B_pos(crt: 10, tgt: 123), B_err:113 B_pos(crt: 102, tgt: 123), B_err:21 B_pos(crt: 102, tgt: 123), B_err:21 B_pos(crt: 10, tgt: 123), B_err:113 B_pos(crt: 106, tgt: 123), B_err:17 B_pos(crt: 10, tgt: 123), B_err:113 B_pos(crt: 111, tgt: 123), B_err:12 B_pos(crt: 111, tgt: 123), B_err:12 B_pos(crt: 11, tgt: 123), B_err:112 B_pos(crt: 115, tgt: 123), B_err:8 B_pos(crt: 118, tgt: 123), B_err:5 B_pos(crt: 119, tgt: 123), B_err:4 B_pos(crt: 119, tgt: 123), B_err:4 B_pos(crt: 12, tgt: 123), B_err:111 B_pos(crt: 12, tgt: 123), B_err:111 B_pos(crt: 12, tgt: 110), B_err:98 B_pos(crt: 126, tgt: 92), B_err:-34 B_pos(crt: 126, tgt: 67), B_err:-59 B_pos(crt: 12, tgt: 43), B_err:31 B_pos(crt: 128, tgt: 24), B_err:-104 B_pos(crt: 128, tgt: 12), B_err:-116 B_pos(crt: 125, tgt: 0), B_err:-125 B_pos(crt: 125, tgt: 0), B_err:-125 B_pos(crt: 12, tgt: 0), B_err:-12 B_pos(crt: 115, tgt: 0), B_err:-115 B_pos(crt: 112, tgt: 0), B_err:-112 B_pos(crt: 108, tgt: 0), B_err:-108 B_pos(crt: 108, tgt: 0), B_err:-108 B_pos(crt: 10, tgt: 0), B_err:-10 B_pos(crt: 98, tgt: 0), B_err:-98 B_pos(crt: 96, tgt: 0), B_err:-96 B_pos(crt: 93, tgt: 12), B_err:-81 B_pos(crt: 93, tgt: 12), B_err:-81 B_pos(crt: 89, tgt: 12), B_err:-77 B_pos(crt: 85, tgt: 12), B_err:-73 B_pos(crt: 82, tgt: 0), B_err:-82 B_pos(crt: 78, tgt: 0), B_err:-78** **
When this happen the error value gets high and the actuator start to oscillate.
Both Arduinos are working at 115200 bauds, both with hardware serial. I try at 38400 first but the same behavior appears.
Arduino Nano Code.
```
**#include <Arduino.h>
// Rotary Encoder Inputs
#define CH_A 2 // Cable verde encoder.
#define CH_B 3 // Cable negro encoder.

int counter = 0, lastCounter = 0;

int currentStateCH_A;
int lastStateCH_A;
String currentDirection = "";

long lastTime = 0, currentTime = 0;

unsigned int period = 25;

void updateEncoder(){
    // Read the current state of CLK
    currentStateCH_A = digitalRead(CH_A);

// If last and current state of CLK are different, then pulse occurred
    // React to only 1 state change to avoid double count
    if (currentStateCH_A != lastStateCH_A  && currentStateCH_A == 1)
    {
        // If the DT state is different than the CLK state then
        // the encoder is rotating CCW so decrement
        if (digitalRead(CH_B) != currentStateCH_A)
        {
            counter ++;
            currentDirection = "CCW";
        } else
        {
            // Encoder is rotating CW so increment
            counter --;
            currentDirection = "CW";
        }
    }
    // Remember last CLK state
    lastStateCH_A = currentStateCH_A;
}

void setup() {
    // Set encoder pins as inputs
    pinMode(CH_A, INPUT); // (CLK)
    pinMode(CH_B, INPUT); // (DT)

// Setup Serial Monitor
    //Serial.begin(38400);
    Serial.begin(115200);

// Read the initial state of CLK
    lastStateCH_A = digitalRead(CH_A);

// Call updateEncoder() when any high/low changed seen
    // on interrupt 0 (pin 2), or interrupt 1 (pin 3)
    attachInterrupt(0, updateEncoder, CHANGE);
    attachInterrupt(1, updateEncoder, CHANGE);

lastTime = millis();
}

void loop() {
    //Serial.print(" | Counter: ");
    //Serial.println(counter);
    currentTime = millis();
    if( (currentTime - lastTime) >= period )
    {
        if(lastCounter != counter)
        {
            Serial.println(counter);
            lastCounter = counter;
        }

lastTime = currentTime;
    }
}**
** **Simplified Arduino UNO Code** **
**const byte numChars = 32;
char receivedChars[numChars];

bool newData = false;
int dataNumber = 0;

long currentTime = 0, lastTime = 0, peri
uint8_t periodoDeseado = 20;

int BrakeActuator_Pos;

void recvWithEndMarker()
{
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;

//if(Serial.available() > 0 && newData == false)
    while(Serial.available() > 0 && newData == false)
    {
        //Serial.println("Entré a Serial.available()");
        rc = Serial.read();

if(rc != endMarker)
        {
            receivedChars[ndx] = rc;
            ndx++;
            if(ndx >= numChars)
            {
                ndx = numChars - 1;
            }
        } else { // rc == endMarker
            receivedChars[ndx] = '\0'; //Caracter de fin de cadena
            ndx = 0;
            newData = true;
            //break; // Esto si se usa while en lugar de if.
        }
    }
}

void recoverIntData(int* positionVariable)
{
    if(newData)
    {
        dataNumber = 0;
        dataNumber = atoi(receivedChars);

*variablePorAsignar = dataNumber;
        newData = false;
    }
}

void setup()
{
    Wire.begin();

//Serial.begin(19200);
    //Serial.begin(38400);
    Serial.begin(115200);
    Serial.println("Comm init.");
}

void loop()
{
currentTime = millis();
if( (currentTime - lastTime) >= period )
    {
recvWithEndMarker();
        recoverIntData(&BrakeActuator_Pos);
       
        Serial.print(", B_pos(cnt: "); Serial.print(ActuadorFreno_Posicion);
        Serial.print(",\t tgt: ");    Serial.print(ActuadorFreno_PosDeseada);
        Serial.print(")");
       
        // Other stuff...
}
}**
```

We already try using the recvWithStartEndMarkers() function, incrementing the period of the Nano to 25 ms, lowering the baudrate of both arduinos to 38400 bps and making an offering to Odin, with no satisfactory results.
Any tips or references that we can review?
Thanks in advance, people!