Is it possible to listen to multiple COM ports at a time?

Hello, I am new to all this so I'd appreciate your patience. I am working on a MIDI project where I use four uC32 boards. I have a USB MIDI keyboard connected to my computer, and I am using it to control the GPIO pins of my uC32 with the help of Hairless MIDI. This setup works great with one board, but Hairless MIDI can only listen to one COM port at a time. Is there a way to listen to multiple COM ports at once using some code or different software? Each uC32 will be coded differently. The choice of having four uC32 boards was to avoid super long wires as they will be placed far apart so I would like to avoid connecting pins together if possible. I am not able to make a ton of changes in terms of hardware and design unless what I am asking is not possible. Any suggestions would be appreciated.

Sure, within your fast loop(), just poll the multiple .available() functions and handle any incoming messages as needed.
Depending on the cycle time of your loop, and the number of ports/traffic will affect the size of buffers.

Often, you should just collect the incoming streams as they arrive, and only parse the buffered data when your app has time to do it properly without holding up other processes.

If any individual message requires ‘blocking time’ to process, you need to consider this in modelling the response times of your code.

One observation... use hardware serial ports !... ideally using interrupts for the buffers. Software serial is a gap-filler, and not suitable for a lot of roles.

The MEGA2560 has four hardware ports, and the RX is interrupt buffered.
The MEGA1284 has two ports but lots more code and data memory... you could add external UARTS, but then you have to provide code to handle them.

I have a USB MIDI keyboard connected to my computer, and I am using it to control the GPIO pins of my uC32 with the help of Hairless MIDI.

So why and how do you use Hairless ?

Is there a way to listen to multiple COM ports at once using some code or different software?

That is the great thing about midi, you can just daisy chain or split using either hardware midi-thru or software midi-thru. Midi has 16 channels so getting the data to the proper device is easy, and the hardware protocol prevents physical electronic connection through the use of opto-couplers.

The choice of having four uC32 boards was to avoid super long wires as they will be placed far apart

How far apart ? midi cables safely run up to 7 meters or more, anything a lot more should probably be done with a RS485 twisted pair setup. How do the UC32 boards communicate now ?

So why and how do you use Hairless ?

Hairless was the only way I could get my USB MIDI keyboard to talk to the uC32. Maybe I’m doing something wrong in my code. I’ll share it for reference. I’m currently using 4 pins but eventually, it will be 48 pins. The plan is to use 12 gpio pins on each uC32. Each uC32 will be responsible for a different octave on the keyboard. Potentially there will be more than one key pressed at once and those keys could be in different octaves, so communicating with multiple uC32’s at once.

#include <MIDI.h>  // Add Midi Library


struct CustomBaud : public midi::DefaultSettings{
    static const long BaudRate = 115200;
};
//Create an instance of the library with default name, serial port and settings
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI, CustomBaud);

void MyHandleNoteOn(byte channel, byte pitch, byte velocity) {
if (channel == 1) //Works only with MIDI channel 10
{
if (pitch == 50)
digitalWrite(2,HIGH); 

if (pitch == 52)
digitalWrite(3,HIGH); 

if (pitch == 53)
digitalWrite(4,HIGH); 

if (pitch == 55)
digitalWrite(5,HIGH); 

}

}

void MyHandleNoteOff(byte channel, byte pitch, byte velocity) {
if (channel == 1)
{
if (pitch == 50)
digitalWrite(2,LOW); 
if (pitch == 52)
digitalWrite(3,LOW); 
if (pitch == 53)
digitalWrite(4,LOW); 
if (pitch == 55)
digitalWrite(5,LOW); 
}
}
void setup() 
{
pinMode (2, OUTPUT);
pinMode (3, OUTPUT); 
pinMode (4, OUTPUT); 
pinMode (5, OUTPUT);
MIDI.begin(1); // Midi channel

MIDI.setHandleNoteOn(MyHandleNoteOn); // This is important!! This command
// tells the Midi Library which function you want to call when a NOTE ON command
// is received. In this case it's "MyHandleNoteOn".
MIDI.setHandleNoteOff(MyHandleNoteOff); // This command tells the Midi Library
// to call "MyHandleNoteOff" when a NOTE OFF command is received.
//MIDI.setHandleControlChange(handleControlChange);
}

void loop() 
{ // Main loop
  MIDI.read(); // Continuously check if Midi data has been received.
}

That is the great thing about midi, you can just daisy chain or split using either hardware midi-thru or software midi-thru. Midi has 16 channels so getting the data to the proper device is easy, and the hardware protocol prevents physical electronic connection through the use of opto-couplers.

Will that still work even though the uC32’s are not MIDI devices? Do you have any suggestions for software midi-thru? I’m on Linux. I have a spare raspberry pi, anyway that can be used as a hardware MIDI thru?

How far apart ? midi cables safely run up to 7 meters or more, anything a lot more should probably be done with a RS485 twisted pair setup. How do the UC32 boards communicate now ?

It should be 6 feet or less so I think I’ll be okay. Right now the uC32’s don’t communicate with each other, I don’t think they will need to but that could change. They are all doing slightly different things with the MIDI data sent because they represent different octaves.

lastchancename:
Sure, within your fast loop(), just poll the multiple .available() functions and handle any incoming messages as needed.
Depending on the cycle time of your loop, and the number of ports/traffic will affect the size of buffers.

Often, you should just collect the incoming streams as they arrive, and only parse the buffered data when your app has time to do it properly without holding up other processes.

If any individual message requires ‘blocking time’ to process, you need to consider this in modelling the response times of your code.

One observation... use hardware serial ports !... ideally using interrupts for the buffers. Software serial is a gap-filler, and not suitable for a lot of roles.

The MEGA2560 has four hardware ports, and the RX is interrupt buffered.
The MEGA1284 has two ports but lots more code and data memory... you could add external UARTS, but then you have to provide code to handle them.

This was informative, thank you. I'll adjust my code and see if I can get things going

Hairless was the only way I could get my USB MIDI keyboard to talk to the uC32.

Assuming that you do have an actual Midi-out on your keyboard, using Midi would be the best way to talk to the uC32.
I am a bit confused as to what you are saying here :

Maybe I'm doing something wrong in my code. I'll share it for reference. I'm currently using 4 pins but eventually, it will be 48 pins. The plan is to use 12 gpio pins on each uC32. Each uC32 will be responsible for a different octave on the keyboard. Potentially there will be more than one key pressed at once and those keys could be in different octaves, so communicating with multiple uC32's at once.

So you have a Usb Midi Keyboard right ? And now you want to make another one with 4 uC32 's ? Or what ? Either way i am pretty sure you are doing something wrong

Will that still work even though the uC32's are not sMIDI devices? Do you have any suggestions for software midi-thru?

Of course! either way it will ! Midi use standard Serial at 31.250 kbps that is a rate at which swSerial is reliably supported. a uC32's has a hwSerial port as well doesn't it. So you can use a midi.h object in which midi thru is standard supported, and add to that, and you can always split midi up in different directions. MIDI
If you insist on connecting as a usb device to your computer, then ControlSurface.h Is the best option.
If you just need more pins, keep in mind that you can also reed switches / keys /sensors by creating a matrix out of your pins. that means that out of 8 digital outputs and 8 analog inputs, you can collect data for 64 analog inputs, and you can do that fast enough for it to be used as a keyboard. Anyway, please explain fully and maybe with the help of a drawing, what it is you want to achieve.

It should be 6 feet or less so I think I'll be okay. Right now the uC32's don't communicate with each other, I don't think they will need to but that could change. They are all doing slightly different things with the MIDI data sent because they represent different octaves.

Ok that's clear, well i would not take it into the pc if that is not needed, just use midi and read the octaves data you want, and use it accordingly.

int incomingByte = 0;
void setup(){
  Serial.begin(9600);
 // Serial1.begin(9600);
  //Serial2.begin(19200);
  Serial3.begin(9600);
delay(1000); 
  Serial.println("Hello Computer");
 // Serial1.println("Hello Serial 1");
  //Serial2.println("Hello Serial 2");
  //Serial3.println("Hello Serial 3");

 



}


void loop() {
  


 if (Serial.available() > 0) {
  incomingByte = Serial.read();
  Serial3.write(incomingByte);
  //Serial.write(incomingByte);
  while (Serial.available() > 0)
    {
    incomingByte = Serial.read();
   Serial3.write(  incomingByte);
 //  Serial.write(  incomingByte);
    }
    
} 

 if (Serial3.available() > 0) {
  incomingByte = Serial3.read();
  Serial.write(incomingByte);
 
  while (Serial3.available() > 0)
    {
    incomingByte = Serial3.read();
   Serial.write(  incomingByte);

    }
} 

 
}

I have this kind of code to use ports 0 and 3. Works in Mega2560.

Assuming that you do have an actual Midi-out on your keyboard, using Midi would be the best way to talk to the uC32.
I am a bit confused as to what you are saying here :

I am using an AKM320 USB MIDI keyboard. I'm not really sure what you mean because I thought I was using MIDI. What I've done so far has been based on other examples I found and they pretty much all use 5 din MIDI controllers, none with USB MIDI. I don't understand why it doesn't work without Hairless MIDI.

So you have a Usb Midi Keyboard right ? And now you want to make another one with 4 uC32 's ? Or what ? Either way i am pretty sure you are doing something wrong

Yes, I do have a USB MIDI keyboard. I am trying to make an hands-free percurssive instrument that will be controlled with the keyboard (So not totally hands-free I guess). If I'm missing something I'm not sure what it is. Did you notice anything wrong in the code I posted earlier? This is my first time working with MIDI.

Anyway, please explain fully and maybe with the help of a drawing, what it is you want to achieve.

I hope the diagram I've attached helps clarify things. Each uC32 will be used to control 12 solenoids. And each solenoid corresponds to a note. And don't worry I am not attempting to power the solenoids off of the uC32's alone. So say for example I was trying to play note 24 and 36 at the same time, I would be sending MIDI to 2 different uC32's. Each uC32 will be coded to handle their respective notes, at least that's the idea.

Ok that's clear, well i would not take it into the pc if that is not needed, just use midi and read the octaves data you want, and use it accordingly.

So the uC32 has a micro USB port and a barrel connector. I'm not sure if you're suggesting to hook up the MIDI keyboard directly up to each uC32 utilizing a female-to-female USB. It's not something I've thought of before and I don't know if it would work.

LMI1:

int incomingByte = 0;

void setup(){
 Serial.begin(9600);
// Serial1.begin(9600);
 //Serial2.begin(19200);
 Serial3.begin(9600);
delay(1000);
 Serial.println("Hello Computer");
// Serial1.println("Hello Serial 1");
 //Serial2.println("Hello Serial 2");
 //Serial3.println("Hello Serial 3");

}

void loop() {

if (Serial.available() > 0) {
 incomingByte = Serial.read();
 Serial3.write(incomingByte);
 //Serial.write(incomingByte);
 while (Serial.available() > 0)
   {
   incomingByte = Serial.read();
  Serial3.write(  incomingByte);
//  Serial.write(  incomingByte);
   }
   
}

if (Serial3.available() > 0) {
 incomingByte = Serial3.read();
 Serial.write(incomingByte);

while (Serial3.available() > 0)
   {
   incomingByte = Serial3.read();
  Serial.write(  incomingByte);

}
}

}



I have this kind of code to use ports 0 and 3. Works in Mega2560.

Thanks! I'll give this a try

What do you need the computer for ? does it serve a purpose other than splitting the data ? because it is actually not very good at that.
You see i would simply use the 5 pin din Midi-out from the keyboard, create a midi in port with a 1n138 opto-coupler a diode a few resistors, and split that incoming signal using a 74xx14 TTL (or a 74xx04 for the the schmitt trigger is the official protocol.)

Midi Splitter.JPG

and send that to the individual uc32's where you can receive it on either of the 2 UART's that it has using again the full midi protocol with the opto-coupler and then diode & resistors.

Midi In.JPG

That the uc32 is a 3.3v device doesn't matter (i've just tested that on an ESP)

That way you create 1 Midi-splitter, and 4 Midi-in devices, which will be universal. You will need to power the splitter with 5v, but a small power supply will easily suffice.
Make a special not of the pinout of the 5-pin Din plug. There are quite a few examples online which have pin 4 & 5 mirrored, but i am sure that this pinout is correct. If you connect them the wrong way around, it will simply not work (you won't break anything though)

Midi In.JPG

Midi Splitter.JPG

Of course you can also just connect 1 uC32 via the computer, and then use either the UART1 RX pin to forward the midi signal (hardware midi thru) or the TX pin (software midi thru enabled by default in midi.h) and split or daisy chain from there.

Deva_Rishi:
What do you need the computer for ? does it serve a purpose other than splitting the data ? because it is actually not very good at that.
You see i would simply use the 5 pin din Midi-out from the keyboard, create a midi in port with a 1n138 opto-coupler a diode a few resistors, and split that incoming signal using a 74xx14 TTL (or a 74xx04 for the the schmitt trigger is the official protocol.)

Midi Splitter.JPG

and send that to the individual uc32's where you can receive it on either of the 2 UART's that it has using again the full midi protocol with the opto-coupler and then diode & resistors.

Midi In.JPG

That the uc32 is a 3.3v device doesn't matter (i've just tested that on an ESP)

That way you create 1 Midi-splitter, and 4 Midi-in devices, which will be universal. You will need to power the splitter with 5v, but a small power supply will easily suffice.
Make a special not of the pinout of the 5-pin Din plug. There are quite a few examples online which have pin 4 & 5 mirrored, but i am sure that this pinout is correct. If you connect them the wrong way around, it will simply not work (you won't break anything though)

The computer is going to be used for other things as well so I don't think I can take it out. Also I am using a USB MIDI keyboard, it doesn't have a 5 din

Please take the trouble to just quote the part you are responding to.

The computer is going to be used for other things as well so I don't think I can take it out. Also I am using a USB MIDI keyboard, it doesn't have a 5 din

Oh i thought it did, well anyway then i suggest you use 1 uC32 to receive form Hairless and forward from there, probably using just the simple midi-passthrough example would be best if you do want to go back to real midi, 'cause i think hairless uses a different baud-rate. I think you have to set that in serialMIDI.h It explains how to do it there at least. Then you can consider to continue forwarding with that baudrate (using just the UART1 which is connected to USB, either hardware or software) or using a passthrough to UART2, where you can chose the baudrate as you like.

i suggest you use 1 uC32 to receive form Hairless and forward from there, probably using just the simple midi-passthrough example would be best if you do want to go back to real midi

Could a USB hub be used for this? Sending the MIDI input to all the uC32s? Or would it just be recognized as multiple COM ports instead of one?

Or would it just be recognized as multiple COM ports instead of one?

It would be, that won't work for you.

Then you can consider to continue forwarding with that baudrate

I think hairless works at 115200, which actually might be a bit to fast for the opto-coupler.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.