BUG in USBHost MIDI Code found, with workaround...

lokki

Well-known member
Hi there,

I spent the last couple of weeks narrowing down an issue I had with a rather complex USBHost MIDI Setup. (Arduino 2.10 Teensy 1.58.1)

Basically I have 5 USB-Midi Devices, A DIN Midi Device and regular USB-Midi all on a Teensy 4.1

one of the usb-midi devices that is connected sends out midi, all others (including DIN and USB-MIDI client) receive midi. this was all working as expected but I got a lot of hanging notes and some very sluggish performance every now and then. I rewrote the code a couple of times and inserted Serial.println() commands in all sort of places but I could not find the problem.

Finally today I realised that the problem always appears after I sent out a Program Change. The way I have set it up, my "master midi controller" sends out a program change to all synths that are connected so I can change the whole scene on all synths simultaneously. Everytime I sent a ProgramChange to all those synths, I got hanging notes and sluggish behaviour.

My code was adopted from the 16x16 example and is quite basic. I simply copy all incoming MIDI messages from one device to all others based on channels. This gave me the hanging/sluggish behaviour as soon as I issued a ProgramChange. I have now (in the attached code) separated all ProgramChange messages from the stream and treat them separately. At first I just issued the ProgramChanges like this:

Code:
else if (type == 0xC0) {
   
   if (pulse2 >= 0) midilist[pulse2]->sendProgramChange(data1,6);
   if (axodub >= 0 ) midilist[axodub]->sendProgramChange(data1,1);
   if (minitaur >= 0)  midilist[minitaur]->sendProgramChange(data1 + 1,8);
   //send to dreadbox typhon...
  MIDI1.sendProgramChange(data1,9);
usbMIDI.sendProgramChange(data1,1);
 }

which immediately got me hanging notes and sluggish behaviour again. if I only issued one ProgramChange though, like this:

Code:
else if (type == 0xC0) {
   
   if (pulse2 >= 0) midilist[pulse2]->sendProgramChange(data1,6);
 }

everything kept running fine. so I concluded that maybe something is wrong in the USBHost implementation of ProgramChange Messages, and sending more then one on different channels immediately after each other (or at the "same" time) caused the hiccups. and indeed....

changing my code to:

Code:
else if (type == 0xC0) {
   
   if (pulse2 >= 0) midilist[pulse2]->sendProgramChange(data1,6);
   delay(1);
   if (axodub >= 0 ) midilist[axodub]->sendProgramChange(data1,1);
    delay(1);
   if (minitaur >= 0)  midilist[minitaur]->sendProgramChange(data1 + 1,8);
   //send to dreadbox typhon...
  MIDI1.sendProgramChange(data1,9);
usbMIDI.sendProgramChange(data1,1);
 }

fixed all issues. a simple delay(1); between messages is enough. so it seems the USBHost code does somehow get corrupted messages when sending multiple program changes at the same time. it would be great if this could be fixed. for now I am VERY happy I figured this out and found a workaround.

finally here is the full code for reference:

Code:
//cpu speed 600 mhz and fast instead of fastest increases stability?

#include <MIDI.h>        // access to serial (5 pin DIN) MIDI
#include <USBHost_t36.h> // access to USB MIDI devices (plugged into 2nd USB port)



//includes for OLEDs
//#include <i2c_driver_wire.h> //Library for I2C interface
#include <U8x8lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#include <Wire.h>

U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE, /* clock=*/ 19, /* data=*/ 18);
#define DEBUG
// Create the Serial MIDI ports
MIDI_CREATE_INSTANCE(HardwareSerial, Serial8, MIDI1);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial3, MIDI2);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial4, MIDI3);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial5, MIDI4);
//midi::MidiInterface &SerialMidiList[6] = {MIDI1, MIDI2, MIDI3, MIDI4, MIDI5, MIDI6};


//usb synth devices

int pulse2 = -1;
int keysaxo = -1;
int minitaur = -1;
int axodub = -1;

//usb midibass controller
int midibass = -1;

//handle on screen boot messages...
elapsedMillis boottime;
int state = 0;
// Create the ports for USB devices plugged into Teensy's 2nd USB port (via hubs)
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub3(myusb);
USBHub hub4(myusb);

MIDIDevice_BigBuffer midi01(myusb);
MIDIDevice_BigBuffer midi02(myusb);
MIDIDevice_BigBuffer midi03(myusb);
MIDIDevice_BigBuffer midi04(myusb);
MIDIDevice_BigBuffer midi05(myusb);
MIDIDevice_BigBuffer midi06(myusb);
MIDIDevice_BigBuffer midi07(myusb);





MIDIDevice_BigBuffer * midilist[7] = {
  &midi01, &midi02, &midi03, &midi04, &midi05, &midi06, &midi07
};




// A variable to know how long the LED has been turned on
//elapsedMillis ledOnMillis;



void setup() {

  Wire.setSDA(18);
  Wire.setSCL(19);
   u8x8.begin();
  u8x8.setPowerSave(0);
  u8x8.setFont(u8x8_font_5x8_f);
  while (!Serial && millis() < 1000) {
   u8x8.drawString(0,4,"Booting...");
  };
   u8x8.clear();
  for (int i=0; i<13; i++) {
  pinMode(i,INPUT_DISABLE);
  }
  for (int i=24; i<34; i++) {
  pinMode(i,INPUT_DISABLE);
  }
   for (int i=36; i<55; i++) {
  pinMode(i,INPUT_DISABLE);
  }
  pinMode(22,INPUT_DISABLE);   
  pinMode(23,INPUT_DISABLE);
  #ifdef DEBUG
  Serial.begin(115200);
  #endif
  pinMode(13, OUTPUT); // LED pin
  digitalWrite(13, LOW);
  MIDI1.begin(MIDI_CHANNEL_OMNI);
  MIDI2.begin(MIDI_CHANNEL_OMNI);
  MIDI3.begin(MIDI_CHANNEL_OMNI);
  MIDI4.begin(MIDI_CHANNEL_OMNI);
  // Wait 3.5 seconds before turning on USB Host.  If connected USB devices
  // use too much power, Teensy at least completes USB enumeration, which
  // makes isolating the power issue easier.
  
  #ifdef DEBUG
  Serial.println("Booting...");
   #endif
   boottime = 0;
   while (boottime < 1000) {
    if (boottime < 300)  {
      if (!state) u8x8.drawString(0,4,"W");
      state = 1;
   } else if (boottime < 600)  {
      if (state == 1)  u8x8.drawString(0,4,"WA");
      state = 2;
   } else if (boottime < 900) {
      if (state == 2)  u8x8.drawString(0,4,"WAI");
      state = 3;
   }
   }

   
  // u8x8.drawString(0,0,"Booting");
 // delay(3500);
 // 
 //usbMIDI.begin();
 myusb.begin();
 delay(100);
 boottime = 0; 
  //wait another 10 seconds before enumerating the devices, hopefully by now they have settled.
  while (boottime < 3000) {
    if (boottime < 300) {
     if (state == 3)  u8x8.drawString(0,4,"WAIT");
      state = 4;
    } else if (boottime < 600) {
      if (state == 4) u8x8.drawString(0,4,"WAITI");
      state = 5;
    } else if (boottime < 900) {
      if (state == 5) u8x8.drawString(0,4,"WAITIN");
      state = 6;
    } else if (boottime < 1200) {
      if (state == 6) u8x8.drawString(0,4,"WAITING");
      state = 7;
    } else if (boottime < 1500)  {
      if (state == 7) u8x8.drawString(0,4,"WAITING.");
      state = 8;
    } else if (boottime < 1800)  {
       if (state == 8)u8x8.drawString(0,4,"WAITING..");
      state = 9;
    } else if (boottime < 2100)  {
       if (state == 9)u8x8.drawString(0,4,"WAITING...");
      state = 10;
    } else if (boottime < 2400) {
      if (state == 10) u8x8.drawString(0,4,"WAITING....");
      state = 11;
    } else if (boottime < 2700)  {
      if (state == 11) u8x8.drawString(0,4,"WAITING.....");
      state = 12;
    } else if (boottime < 3000){
      if (state == 12) u8x8.drawString(0,4,"WAITING......");
      state = 13;
    }
  }
  u8x8.clear();
  u8x8.drawString(0,0,"  USB DEVICES  ");
  u8x8.drawString(0,1,"---------------");
  u8x8.drawString(0,7,"---------------");
  delay(500);
//delay(10000);
Serial.println("");
Serial.println("------------NEW START--------------");
for (int i=0; i<7; i++) {


  if (midilist[i]->manufacturer() != NULL && midilist[i]->serialNumber() != NULL) {
    #ifdef DEBUG
     Serial.println("-----------------------------------"); 
     Serial.print("Serial:"); 
     Serial.println((char*)midilist[i]->serialNumber());
     Serial.print("ProductID:"); 
     Serial.println(midilist[i]->idProduct());
     Serial.println("-----------------------------------"); 
     #endif
     
    
     if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"003600433435511733353932")) {//Axoloti for qunexus/vocoder serial
     #ifdef DEBUG
      Serial.println("here is axovocoder");
      
       #endif
       
       u8x8.drawString(0,i+2,"AxoVox");
       u8x8.drawString(10,i+2,String(i).c_str());
      keysaxo = i;
     
     }

     if (midilist[i]->idProduct() == 22) {
      #ifdef DEBUG
      Serial.println("here is Pulse2");
      
       #endif
       u8x8.drawString(0,i+2,"Pulse2");
       u8x8.drawString(10,i+2,String(i).c_str());
      pulse2 = i;
   
     }

    /*   if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"325B346C3030")) {//typhon dreadbox
     #ifdef DEBUG
      Serial.println("here is typhon dreadbox");
       #endif
      dreadbox = i;
     
     } */

    /*   if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"6633190")) {//midibass
       #ifdef DEBUG
      Serial.println("here is MIDIBASS!!");
       #endif
      midibass = i;
     
     } */

        if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"12209010")) {//midibass
       #ifdef DEBUG
      Serial.println("here is MIDIBASS!!");
       #endif
       u8x8.drawString(0,i+2,"MIDIBASS");
       u8x8.drawString(10,i+2,String(i).c_str());
      midibass = i;
     
     }

  if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"003500323532470532323631")) {//Axoloti for qunexus/vocoder serial
  #ifdef DEBUG
      Serial.println("here is axodub");
       #endif
       u8x8.drawString(0,i+2,"AxoDub");
       u8x8.drawString(10,i+2,String(i).c_str());
      axodub = i;
    
     }
 
if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"MTc537ef")) {//moog minitaur
#ifdef DEBUG
      Serial.println("here is the minitaur");
      #endif
      u8x8.drawString(0,i+2,"Minitaur");
      u8x8.drawString(10,i+2,String(i).c_str());
      minitaur = i;
      
     }
  }
  
  delay(300);
  }
delay(100);
  
Serial.println("------------Finished------------");
if (pulse2 >= 0) midilist[pulse2]->sendProgramChange(0,6);
   delay(1);
   if (axodub >= 0 ) midilist[axodub]->sendProgramChange(0,1);
    delay(1);
   if (minitaur >= 0)  midilist[minitaur]->sendProgramChange(1,8);
   //send to dreadbox typhon...
  MIDI1.sendProgramChange(0,9);
usbMIDI.sendProgramChange(0,1);
}


void loop() {
  if(usbMIDI.read()) {
      uint8_t type =       usbMIDI.getType();
      uint8_t data1 =       usbMIDI.getData1();
      uint8_t data2 =       usbMIDI.getData2();
      uint8_t channel =     usbMIDI.getChannel();
      uint8_t cable =       usbMIDI.getCable();
     
    midilist[midibass]->send(type, data1, data2, channel, cable);  
  }
 myusb.Task();

  if (midibass >= 0){
 if (midilist[midibass]->read()) {
      uint8_t type =       midilist[midibass]->getType();
      uint8_t data1 =      midilist[midibass]->getData1();
      uint8_t data2 =      midilist[midibass]->getData2();
      uint8_t channel =    midilist[midibass]->getChannel();
      uint8_t cable =      midilist[midibass]->getCable();
     // const uint8_t *sys = midilist[midibass]->getSysExArray();
      midi::MidiType mtype = (midi::MidiType)type;
      
      if (type != 0xC0) {
      if (!cable) {
        
          
          if (channel == 1) {
            sendToMacMini(type, data1, data2, channel, 0); 
            if (axodub >= 0) midilist[axodub]->send(type, data1, data2, channel);
          }
          if (channel == 6) {
            if (pulse2 >= 0)  midilist[pulse2]->send(type, data1, data2, channel);
          }
          if (channel == 7) {
            if (axodub >= 0)  midilist[axodub]->send(type, data1, data2, channel);
          }
          if (channel == 8) {
            if (minitaur >= 0)  midilist[minitaur]->send(type, data1, data2, channel);
          }
          if (channel == 9) { 
            //if (dreadbox < 11) midilist[dreadbox]->send(type, data1, data2, channel);
            MIDI1.send(mtype, data1, data2, channel);
          }
          if (((channel > 1) && (channel < 6)) || (channel > 9)) sendToMacMini(type, data1, data2, channel, 0); // channel 2-5 and 10-16
          
         // case 9: if (keysaxo >= 0)  midilist[keysaxo]->send(type, data1, data2, channel); break;
        // case 9: MIDI1.send(mtype, data1, data2, channel); break;
        
        
      }
      else if (cable == 1) {
      sendToMacMini(type, data1, data2, channel - 5, 1); //send all accordion data to the macmini on port 1
       if ((channel > 12) && (keysaxo >= 0))  midilist[keysaxo]->send(type, data1, data2, channel);
      }
 } else if (type == 0xC0) {
   
   if (pulse2 >= 0) midilist[pulse2]->sendProgramChange(data1,6);
   delay(1);
   if (axodub >= 0 ) midilist[axodub]->sendProgramChange(data1,1);
    delay(1);
   if (minitaur >= 0)  midilist[minitaur]->sendProgramChange(data1 + 1,8);
   //send to dreadbox typhon...
  MIDI1.sendProgramChange(data1,9);
usbMIDI.sendProgramChange(data1,1);
 }
     // activity = true;
    }
  }
}


void sendToMacMini(byte type, byte data1, byte data2, byte channel, byte cable)
{
  if (type != midi::SystemExclusive) {
    usbMIDI.send(type, data1, data2, channel, cable);
  } else {
   // unsigned int SysExLength = data1 + data2 * 256;
   // usbMIDI.sendSysEx(SysExLength, sysexarray, true, cable);
  }
}
 
Something similar popped up on a Roland JV-XP related forum recently and the solution boiled down to allowing some 80ms for the ProgramChange to fully instantiate before sending a note message.

Some other synth may handle this situation differently and who knows if it's gonna leave a hanging note (or not) if the next note comes in before a Program Change has fully instantiated.

I'd be building a test regime to closely examine the actual behavior of the synth.
 
Thanks for your answer.
Obviously I did not formulate my original post clearly enough. This is not an issue with the synths, and I can wait as long as I want after a ProgramChange, MIDI is still garbled after I issue multiple PC messages to different synths without delay() in between.
It is an issue with the MIDI USB-Host implementation on teensy!
And only the USB-Host side is affected. I get "normal" MIDI output on Serial and usbMIDI lines even with my older code that had no delay(); between the PC messages.


Also incoming MIDI from a connected Mac that I send back to the MIDI-Controller gets garbled after I issued the "multiple PC" messages. So again, it is outgoing traffic from USBHost MIDI that is affected. It feels like a buffer or something is off after the messages have been sent, or data1 and data2 of a midi messages get mixed up. In some cases I could make it work again after playing with it for a while as if a certain MIDI message reset the behaviour. But every time I sent a PC message again, boom hanging notes, and garbled MIDI input again.
 
Any suggestions how I should try to reproduce this issue without a Roland JV-XP or U8X8 hardware?

EDIT: oh, now I see this is sending to at least 3 connected USB MIDI devices. I'm going to try plugging 3 Teensy 4.0s into a USB hub. Maybe that will be enough to reproduce?
 
Last edited:
Ok, I have 3 Teensy 4.0s plugged into a hub connected to a Teensy 4.1. I think I've managed to reproduce the problem. Maybe?

usb.jpg

Running this on each Teensy 4.0, blink the LED when a Program Change message arrives.

Code:
elapsedMillis LED_on_time;

void myProgramChange(byte channel, byte program) {
  digitalWrite(13, OUTPUT);
  LED_on_time = 0;
}

void setup() {
  pinMode(13, OUTPUT);
  usbMIDI.setHandleProgramChange(myProgramChange);
  LED_on_time = 10000;
}

void loop() {
  usbMIDI.read();
  if (LED_on_time > 200) {
    digitalWrite(13, LOW);
  }
}

Running this on the Teensy 4.1 with USB host, rapidly transmit Program Change to all devices.

Code:
#include <USBHost_t36.h>

USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub3(myusb);
USBHub hub4(myusb);

MIDIDevice_BigBuffer midi01(myusb);
MIDIDevice_BigBuffer midi02(myusb);
MIDIDevice_BigBuffer midi03(myusb);
MIDIDevice_BigBuffer midi04(myusb);
MIDIDevice_BigBuffer midi05(myusb);
MIDIDevice_BigBuffer midi06(myusb);
MIDIDevice_BigBuffer midi07(myusb);

MIDIDevice_BigBuffer * midilist[7] = {
  &midi01, &midi02, &midi03, &midi04, &midi05, &midi06, &midi07
};

int count = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial) ;
  Serial.println("USB Host MIDI transmit test");
  delay(500);
  myusb.begin();
  Serial.print("USB host on");
  for (int i = 0; i < 4; i++) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println();
  for (int i = 0; i < 7; i++) {
    if (*midilist[i]) {
      Serial.print("USB MIDI Device ");
      Serial.print("Serial=");
      Serial.print((char*)midilist[i]->serialNumber());
      Serial.print(", ProductID=");
      Serial.print(midilist[i]->idProduct(), HEX);
      Serial.println();
      count = count + 1;
    }
  }
  if (count == 0) {
    Serial.println("No USB MIDI devices found :-(");
  }
}

void loop() {
  if (count > 0) {
    Serial.println("transmit program change to all USB MIDI devices");
    for (int i = 0; i < 7; i++) {
      if (midilist[i]->manufacturer() != NULL) {
        Serial.println(i);
        midilist[i]->sendProgramChange(20, i);
      }
    }
  }
  delay(5000);
}

Indeed I see usually only 1 of them blink, sometimes 2, but never all 3. Hopefully this is the same problem...

This is what I'm seeing with the USB protocol analyzer. Looks like it is indeed failing to transmit some messages.

screenshot.png

Why... don't know yet. Just wanted to first confirm I set up this test so I can start investigating.
 
great! thanks for confirming and checking out.

this looks indeed like the same bug. if you can further write a function that receives midi note-on and off messages on the clients *after* the program changes you should see that those messages are garbled (hanging notes, etc.)
 
Here's some Roland Sysex at the press of a button or receipt of Midi CC#32 Value 127 extracted from my T4.0 project.
Has a couple of tabs.
 

Attachments

  • RolandDump.zip
    7.1 KB · Views: 281
Is this perhaps also related to the issue in this thread?

Unlikely to be related, as that thread involves receiving MIDI messages. This issue is about transmitting. Of course I can't rule anything out until both problems are fully understood (and likely solved) but I can tell you the receive stuff is fairly independent of the transmit stuff, so these aren't likely to be the same issue.

EDIT: I posted a message on that thread requesting a usbMIDI transmit test program to reproduce the USB Host receive problem.
 
Last edited:

Attachments

  • ehci.cpp
    47.9 KB · Views: 73
thanks for this fix, I am abroad and will only be able to check this out the next week. I will post here with my findings...
 
1.59-beta3 has been released with this bug fix.

If using Arduino IDE 2.1.1, you can get this update from Boards Manager by switching to 0.59.3 in the drop-down list.

If using Arduino IDE 1.8.19, just download and run the installer to update.
 
Hi Paul, I had some time to test your fix (both with just ehci.cpp replaced and with beta3) and I can confirm that I get no more hanging notes after switching programs! So your fix indeed seems to work. I have not jet been able to do a long test to see if there are some downsides to this fix, but I don't think there are any.

Just out of curiosity, does the fix treat all midi data in a new way? I briefly looked at the changed lines and it seems you are now checking before a message is processed to make sure there is no other message still processed?

With this fix there is only one remaining "BUG" in my midi-usb-host-teensy-thingy. The startup process (with 5 USB-Midi devices a.t.m.) is not consistent. Sometimes the teensy hangs on initialisation of the usb devices.

I have tried several HUBs, different powering methods, capacitors at the 5v line of teensy etc. I measured the 5v line with all devices connected and I don't think it is a hardware issue.

I can post some debug serial lines, but the new IDE has a hard time with this many messages and usually freezes... also copying a whole lot of serial is still a mess on the new IDE...

Could you maybe try in your setup with more than 3 Teensy-Clients and see if you can initialise them all consistently. By that I mean checking for serial number at startup and the ability to later send specific messages to specific devices.

I do it like this in my program:

Code:
for (int i=0; i<7; i++) {


  if (midilist[i]->manufacturer() != NULL && midilist[i]->serialNumber() != NULL) {
    #ifdef DEBUG
     Serial.println("-----------------------------------"); 
     Serial.print("Serial:"); 
     Serial.println((char*)midilist[i]->serialNumber());
     Serial.print("ProductID:"); 
     Serial.println(midilist[i]->idProduct());
     Serial.println("-----------------------------------"); 
     #endif
     
    
     if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"003600433435511733353932")) {//Axoloti for qunexus/vocoder serial
     #ifdef DEBUG
      Serial.println("here is axovocoder");
      
       #endif
       
       u8x8.drawString(0,i+2,"AxoVox");
       u8x8.drawString(10,i+2,String(i).c_str());
      keysaxo = i;
     
     }

     if (midilist[i]->idProduct() == 22) {
      #ifdef DEBUG
      Serial.println("here is Pulse2");
      
       #endif
       u8x8.drawString(0,i+2,"Pulse2");
       u8x8.drawString(10,i+2,String(i).c_str());
      pulse2 = i;
   
     }

    /*   if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"325B346C3030")) {//typhon dreadbox
     #ifdef DEBUG
      Serial.println("here is typhon dreadbox");
       #endif
      dreadbox = i;
     
     } */

    /*   if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"6633190")) {//midibass
       #ifdef DEBUG
      Serial.println("here is MIDIBASS!!");
       #endif
      midibass = i;
     
     } */

        if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"12209010")) {//midibass
       #ifdef DEBUG
      Serial.println("here is MIDIBASS!!");
       #endif
       u8x8.drawString(0,i+2,"MIDIBASS");
       u8x8.drawString(10,i+2,String(i).c_str());
      midibass = i;
     
     }

  if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"003500323532470532323631")) {//Axoloti for qunexus/vocoder serial
  #ifdef DEBUG
      Serial.println("here is axodub");
       #endif
       u8x8.drawString(0,i+2,"AxoDub");
       u8x8.drawString(10,i+2,String(i).c_str());
      axodub = i;
    
     }
 
if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"MTc537ef")) {//moog minitaur
#ifdef DEBUG
      Serial.println("here is the minitaur");
      #endif
      u8x8.drawString(0,i+2,"Minitaur");
      u8x8.drawString(10,i+2,String(i).c_str());
      minitaur = i;
      
     }
  }
  
  delay(300);
  }
 
With this fix there is only one remaining "BUG" in my midi-usb-host-teensy-thingy. The startup process (with 5 USB-Midi devices a.t.m.) is not consistent. Sometimes the teensy hangs on initialisation of the usb devices.
...
I do it like this in my program:

Let's call this startup issue a different problem. Please start a new thread. Please try to describe it as fully as possible. I see you gave code, but not a complete program which can be copied into Arduino IDE and used without guesswork about whatever other parts are needed. When you start a new thread, please start the first post with a complete program. Even if the other stuff is "trivial", it's important to give a complete program so there's no guessing needed.


Could you maybe try in your setup with more than 3 Teensy-Clients and see if you can initialise them all consistently. By that I mean checking for serial number at startup and the ability to later send specific messages to specific devices.

If you want me set that test up again (the hardware is all put away, but easy to get out again) please also give the program(s) I should run on those 3 Teensy 4.0 boards plugged into the hub. Again, give the complete program so I don't have to guess any missing parts, even if they're considered trivial.
 
yes sorry, you are of course right. I got a bit over excited by the fact that the other bug was resolved. I will have to check but I don't think I have 4 or 5 teensies ready to set this up, but I will check. Otherwise I can write the code, but I won't know if it fails :)
 
Back
Top