USB-host 3.6 on recent Teensduino 16x16 midi example

lokki

Well-known member
hi there,

i have used the usb-host feature of teensy 3.6 extensively over the last year for a midi controller project. i had all my synths connected to a usb hub and the teensy midi controller would send midi to them. in recent versions of the library i have encountered a lot of hanging notes and my whole program would crash. i rewrote my midi project now to use the standard midi usb output and will connect my (usb) synths and the controller i built to a HUB and control that via a separate teensy 4.1. one of the problems that arose with newer versions of the usbhost library seems to be that writing to unused ports causes hiccups. this was certainly no problem with the 0.1. version of the usbhost library. should this work? or is writing to non connected HUB ports a nogo? from looking at the 16x16 host midi example at least reading from (potentially) unused ports is ok.

i had a look at the new usbhost midi code and there are quite some substantial changes with regards to sending messages (timers to try and fill midi USB messages, while retaining low latency etc.) maybe there is some regression there? there are also quite a few recent forum comments about usbhost MIDI code not running smoothly (jittery midi clock for example). how were the new sending "features" tested?

additionally the 16x16 host example does not compile on Arduino 2.0.3 for teensy if i use the BigBuffer MIDIDevice, which i need to read/write from/to newer usb2 teensies. here is the error:

Code:
/private/var/folders/l7/m07k7_t14kbgsj8y_sychc0c0000gn/T/arduino-sketch-B91CD7AB12FDC96842B9810B4B3F3A87/sketch/Interface_16x16.ino.cpp.o:(.rodata._ZTV20MIDIDevice_BigBuffer[_ZTV20MIDIDevice_BigBuffer]+0x10): undefined reference to `MIDIDeviceBase::timer_event(USBDriverTimer*)'
collect2: error: ld returned 1 exit status
Multiple libraries were found for "MIDI.h"
  Used: /Users/lokki/Library/Arduino15/packages/teensy/hardware/avr/1.57.2/libraries/MIDI
  Not used: /Users/lokki/Documents/Arduino/libraries/MIDIarduino
Multiple libraries were found for "USBHost_t36.h"
  Used: /Users/lokki/Library/Arduino15/packages/teensy/hardware/avr/1.57.2/libraries/USBHost_t36
  Not used: /Users/lokki/Library/Arduino15/packages/teensy/hardware/avr/1.57.2/libraries/USBHost_t36_old
Using library MIDI Library at version 5.0.2 in folder: /Users/lokki/Library/Arduino15/packages/teensy/hardware/avr/1.57.2/libraries/MIDI 
Using library USBHost_t36 at version 0.2 in folder: /Users/lokki/Library/Arduino15/packages/teensy/hardware/avr/1.57.2/libraries/USBHost_t36 
Using library SdFat at version 2.1.2 in folder: /Users/lokki/Library/Arduino15/packages/teensy/hardware/avr/1.57.2/libraries/SdFat 
Using library SPI at version 1.0 in folder: /Users/lokki/Library/Arduino15/packages/teensy/hardware/avr/1.57.2/libraries/SPI 
exit status 1

Compilation error: exit status 1

thanks
 
Last edited:
aha, compiling on 1.8.19 and Teensyduino 1.57 works with _BigBuffer ... so i will use that for the time being.
 
does the usbhost midi part somehow support the "cable" variable as well? as in the usbMIDI part? i would like to read some usb data that comes from a teensy that sends on multiple "cables" but i see there is no method (at least not in the examples) that can discern between multiple cables. here is the relevant part of the example code:

Code:
for (int port=0; port < 10; port++) {
    if (midilist[port]->read()) {
      uint8_t type =       midilist[port]->getType();
      uint8_t data1 =      midilist[port]->getData1();
      uint8_t data2 =      midilist[port]->getData2();
      uint8_t channel =    midilist[port]->getChannel();
      const uint8_t *sys = midilist[port]->getSysExArray();
      sendToComputer(type, data1, data2, channel, sys, 6 + port);
      activity = true;
    }
  }

EDIT: just try it and it will work :) there is indeed a getCable() function in the host part as well, it is just not in the example....
 
coming back to this again:

with USBHost_t36 0.2 and Arduino 1.8.19 whenever i try to access the manufacturer or serial number of a connected mididebvice, the teensy simply reboots

so for example this line:

Code:
Serial.println((char*)midilist[i]->serialNumber());
reboots the teensy (the statement is in the setup part).

here is the whole code which is a simple adaption of the InputFunctions example in the host examples.

Code:
/* Receive Incoming USB Host MIDI using functions.  As usbMIDI
   reads incoming messages, handler functions are run.
   See the InputRead example for the non-function alterative.

   This very long example demonstrates all possible handler
   functions.  Most applications need only some of these.
   This example is meant to allow easy copy-and-paste of the
   desired functions.

   Use the Arduino Serial Monitor to view the messages
   as Teensy receives them by USB MIDI

   You must select MIDI from the "Tools > USB Type" menu

   This example code is in the public domain.
*/

#include <USBHost_t36.h>

USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub3(myusb);
USBHub hub4(myusb);
MIDIDevice midi01(myusb);
MIDIDevice midi02(myusb);
MIDIDevice midi03(myusb);
MIDIDevice midi04(myusb);
MIDIDevice midi05(myusb);
MIDIDevice midi06(myusb);
MIDIDevice midi07(myusb);

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

//devices

int pulse2 = 7;
int keysaxo = 7;
//int footpedal = 7;
int minitaur = 7;
//int macmini = 7;
//int preenfm = 7;
int axodub = 7;

//midibass
int midibass = 7;

void setup() {
  Serial.begin(115200);

  // Wait 1.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.
  delay(1500);
  Serial.println("USB Host InputFunctions example");
  delay(10);
  myusb.begin();
  for (int i=0; i<7; i++) {
  Serial.print("trying");
  Serial.println(i);
Serial.println((char*)midilist[i]->serialNumber());
  if (midilist[i]->manufacturer() != NULL && midilist[i]->serialNumber() != NULL) {
     Serial.println("-----------------------------------"); 
     Serial.print("Serial:"); 
     Serial.println((char*)midilist[i]->serialNumber());
     Serial.print("ProductID:"); 
     Serial.println(midilist[i]->idProduct());
     Serial.println("-----------------------------------"); 
     
    // if (!strcmp(midilist[i]->serialNumber(), 9)) { //Waldorf Pulse2
    if (midilist[i]->idProduct() == 22) {
      Serial.println("here is Pulse2");
      pulse2 = i;
   
     }

   /*  if (midilist[i]->idProduct() == 82) {
      Serial.println("here is blofeld at edirol");
      blofeld = i;
     } */

     if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"003600433435511733353932")) {//Axoloti for qunexus/vocoder serial
      Serial.println("here is axovocoder");
      keysaxo = i;
     
     }

  if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"003500323532470532323631")) {//Axoloti for qunexus/vocoder serial
      Serial.println("here is axodub");
      axodub = i;
    
     }
 
/*if (midilist[i]->idProduct() == 22336) {//preenfm3 
      Serial.println("here is preenfm3");
      preenfm = i;
     } */
   /*  if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"EncoderFanel")) {//teensy LC footcontroller
      Serial.println("here is the footcontroller");
      footpedal = i;
     } */
if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"MTc537ef")) {//moog minitaur
      Serial.println("here is the minitaur");
      minitaur = i;
      
     }

/*if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"7795010")) {//mac mini via teensy lc
      Serial.println("here is the vital mac mini");
      macmini = i;
     
     }     */

     /*if (!strcmp(midilist[i]->serialNumber(), "11390072173-1304284600")) { //Waldorf Blofeld Serial
      Serial.println("here is blofeld");
      blofeld = i;
     } */
     
  }
  delay(10);
  }
  midi01.setHandleNoteOn(myNoteOn);
  midi01.setHandleNoteOff(myNoteOff);
  midi01.setHandleAfterTouchPoly(myAfterTouchPoly);
  midi01.setHandleControlChange(myControlChange);
  midi01.setHandleProgramChange(myProgramChange);
  midi01.setHandleAfterTouchChannel(myAfterTouchChannel);
  midi01.setHandlePitchChange(myPitchChange);
  // Only one of these System Exclusive handlers will actually be
  // used.  See the comments below for the difference between them.
  midi01.setHandleSystemExclusive(mySystemExclusiveChunk);
  midi01.setHandleSystemExclusive(mySystemExclusive); 
  midi01.setHandleTimeCodeQuarterFrame(myTimeCodeQuarterFrame);
  midi01.setHandleSongPosition(mySongPosition);
  midi01.setHandleSongSelect(mySongSelect);
  midi01.setHandleTuneRequest(myTuneRequest);
  midi01.setHandleClock(myClock);
  midi01.setHandleStart(myStart);
  midi01.setHandleContinue(myContinue);
  midi01.setHandleStop(myStop);
  midi01.setHandleActiveSensing(myActiveSensing);
  midi01.setHandleSystemReset(mySystemReset);
  // This generic System Real Time handler is only used if the
  // more specific ones are not set.
  midi01.setHandleRealTimeSystem(myRealTimeSystem);
}

void loop() {
  // The handler functions are called when midi01 reads data.  They
  // will not be called automatically.  You must call midi01.read()
  // regularly from loop() for midi01 to actually read incoming
  // data and run the handler functions as messages arrive.
  myusb.Task();
  midi01.read();
}


void myNoteOn(byte channel, byte note, byte velocity) {
  // When a USB device with multiple virtual cables is used,
  // midi01.getCable() can be used to read which of the virtual
  // MIDI cables received this message.
  Serial.print("Note On, ch=");
  Serial.print(channel, DEC);
  Serial.print(", note=");
  Serial.print(note, DEC);
  Serial.print(", velocity=");
  Serial.println(velocity, DEC);
}

void myNoteOff(byte channel, byte note, byte velocity) {
  Serial.print("Note Off, ch=");
  Serial.print(channel, DEC);
  Serial.print(", note=");
  Serial.print(note, DEC);
  Serial.print(", velocity=");
  Serial.println(velocity, DEC);
}

void myAfterTouchPoly(byte channel, byte note, byte velocity) {
  Serial.print("AfterTouch Change, ch=");
  Serial.print(channel, DEC);
  Serial.print(", note=");
  Serial.print(note, DEC);
  Serial.print(", velocity=");
  Serial.println(velocity, DEC);
}

void myControlChange(byte channel, byte control, byte value) {
  Serial.print("Control Change, ch=");
  Serial.print(channel, DEC);
  Serial.print(", control=");
  Serial.print(control, DEC);
  Serial.print(", value=");
  Serial.println(value, DEC);
}

void myProgramChange(byte channel, byte program) {
  Serial.print("Program Change, ch=");
  Serial.print(channel, DEC);
  Serial.print(", program=");
  Serial.println(program, DEC);
}

void myAfterTouchChannel(byte channel, byte pressure) {
  Serial.print("After Touch, ch=");
  Serial.print(channel, DEC);
  Serial.print(", pressure=");
  Serial.println(pressure, DEC);
}

void myPitchChange(byte channel, int pitch) {
  Serial.print("Pitch Change, ch=");
  Serial.print(channel, DEC);
  Serial.print(", pitch=");
  Serial.println(pitch, DEC);
}


// This 3-input System Exclusive function is more complex, but allows you to
// process very large messages which do not fully fit within the midi01's
// internal buffer.  Large messages are given to you in chunks, with the
// 3rd parameter to tell you which is the last chunk.  This function is
// a Teensy extension, not available in the Arduino MIDI library.
//
void mySystemExclusiveChunk(const byte *data, uint16_t length, bool last) {
  Serial.print("SysEx Message: ");
  printBytes(data, length);
  if (last) {
    Serial.println(" (end)");
  } else {
    Serial.println(" (to be continued)");
  }
}

// This simpler 2-input System Exclusive function can only receive messages
// up to the size of the internal buffer.  Larger messages are truncated, with
// no way to receive the data which did not fit in the buffer.  If both types
// of SysEx functions are set, the 3-input version will be called by midi01.
//
void mySystemExclusive(byte *data, unsigned int length) {
  Serial.print("SysEx Message: ");
  printBytes(data, length);
  Serial.println();
}

void myTimeCodeQuarterFrame(byte data) {
  static char SMPTE[8]={'0','0','0','0','0','0','0','0'};
  static byte fps=0;
  byte index = data >> 4;
  byte number = data & 15;
  if (index == 7) {
    fps = (number >> 1) & 3;
    number = number & 1;
  }
  if (index < 8 || number < 10) {
    SMPTE[index] = number + '0';
    Serial.print("TimeCode: ");  // perhaps only print when index == 7
    Serial.print(SMPTE[7]);
    Serial.print(SMPTE[6]);
    Serial.print(':');
    Serial.print(SMPTE[5]);
    Serial.print(SMPTE[4]);
    Serial.print(':');
    Serial.print(SMPTE[3]);
    Serial.print(SMPTE[2]);
    Serial.print('.');
    Serial.print(SMPTE[1]);  // perhaps add 2 to compensate for MIDI latency?
    Serial.print(SMPTE[0]);
    switch (fps) {
      case 0: Serial.println(" 24 fps"); break;
      case 1: Serial.println(" 25 fps"); break;
      case 2: Serial.println(" 29.97 fps"); break;
      case 3: Serial.println(" 30 fps"); break;
    }
  } else {
    Serial.print("TimeCode: invalid data = ");
    Serial.println(data, HEX);
  }
}

void mySongPosition(uint16_t beats) {
  Serial.print("Song Position, beat=");
  Serial.println(beats);
}

void mySongSelect(byte songNumber) {
  Serial.print("Song Select, song=");
  Serial.println(songNumber, DEC);
}

void myTuneRequest() {
  Serial.println("Tune Request");
}

void myClock() {
  Serial.println("Clock");
}

void myStart() {
  Serial.println("Start");
}

void myContinue() {
  Serial.println("Continue");
}

void myStop() {
  Serial.println("Stop");
}

void myActiveSensing() {
  Serial.println("Actvice Sensing");
}

void mySystemReset() {
  Serial.println("System Reset");
}

void myRealTimeSystem(uint8_t realtimebyte) {
  Serial.print("Real Time Message, code=");
  Serial.println(realtimebyte, HEX);
}



void printBytes(const byte *data, unsigned int size) {
  while (size > 0) {
    byte b = *data++;
    if (b < 16) Serial.print('0');
    Serial.print(b, HEX);
    if (size > 1) Serial.print(' ');
    size = size - 1;
  }
}

can somebody check? if i remove the calls to manufacturer and serial number, the sketch runs without a problem
 
ok i narrowed it down to this:

in the default Interface_16x16 example, when i try to loop over the connected devices by adding

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

Serial.println((char*)midilist[1]->serialNumber());
delay(200);
  }

to the setup part after myusb.begin(); the teensy reboots if there is no device connected on one of the checked ports. this used to work just fine. what is the current procedure to check for devices and where they are? i used this in the past and it worked great:

Code:
  for (int i=0; i<7; i++) {
  Serial.print("trying");
  Serial.println(i);
Serial.println((char*)midilist[i]->serialNumber());
  if (midilist[i]->manufacturer() != NULL && midilist[i]->serialNumber() != NULL) {
     Serial.println("-----------------------------------"); 
     Serial.print("Serial:"); 
     Serial.println((char*)midilist[i]->serialNumber());
     Serial.print("ProductID:"); 
     Serial.println(midilist[i]->idProduct());
     Serial.println("-----------------------------------"); 
     
    // if (!strcmp(midilist[i]->serialNumber(), 9)) { //Waldorf Pulse2
    if (midilist[i]->idProduct() == 22) {
      Serial.println("here is Pulse2");
      pulse2 = i;
   
     }

   /*  if (midilist[i]->idProduct() == 82) {
      Serial.println("here is blofeld at edirol");
      blofeld = i;
     } */

     if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"003600433435511733353932")) {//Axoloti for qunexus/vocoder serial
      Serial.println("here is axovocoder");
      keysaxo = i;
     
     }

  if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"003500323532470532323631")) {//Axoloti for qunexus/vocoder serial
      Serial.println("here is axodub");
      axodub = i;
    
     }
 
/*if (midilist[i]->idProduct() == 22336) {//preenfm3 
      Serial.println("here is preenfm3");
      preenfm = i;
     } */
   /*  if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"EncoderFanel")) {//teensy LC footcontroller
      Serial.println("here is the footcontroller");
      footpedal = i;
     } */
if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"MTc537ef")) {//moog minitaur
      Serial.println("here is the minitaur");
      minitaur = i;
      
     }

/*if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"7795010")) {//mac mini via teensy lc
      Serial.println("here is the vital mac mini");
      macmini = i;
     
     }     */

     /*if (!strcmp(midilist[i]->serialNumber(), "11390072173-1304284600")) { //Waldorf Blofeld Serial
      Serial.println("here is blofeld");
      blofeld = i;
     } */
     
  }
  delay(10);
  }

however this reboots the teensy since not all of these devices are always present...
 
can somebody check? if i remove the calls to manufacturer and serial number, the sketch runs without a problem

@lokki:

I have only Teensy 4.0 & 4.1 processors in my Teensy hardware collection, so I can't check your program in exactly the same configuration that you have. However, in loading & running your posted code on a T4.1, I activated the crash report as follows (in setup):

Code:
void setup() {
   Serial.begin(115200);

   // Wait 1.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.
   delay(1500);

   if (CrashReport) {
      Serial.print(CrashReport);
   }

   Serial.println("USB Host InputFunctions example");
   delay(10);
   myusb.begin();
   for (int i = 0; i < 7; i++) {
      Serial.print("trying");
      Serial.println(i);
      Serial.println((char*)midilist[i]->serialNumber());
      if (midilist[i]->manufacturer() != NULL && midilist[i]->serialNumber() != NULL) {
         Serial.println("-----------------------------------");
         Serial.print("Serial:");
         Serial.println((char*)midilist[i]->serialNumber());
         Serial.print("ProductID:");
         Serial.println(midilist[i]->idProduct());
         Serial.println("-----------------------------------");

         // if (!strcmp(midilist[i]->serialNumber(), 9)) { //Waldorf Pulse2
         if (midilist[i]->idProduct() == 22) {
            Serial.println("here is Pulse2");
            pulse2 = i;

         }

         /*  if (midilist[i]->idProduct() == 82) {
            Serial.println("here is blofeld at edirol");
            blofeld = i;
            } */

         if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()), "003600433435511733353932")) { //Axoloti for qunexus/vocoder serial
            Serial.println("here is axovocoder");
            keysaxo = i;

         }

         if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()), "003500323532470532323631")) { //Axoloti for qunexus/vocoder serial
            Serial.println("here is axodub");
            axodub = i;

         }

         /* if (midilist[i]->idProduct() == 22336) {//preenfm3
               Serial.println("here is preenfm3");
               preenfm = i;
              } */
         /*  if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"EncoderFanel")) {//teensy LC footcontroller
            Serial.println("here is the footcontroller");
            footpedal = i;
            } */
         if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()), "MTc537ef")) { //moog minitaur
            Serial.println("here is the minitaur");
            minitaur = i;

         }

         /* if (!strcmp(reinterpret_cast<const char *>(midilist[i]->serialNumber()),"7795010")) {//mac mini via teensy lc
               Serial.println("here is the vital mac mini");
               macmini = i;

              }     */

         /* if (!strcmp(midilist[i]->serialNumber(), "11390072173-1304284600")) { //Waldorf Blofeld Serial
            Serial.println("here is blofeld");
            blofeld = i;
            } */

      }
      delay(10);
   }
   midi01.setHandleNoteOn(myNoteOn);
   midi01.setHandleNoteOff(myNoteOff);
   midi01.setHandleAfterTouchPoly(myAfterTouchPoly);
   midi01.setHandleControlChange(myControlChange);
   midi01.setHandleProgramChange(myProgramChange);
   midi01.setHandleAfterTouchChannel(myAfterTouchChannel);
   midi01.setHandlePitchChange(myPitchChange);
   // Only one of these System Exclusive handlers will actually be
   // used.  See the comments below for the difference between them.
   midi01.setHandleSystemExclusive(mySystemExclusiveChunk);
   midi01.setHandleSystemExclusive(mySystemExclusive);
   midi01.setHandleTimeCodeQuarterFrame(myTimeCodeQuarterFrame);
   midi01.setHandleSongPosition(mySongPosition);
   midi01.setHandleSongSelect(mySongSelect);
   midi01.setHandleTuneRequest(myTuneRequest);
   midi01.setHandleClock(myClock);
   midi01.setHandleStart(myStart);
   midi01.setHandleContinue(myContinue);
   midi01.setHandleStop(myStop);
   midi01.setHandleActiveSensing(myActiveSensing);
   midi01.setHandleSystemReset(mySystemReset);
   // This generic System Real Time handler is only used if the
   // more specific ones are not set.
   midi01.setHandleRealTimeSystem(myRealTimeSystem);
}

Running your sketch (exactly as posted, but with the added crash report) results in the following crash report:

Code:
CrashReport:
  A problem occurred at (system time) 0:0:2
  Code was executing from address 0x57E4
  CFSR: 82
	(DACCVIOL) Data Access Violation
	(MMARVALID) Accessed Address: 0x0 (nullptr)
	  Check code at 0x57E4 - very likely a bug!
	  Run "addr2line -e mysketch.ino.elf 0x57E4" for filename & line number.
  Temperature inside the chip was 32.78 °C
  Startup CPU clock speed is 600MHz
  Breadcrumb #1 was 1087474310 (0x40D18A86)
  Breadcrumb #3 was 9467936 (0x907820)
  Breadcrumb #4 was 3309265875 (0xC53F63D3)
  Breadcrumb #5 was 888429617 (0x34F45C31)
  Breadcrumb #6 was 1219487063 (0x48AFE557)
USB Host InputFunctions example
trying0

Looking at the listing file (.lst extension in the temporary build folder) to correlate the reported failure location, this address falls within the "strlen" function as follows:

Code:
000057c0 <strlen>:
    57c0:	f890 f000 	pld	[r0]
    57c4:	e96d 4502 	strd	r4, r5, [sp, #-8]!
    57c8:	f020 0107 	bic.w	r1, r0, #7
    57cc:	f06f 0c00 	mvn.w	ip, #0
    57d0:	f010 0407 	ands.w	r4, r0, #7
    57d4:	f891 f020 	pld	[r1, #32]
    57d8:	f040 8049 	bne.w	586e <strlen+0xae>
    57dc:	f04f 0400 	mov.w	r4, #0
    57e0:	f06f 0007 	mvn.w	r0, #7
[COLOR="#FF0000"]    57e4:	e9d1 2300 	ldrd	r2, r3, [r1]
[/COLOR]    57e8:	f891 f040 	pld	[r1, #64]	; 0x40
    57ec:	f100 0008 	add.w	r0, r0, #8
    57f0:	fa82 f24c 	uadd8	r2, r2, ip
    57f4:	faa4 f28c 	sel	r2, r4, ip
    57f8:	fa83 f34c 	uadd8	r3, r3, ip
    57fc:	faa2 f38c 	sel	r3, r2, ip
    5800:	bb4b      	cbnz	r3, 5856 <strlen+0x96>
    5802:	e9d1 2302 	ldrd	r2, r3, [r1, #8]
    5806:	fa82 f24c 	uadd8	r2, r2, ip
    580a:	f100 0008 	add.w	r0, r0, #8
    580e:	faa4 f28c 	sel	r2, r4, ip
    5812:	fa83 f34c 	uadd8	r3, r3, ip
    5816:	faa2 f38c 	sel	r3, r2, ip
    581a:	b9e3      	cbnz	r3, 5856 <strlen+0x96>
    581c:	e9d1 2304 	ldrd	r2, r3, [r1, #16]
    5820:	fa82 f24c 	uadd8	r2, r2, ip
    5824:	f100 0008 	add.w	r0, r0, #8
    5828:	faa4 f28c 	sel	r2, r4, ip
    582c:	fa83 f34c 	uadd8	r3, r3, ip
    5830:	faa2 f38c 	sel	r3, r2, ip
    5834:	b97b      	cbnz	r3, 5856 <strlen+0x96>
    5836:	e9d1 2306 	ldrd	r2, r3, [r1, #24]
    583a:	f101 0120 	add.w	r1, r1, #32
    583e:	fa82 f24c 	uadd8	r2, r2, ip
    5842:	f100 0008 	add.w	r0, r0, #8
    5846:	faa4 f28c 	sel	r2, r4, ip
    584a:	fa83 f34c 	uadd8	r3, r3, ip
    584e:	faa2 f38c 	sel	r3, r2, ip
    5852:	2b00      	cmp	r3, #0
    5854:	d0c6      	beq.n	57e4 <strlen+0x24>
    5856:	2a00      	cmp	r2, #0
    5858:	bf04      	itt	eq
    585a:	3004      	addeq	r0, #4
    585c:	461a      	moveq	r2, r3
    585e:	ba12      	rev	r2, r2
    5860:	fab2 f282 	clz	r2, r2
    5864:	e8fd 4502 	ldrd	r4, r5, [sp], #8
    5868:	eb00 00d2 	add.w	r0, r0, r2, lsr #3
    586c:	4770      	bx	lr
    586e:	e9d1 2300 	ldrd	r2, r3, [r1]
    5872:	f004 0503 	and.w	r5, r4, #3
    5876:	f1c4 0000 	rsb	r0, r4, #0
    587a:	ea4f 05c5 	mov.w	r5, r5, lsl #3
    587e:	f014 0f04 	tst.w	r4, #4
    5882:	f891 f040 	pld	[r1, #64]	; 0x40
    5886:	fa0c f505 	lsl.w	r5, ip, r5
    588a:	ea62 0205 	orn	r2, r2, r5
    588e:	bf1c      	itt	ne
    5890:	ea63 0305 	ornne	r3, r3, r5
    5894:	4662      	movne	r2, ip
    5896:	f04f 0400 	mov.w	r4, #0
    589a:	e7a9      	b.n	57f0 <strlen+0x30>
    589c:	0000      	movs	r0, r0
	...

Speculating that the first line which attempts to print the serialnumber might be the culprit (trying to print an empty string, which results in accessing a NULL pointer), & using the fact that your second reference to the serialnumber already included a check for non-NULL, I made a slight modification to your sketch as follows:

Code:
      if ((char*)midilist[i]->serialNumber())
      {
         Serial.println((char*)midilist[i]->serialNumber());
      }

With this change, the crash is eliminated. Now, determining the exact cause still remains as an exercise for the reader ;) . . .

Hope that helps . . .

Mark J Culross
KD5RXT
 
yes it does... actually i had the code in this way before:

Code:
if (midilist[i]->manufacturer() != NULL && midilist[i]->serialNumber() != NULL) {
     Serial.println("-----------------------------------"); 
     Serial.print("Serial:"); 
     Serial.println((char*)midilist[i]->serialNumber());
     Serial.print("ProductID:"); 
     Serial.println(midilist[i]->idProduct());
     Serial.println("-----------------------------------"); 
}

which checks for the NULL... thanks!
 
Back
Top