Writing to multiple serial ports without delay


#1

I am doing a large scale LED project using processing and STM32.
processing converts the video data into led pixel data and sends them to STM32 controllers.
each controller controls about 1200 LEDs.
each controller is connected to computer using a USB CDC serial port.
i was successfully able to send LED_DATA to one STM32 controller and display it on LED screen.

But when i will be using multiple serial ports(lets say 12) there would be delay between the time at which data is written to first serial and the 12th one.

I wanted to know
1)how to measure this delay.
2)how to send data simultaneously to all serial ports.

If anyone needs to the see the code i can post it.


#2

Are you sending 1200 LEDs to the first controller, then 1200 LEDs to the second controller, et cetera?

Could you instead loop over the pixels[] array and send LED 1 to each controlled , then LED 2 to each, et cetera? Not familiar with the STM32.


#3

Are you sending 1200 LEDs to the first controller, then 1200 LEDs to the second controller, et cetera?

Exactly.
Concider STM32 controllers similar to arduino.

I wanted a way so that we can send data to multiple controllers simultaneously.

Could you instead loop over the pixels[] array and send LED 1 to each controlled , then LED 2 to each, et cetera?

did not understand.


#4

If you are doing this:

for(int c=0; c<12; c++){
  for(int p=0; p<1200; p++){
    send(c, p);
  }
}

…could you do this?

for(int p=0; p<1200; p++){
  for(int c=0; c<12; c++){
    send(c, p);
  }
}

#5

firstly sorry for the late reply

i still don’t understand what you are saying.
is C the serial port and p the led data.

this is my current code:

Serial myPort;  // The serial port
byte[] leddata = new byte[3600]; // 3  byte for each LED's RGB data
void draw() 
{
myPort.write(leddata);
}

the code has all the setup and draw loop not shown here.

this is one leddata array.
i have multiple arrays and multiple ports and i want to write data to each port simultaneously,
because if i do this

Serial myPort1;  // The serial port
Serial myPort2;
byte[] leddata1 = new byte[3600]; // 3  byte for each LED's RGB data
byte[] leddata2 = new byte[3600];
void draw() 
{
myPort1.write(leddata1);
myPort2.write(leddata2);
}

there would be a delay between controller one and controller two receiving data.
i don’t want that delay to be there.

Thank you


#6

So, if you have a setup something like this:

Serial[] myPorts;
byte[][] leddata;
int DEVICES = 12;
int LEDS = 3600;

void setup(){
  myPorts = new Serial[DEVICES];
  // assign ports
  leddata = byte[DEVICES][LEDS];
  // import
}

…then one thing to do might be to walk across your led data in an outer loop, and send only part of it – a subrange of LEDs, like 100, or 300, or 600 - to each device in the inner loop. Then, in the outer loop, advance to the next chunk, and send that chunk to each of the 12 devices in the inner loop. And so on, until your outer loop has moved through all 3600 LEDs, and the inner loop has finished all 12 devices for the last chunk.

int chunk = 100;
for(int i=0; i<3600; i=i+chunk){
  for(int j=0; j<DEVICES; j++){
    // send a chunk of leddata[j][i]-to-[j][i+chunk-1]  to that device
  }
}

Maybe people with more serial experience will have additional feedback on whether that approach is worth trying.


#7

ok got what you were trying to say.
but the problem sending data in chunk causes a additional delay in the entire transmission process.

Thank you so much.


#8

A core issue is, you can either send that much information with your hardware in real time or your can’t. If you can’t, there will be delay – you just have to decide where the delay will happen. You can synchronize on scan lines, or on chunks, or on whole frames – so synchronizing on scan lines or chunks will drop your frame drawing time, but the frames will be in sync. You can’t send a million cars between two cities, and then a million trucks, and have them all arrive at the same time because: roads. However, you can send 100 of each in repeated turns and the arrivals of both will remain more or less constant.

Some other alternatives:

  1. send less data
  2. use faster hardware
  3. pre-render and cache the data locally so that it doesn’t have to be sent over the wire, then synchronize playback from local data based on shared clock or sending simple frame data over the wire
  4. have multiple playing computers that are synchronized, each one feeding data to only one (or fewer) serial ports
  5. experiment with multi-threaded solutions using thread() or java Thread – although if this is a bandwidth issue then results will probably be little different from the chunk solution I already suggested.

I would love to see people with more serial experience weigh in on this – particularly re:multiple devices and bandwidth. But if it is bandwidth, I think there is no magic bullet.


#9

understood.
lets see what others have to say


#10

What baud rate are you using for communication? How fast are you expecting?
At 115000 bit/s
10 bits per byte (1 start, 1 stop, 8 data)
x3600 bytes = ~1/3 sec per device

To measure the time, you could grab millis() before then after sending each frame.
Perhaps have the STM32 reply when complete.


#11

I am using USB CDC for communication.

The STM32 micro-controllers have these inbuild.

so when i connect the device using usb micro to the computer it shows up as COM port (because of the drivers)but is actually a USB 2.0 device capable of 12Mbits/s( i guess) communication speed.
I tested the time gap it was around 30ms, from STM32 initiating the request to receving the entire array on the controller.


#12

As @jeremydouglass suggested, multi-threading is likely your best bet if using a single PC. Different hardware, different options.

I suspect you would see some slowing by spreading the cpu over multiple channels but the group would still finish earlier than in sequence.

3600 bytes in 30mS is pretty fast (~1.2Mbits/s). Makes sense if the communication is more USB than a UART.:thinking:

I am curious to see your code if you would not mind showing it.


#13

here is the code

import processing.serial.*;

Serial myPort;  // The serial port
byte[] buff = new byte[3600];
int i;
int k=0,init=0;
String report = "!";
String ack = "0";
String request = "0";
String incoming ;
void setup()
{
  printArray(Serial.list()); // List all the available serial ports
  myPort = new Serial(this, Serial.list()[0], 9600);// the speed stated here does not matter
                                                    //  the serial port works at full 12Mbit/s speed
  
  //fill the transmit buffer
  for(i=0;i<3600;i++)
  {
    buff[i] = (byte)k;
    k++;
    if(k==256)
    k=0;
  }
  //check the connecion with stm32 controller
  while(init==0)
  {
   myPort.write(report);
   delay(1000);
      while (myPort.available() > 0) 
       {
         ack = myPort.readString();
       }
        println("checking");
        println(ack);
      if(ack.equals("OK") == true)
       {
         println("connection to STM32 is successful");
         init = 1;
       }
  }
}

void draw() 
{
  while (myPort.available() > 0)
   {
    request = myPort.readString();//request generated by STM32 for ledData
   }
   
  if(request.equals("<") == true)
   {
     //for(i=0;i<3600;i++)
       // {
         myPort.write(buff);
       // }
      request = "0";
      println("snet one frame data");
      delay(1000);
      while (myPort.available() > 0)
         {
         incoming = myPort.readString();//the time delay in Millisecond calculated by the STM32
          println(incoming);
         }
   }
}

Please tell how to do multi threading


#14

I imagine you would want some kind of producer/consumer setup.
Producer: prepares a frame, adds it to a queue
Consumer: waits for request on USB, pulls from the queue, writes frame to USB

Need to have a pair to handle each of the STM32’s.
Shared resources may be troublesome… though reading from memory should be less of problem.
Maybe you could get away with a single producer for the lot.

Are you generating the data from individual frames of video or would one STM32 control a portion of the same video?

There are a few examples at java2s.
http://www.java2s.com/Code/Java/Threads/Producer-Consumer.htm
More topics:
http://www.java2s.com/Code/Java/Threads/CatalogThreads.htm

Not sure I could walk you through it. Certainly not at this hour. :arrow_right: :coffee:


#15

Maybe a solution is to send all your data like you are doing but tell your STM32 to wait for a signal to actually use that data.

So then you can send a “go” to all your devices one after another, but since it will be very little information, it would be fast enough to appear in sync.


#16

Hmm… I may have misunderstood the primary issue.

Do you think you will have trouble getting all data down the line in time or more concerned with getting the displays to update at the same time?

I realize one of those things can lead to the other.
Assuming the data gets there fast enough you could synchronize the STM32s via a circuit.


#17

Each STM32 has an internal counter which knows when all the data has arrived(since the data send to each controller is fixed 3600 bytes)

Each controller knows when they have received the entire data.
but is there a way to know which one will receive the entire data last.
if there is then i can make the that one create a signal for all other controllers to start displaying the data.

I am more concerned about the frame rate.
at 30ms per controller I am getting a frame rate of 30fps theoretical .
i will having almost 20 controllers which reduces the frame rate.
so I wanted a way so that each one can receive the data at the same time.


#18

If you have a counter for the data then send all the data except one to each controller.

When it is done, send the last data to each controller. It should be fast enough so they all receive that last data almost at the same time and thus make it look like they are in sync


#19

@jb4x 's suggestion would not add hardware and get the job done. :slightly_smiling_face:

An external circuit might simplify your code, so there is a tradeoff.

You could have the controllers watch a common signal and connect them as an AND logic circuit:
ANDGateLogic


#20

Ok
Thank you so much for helping me