2560 serial ports conflicts?

I am using one 2560 as a master to receive data from 4 slave 2560s via serial ports. Because each slave sends 1000 data points per second and each data point is a 7-byte char array ends with ; ( example abcdefg; ) using Serial.print(). I expect the 2560 to work very fast. I had the digital pin 11 of the 2560 to be set high and low once in each iteration, using setBit()so I can monitor the loop rate of it using an oscilloscope. I found something strange, when I only monitor serial0 (code1 ), I found the 2560 runs at a 45KHz loop rate. When I try to monitor the both the serial0 and serial1 (code2 ), I found the 2560 runs at about 30KHz for 30 seconds or so and then slows down to ~ 1.2KHz. After that slow down, if I send data to the 2560, it will not resend it to the right port (before it slows down, it would). I reset the 2560 and tried several boards and this happens from time to time. Note even I don't send any data to it, it still slows down after a while. So I wonder why does this happen? Another strange thing is while I sending data to this master 2560 through serial0, it would not reboot even I held and pressed the reset button. Another strange thing is when I sent abcdefg;, the 2560 receives and resend abcdefgd sometimes.

I guess I have two questions: 1. Why checking extra serial ports takes so much time and is there a way to speed it up, do the four ports share the same interrupt ? 2. Why does it automatically slow down? This is not a high speed circuit...

I split the serial0, using its tx to send the total data to pc via its usb cable, connecting its rx to one of the four slaves. Using other three serials to connect to other three slaves as usual.

The whole system works fine when the data rate of each slave is 19Hz.

Thanks a lot!

Code1:


char buf1_BUF[8];  
char buf2_BUF[8];  
char buf3_BUF[8]; 
char buf4_BUF[8];  

char buf1 = 'a';
char buf2 = 'a';
char buf3 = 'a';
char buf4 = 'a';

int i = 0;
int i1 = 0;
int i2 = 0;
int i3 = 0;
int i4 = 0;


void setup() {

  Serial.begin(500000);   
  Serial1.begin(500000);  
  Serial2.begin(500000);  
  Serial3.begin(500000);  

  bitSet(DDRB, 5);  //SET PIN 11 TO OUTPUT.

}

void loop() {
  
  bitSet(PINB,5);

  if (Serial.available() > 0) {  
    buf1 = Serial.read();

    if (buf1 == ';') {
 
      i1 = 0;

      Serial.println(buf1_BUF);

      Serial.println('A');

    } else {
      buf1_BUF[i1] = buf1;
      i1++;
    }
  }
  bitSet(PINB,5);

Code2:


char buf1_BUF[8];  
char buf2_BUF[8];  
char buf3_BUF[8]; 
char buf4_BUF[8];  

char buf1 = 'a';
char buf2 = 'a';
char buf3 = 'a';
char buf4 = 'a';

int i = 0;
int i1 = 0;
int i2 = 0;
int i3 = 0;
int i4 = 0;


void setup() {

  Serial.begin(500000);   
  Serial1.begin(500000);  
  Serial2.begin(500000);  
  Serial3.begin(500000);  

  bitSet(DDRB, 5);  //SET PIN 11 TO OUTPUT.

}

void loop() {
  
  bitSet(PINB,5);

  if (Serial.available() > 0) {  
    buf1 = Serial.read();

    if (buf1 == ';') {
 
      i1 = 0;

      Serial.println(buf1_BUF);

      Serial.println('A');

    } else {
      buf1_BUF[i1] = buf1;
      i1++;
    }
  }


  if (Serial1.available() > 0) {
    // digitalWrite(9, HIGH);
    buf2 = Serial1.read();
    if (buf2 == ';') {
      i2 = 0;
      // Serial.println(micros());
      Serial.println(buf2_BUF);
      //  Serial.println(micros());
      // buf2_BUF = "";
      // break;
      Serial.println('B');
    } else {
      buf2_BUF[i2] = buf2;
      i2++;
    }
  }
  
  bitSet(PINB,5);

You need to make sure that you never overwrite the buffers (buf1_BUF, buf2_BUF, etc). You are incrementing i1, i2, etc, but never checking for an out-of-range value.

Serial.println() needs a null-terminated char array, but nowhere does your code insert this null terminator.

You state the data being received is a 7-byte char array, how is this being sent? if you are using println() when sending the data, a carriage return and linefeed will be included, making it 9 bytes and unable to fit in your buffers.

if your data is 1000 *7 bytes that is 7000 bytes/second - can a mega cope with more than one of these?
maybe worth trying an Arduino Due but you have to convert the UNO 5V logic to 3.3V

Oh. I just updated the original post. Every data point I send looks like 123456; . It always ends with ;. So in the 2560 script, it checks ; and resets i1~ i4. So in principle, i1 to i4 should never be beyond 8.

The mega itself has no problem with that speed.
The Serial output will be able to handle that data rate, given the sample code. 500,000 baud allows for 50,000 chars/second, or 12,500 char/second per input (with all four inputs). The data being sent per serial line is 1000 * (7 + 2 + 1 + 2) (characters plus carriage returns and line feeds) or 12,000 characters per second.

Yes. this is part of the test to see how much percent this 2560 can do to achieve this. But even before I send data to the 2560, it slows down by itself...

I am trying the due, but once I sent the baud rate to 500000, I can't get the correct information from the serial monitor.

How is everything connected? With no data being sent to the 2560 there should not be anything to slow it down, unless you are getting some spurious signals on the serial RX lines causing random characters to be received.

Clarification, please. You have 4 devices talking to the Mega, plus you use Serial monitor; how is that being done? I only see four Serial.begin().

Just to be on the safe side, I would use pinMode() and digitalWrite() instead of bitSet(), don't think that would affect anything since port B is not involved with any of the serial lines, but code speed is not going to be a problem here.

Oh, I split the serial0, using its tx to send the total data to pc via its usb cable, connecting its rx to one of the four slaves.

1 Like

Gotcha. Ok. Is your serial output to the Serial Monitor backing up? There's an output queue, and if it fills up then Serial.print() becomes a blocking process. Be careful to do the math on your output to Serial.Monitor, counting up all the bytes being sent.

Just a warning, if the 2560 is slowing down too much, you may start overrunning the serial input buffers, which will eventually start overrunning the buffers in your code if the semicolon gets lost on a transmission.

I tested both the digitalWrite way and the current one, the digitalWrite one is way slower. I followed other treads.

I think the bottleneck here is the main loop, if it can reach 50kHz, then it is safer to say this is achievable.

what library are you using on the UNOs to transmit data at 500000baud
using SoftwareSerial on a UNO transmiting to Serial1 of a Mega I get garbage over 300000baud

Use the hardserial please, I found the soft ones are slower. The most recent results are from four slave 2560s.

I experience the slow down before feeding any data to the main 2560. And I increased the size of the buffers to 5120 bytes in the serial h file.

Ok, lets try for maximum speed then.
Put only a single bitSet(PINB, 5) in loop, the oscilloscope will show 1/2 the frequency but will take less processing time.
Put the entire code within a while() loop, to avoid the small overhead involved in calling loop from main.

void loop() {
  while (true) {
    bitSet(PINB, 5);
    //remainder of code
  }
}

just hacked a quick thing together

this seems to be able to check the 4 Serial ports ~60000 times per second (when there is nothing coming)

don't call available(), just read and check against -1 to see if there was something pending

Slowing down with no signal being fed into the serial ports does not make since, the initial loop speed should not slow down if no serial is ever available. Are the serial ports connected to anything at that time? Do you have the UNOs connected and powered off? That might show a low on the serial input, which might mess up the serial receive.

Okay. after this modification, the code2 shows the following result (without feeding any data, without connecting to anything, only 5v and gnd wires connected, not even usb cable):

arduino 2560 #1 (official arduino 2560) freq: 470Hz

arduino 2560 #2 (an 2560 clone with ch340 chip on it) freq: 478Hz for about 10 seconds and then changed to 618Hz.