Send one Mesage via multiple Serial Interfaces simultaneously?

Hi,

I'm wondering, if it is possible to send messages via multiple Serial Interfaces at the same time? At the moment I'm sending one Message via Serial1 and then the same Message via Serial2. So far i couldn't find any information about this topic in this forum.

Thanks.

What exactly are you trying to do ? What means for your project "at the same time" ?

Well, kind of... The hardware can send one byte at a time. After that one byte you have to load another. This can be done either by waiting around (are you ready yet? Are you ready yet?) after each byte so you can send the next or, you can do it via interrupts where you load a byte and then go do whatever else you want. Then when the hardware is ready for another character it fires an interrupt and if the serial buffer has a character it will automatically load it and resume your program again. This is faster from your program's perspective as you aren't sitting around waiting to send characters.

Because I wanted interrupt driven serial transmission I helped to get that added to the Due core a couple of years back. So, all the UARTS on the Due are interrupt driven for both receive and transmit. This means if you are sending less characters than the buffer size (128 bytes) your program will immediately return when you call something like Serial.write or Serial.println. And that means you can then go do Serial2.print immediately. This will cause them both to send at the same time. However, if you start sending a lot of data and you cause a back up (say, you sent 100 bytes then almost immediately try to send 100 more) then it will block on whichever serial port you are trying to send too much data to. All serial ports with pending transmissions will still be sending at the same time but you won't get back to your program until the plugged up data is cleared out. In the above example you are sending 200 characters but the buffer is 128 long. The first character gets sent immediately so you can take 129 characters right away. That leaves 71 characters pending. The routine will thus block for 71 bytes or about 710 bit times. During this time interrupts fire and all serial ports will send but if the rest had only a little bit of data then they'll run out of characters while you are still clearing out the 71 extra characters. Once you get to the end of the 71 characters (with 128 characters still buffered) the routine will exit and you'll be able to run your program again.

So, the answer is that you can send on multiple serial interfaces right this second but you must ensure you do not buffer up more than 128 characters to any serial port or you'll face a blockage.

I hope this thoroughly answers the question.

Thank you for your replies so far.

I'm thinking of a solution, that I'm putting one byte after another into two serial interfaces and use something like Serial1_2.write("Foo");

AdderD:
So, the answer is that you can send on multiple serial interfaces right this second but you must ensure you do not buffer up more than 128 characters to any serial port or you'll face a blockage.

I hope this thoroughly answers the question.

Ok, does this blockage even occur if I alter the buffer size to 512Byte?

van_iKE:
Ok, does this blockage even occur if I alter the buffer size to 512Byte?

The 128 byte buffer is part of RingBuffer in the Due core. The way it is currently coded you'd have to change the size of all ring buffers. If you switch them all to 512 you would then be able to buffer that many characters per serial port before blocking. But, it would also enlarge the serial receive buffer to that size. At 512 bytes each serial port takes up 1k of RAM. This may or may not be good for you but isn't ideal for everyone. So, feel free to modify the Due core if you'd like. Set it to 1k if you want. Set it to 4k if you want. Just remember that changing the core ties the compiling of your sketch to that specific computer unless you actually fork the core on Github and then distribute your forked copy to all machines that need to compile it. If you alter the RingBuffer size (it's in RingBuffer.h) then you will be able to send more bytes before blocking. But, the serial port will still be the same speed so all you'd be doing is buying yourself a bit more time between feeding the serial ports. Depending on how the sketch is coded this might be desirable or you might be able to just hit your sending routines more frequently to keep things fed.

I bet for an XY problem and you didn't answer my questions.

Anyway, if you want to send messages via multiple serial interfaces at the same time, you send these messages via an AHB DMA (one for each USART) and you enable all DMA channels at the same time.

See an example sketch here, reply #5:

AdderD:
The 128 byte buffer is part of RingBuffer in the Due core. The way it is currently coded you'd have to change the size of all ring buffers. If you switch them all to 512 you would then be able to buffer that many characters per serial port before blocking. But, it would also enlarge the serial receive buffer to that size. At 512 bytes each serial port takes up 1k of RAM. This may or may not be good for you but isn't ideal for everyone. So, feel free to modify the Due core if you'd like. Set it to 1k if you want. Set it to 4k if you want. Just remember that changing the core ties the compiling of your sketch to that specific computer unless you actually fork the core on Github and then distribute your forked copy to all machines that need to compile it. If you alter the RingBuffer size (it's in RingBuffer.h) then you will be able to send more bytes before blocking. But, the serial port will still be the same speed so all you'd be doing is buying yourself a bit more time between feeding the serial ports. Depending on how the sketch is coded this might be desirable or you might be able to just hit your sending routines more frequently to keep things fed.

Thank you, for your detailed answer. I will keep that in mind.

ard_newbie:
I bet for an XY problem and you didn't answer my questions.

Anyway, if you want to send messages via multiple serial interfaces at the same time, you send these messages via an AHB DMA (one for each USART) and you enable all DMA channels at the same time.

See an example sketch here, reply #5:

DMA UART (Serial)? - Arduino Due - Arduino Forum

Then I will explain my problem in more detail. I have multiple arduinos connected together via serial interfaces and they also have synchronized clocks. When one arduino sends a timestamped message to two other ones the other two should process and verify the timestamp at the same time. I hope this explanation makes it more clear why I need a "parallel" serial.write. Your hint looks like exactly what i need.

van_iKE:
I have multiple arduinos connected together via serial interfaces and they also have synchronized clocks. When one arduino sends a timestamped message to two other ones the other two should process and verify the timestamp at the same time

How do you synchronize your multiple ( what models ?) arduino clocks ?

I have one arduino due which is connected to all the other arduino dues via one digital pin. I attached an interrupt on this pin for every member of the network, so they are waiting for the moment when this pin gets toggled and save the current micros() in a delta variable. So micros()-delta is the synchronized time on every arduino.

This is what I suspected.

Try firstly to set the maximum baud rate between 3 DUEs : Serial1.begin(5250000); and Serial2.begin(5250000)
for the "main" DUE and obviously the same baud rate in the other 2 DUEs, then print the timestamp to receive a single message.

With one active arduino sending messages it looks good, but with multiple active arduinos I'm loosing some messages.

Can Arduino Due reliably receive serial data at 5.25 Mbit/sec speed?

The serial ports do not have FIFOs, so only up to 1.9 us interrupt latency can be tolerated before data loss (assuming 8N1 format - 10 bit times per byte). That's only 160 clock cycles, and just getting in and out of an interrupt takes at least 24 clock cycles on M3, plus any flash wait states. The normal available() and read() approach requires 2 function calls and overhead to access the buffers for every single byte - and that's just for 1 port. Questionable whether Due could keep up for even 1 port sustaining that speed, much less 2 ports.