Teensy 4.1 and sysex MIDI messages in host mode

Status
Not open for further replies.

Xantra

Member
Hi All,
Here's some context first. I'm trying to connect my guitar amp to a teensy 4.1 via usb in order to control the amp via some custom code running on the teensy. The end goal is to be able to turn effects on and off via some foot switches. The messages I need to send to the amp are sysex midi over usb, and I already found plenty of resources on that topic. But most (all) people doing such thing seems to be using an SPI to USB adapter instead of a built-in usb like I want to do with my teensy 4.1.

I think I need to select "Serial + MIDI" in the Tool, USB type menu in the Arduino IDE. Am I correct in assuming that this means the programming USB will stay as my Serial link for debug and the other USB (the one I soldered to the usb host cable) will be my host for the amp and I will be able to talk to it via MIDI commands ?

I think my best bet will be to use usbMIDI.sendSysEx() right ?

Is there something I need to run to initialise the usb, or the midi ? Before I send any command, how can I check that something is connected to the usb host ? And how can I query it to know what it is ?


Thanks
 
I have been doing some more reading on the forum and other places, and I think I made some progress but I also have new questions now. But let me start by answering one of my own question.
I think I need to select "Serial + MIDI" in the Tool, USB type menu in the Arduino IDE. Am I correct in assuming that this means the programming USB will stay as my Serial link for debug and the other USB (the one I soldered to the usb host cable) will be my host for the amp and I will be able to talk to it via MIDI commands ?
This only affects the main USB, not the USB Host (2nd interface).

I have now coded the following basic thing, and enabled USBHost debug.
Code:
#include "USBHost_t36.h"

USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
MIDIDevice midi1(myusb);

void setup() {
  Serial.begin(115200);
  delay(1500);
  myusb.begin();
  Serial.println("Ready");
}

void loop() {
  myusb.Task();
  midi1.read();
}

When I plug the amp to the teensy I get the following from the Serial port :
Code:
USB2 PLL running
 reset waited 6
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 20003000
periodictable = 20003000
Ready
port change: 14001403
    connect
  begin reset
port change: 14001005
  port enabled
  end recovery
new_Device: 1.5 Mbit/sec
new_Pipe
ERROR Followup
    remove from followup list
    stray halted 200034C0
  qtd: 20003480, token=80080180, next=200034C0
  qtd: 200034C0, token=80008080, next=20003500
  dummy halt: 20003500
enumeration:
    remain on followup list
    remain on followup list
    remain on followup list

So something seem to be going wrong during enumeration. I have just soldered a bunch of wires to the teensy without shielding for the usb, is this the problem ? Or is the USBHost lib not able to recognise the device I'm plugging in ?
 
I have just soldered a bunch of wires to the teensy without shielding for the usb, is this the problem ?
I have now used a shielded cable and grounded it on both sides, and I'm still getting the same error, so it seems to be an enumeration issue.

I tried to plug a usb key onto it instead because that's the only other usb device I have on hand, but nothing happens.
Any idea what could be the issue here or what I could try ?
 
Here are some details from Linux of what happens when I plug the amp

Code:
[  167.356085] usb 1-1.3: new high-speed USB device number 4 using dwc_otg
[  167.488353] usb 1-1.3: New USB device found, idVendor=0582, idProduct=01d8, bcdDevice= 0.00
[  167.488439] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  167.488465] usb 1-1.3: Product: KATANA
[  167.488487] usb 1-1.3: Manufacturer: BOSS
[  168.015425] usbcore: registered new interface driver snd-usb-audio

Code:
pi@raspberrypi:~ $ sudo amidi -l
Dir Device    Name
IO  hw:2,0,0  KATANA MIDI 1
IO  hw:2,0,1  KATANA MIDI 2
IO  hw:2,0,2  KATANA MIDI 3

Code:
pi@raspberrypi:~ $ lsusb -v -d 0582:01d8
Bus 001 Device 005: ID 0582:01d8 Roland Corp.
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          255 Vendor Specific Class
  bDeviceSubClass         0
  bDeviceProtocol       255
  bMaxPacketSize0        64
  idVendor           0x0582 Roland Corp.
  idProduct          0x01d8
  bcdDevice            0.00
  iManufacturer           1
  iProduct                2
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x00bc
    bNumInterfaces          4
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xc0
      Self Powered
    MaxPower                0mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol      0
      iInterface              0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      2
      bInterfaceProtocol      2
      iInterface              0
      ** UNRECOGNIZED:  06 24 f1 01 00 00
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       1
      bNumEndpoints           1
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      2
      bInterfaceProtocol      2
      iInterface              0
      ** UNRECOGNIZED:  07 24 01 01 00 01 00
      ** UNRECOGNIZED:  0b 24 02 01 04 04 18 01 44 ac 00
      ** UNRECOGNIZED:  06 24 f1 04 16 00
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x0d  EP 13 OUT
        bmAttributes            5
          Transfer Type            Isochronous
          Synch Type               Asynchronous
          Usage Type               Data
        wMaxPacketSize     0x0070  1x 112 bytes
        bInterval               1
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      2
      bInterfaceProtocol      1
      iInterface              0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       1
      bNumEndpoints           1
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      2
      bInterfaceProtocol      1
      iInterface              0
      ** UNRECOGNIZED:  07 24 01 07 00 01 00
      ** UNRECOGNIZED:  0b 24 02 01 04 04 18 01 44 ac 00
      ** UNRECOGNIZED:  06 24 f1 04 16 00
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x8e  EP 14 IN
        bmAttributes           37
          Transfer Type            Isochronous
          Synch Type               Asynchronous
          Usage Type               Implicit feedback Data
        wMaxPacketSize     0x0070  1x 112 bytes
        bInterval               1
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        3
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      3
      bInterfaceProtocol      0
      iInterface              0
      ** UNRECOGNIZED:  06 24 f1 02 03 03
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x03  EP 3 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x84  EP 4 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        3
      bAlternateSetting       1
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      3
      bInterfaceProtocol      0
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x03  EP 3 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               4
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x85  EP 5 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               4
 
Best I can tell is that the USB Midi is not class compliant since this device does need a driver as per the Boss website and the the lsusb results only show Vender Specific Classes. If you wanted to go the hard route you’d have to reverse engineer a driver for the Teensy for this or you could just use the DIN Midi on the Katana.
 
It seems to be registered as a MIDI device out of the box in Linux though, so their must be some sort of a driver built into Linux that does that right ? Would this be part of the Linux Kernel or would ALSA bridge the gap in this case ? As both projects are opensource, I should be able to find the source of the driver right ? Any idea where I could start on this quest ?

Also, it seems that some people have been able to work around that problem by using a USB host shield based on the MAX3421E and the following lib : https://github.com/felis/USB_Host_Shield_2.0
I doubt that the MAX3421E has special support for the Katana, so would that mean that this library contain special code for the Katana ?

Unfortunately I have the model that only has a USB port, and doesn't have the DIN MIDI plug. I wouldn't mind to go the hard way, as I don't know anything about USB that would be a good learning exercise. But unfortunately as I don't know anything about USB I'm not too sure where to start from :).

By the way, I also found the following post that seems to be in the exact same condition as me (none class compliant midi device), but in his case the enumeration does work successfully, so I think there's something else wrong causing the followup error I'm seeing preventing the enumeration to complete correctly :
https://forum.pjrc.com/threads/55142-MIDI-SendSysEx-on-USB-host
 
Last edited:
So I have now sorted my enumeration issue, and I'm a bit confused because it seems that the library picked-up the device as a midi device and seems to have associated it correctly.

Code:
USB2 PLL running
 reset waited 6
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 20003000
periodictable = 20003000
Ready
port change: 10001803
    connect
  begin reset
port change: 18001205
  port enabled
  end recovery
new_Device: 480 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
  12 01 00 02 FF 00 FF 40 82 05 D8 01 00 00 01 02 00 01 
    VendorID = 0582, ProductID = 01D8, Version = 0000
    Class/Subclass/Protocol = 255 / 0 / 255
    Number of Configurations = 1
enumeration:
enumeration:
Manufacturer: BOSS
enumeration:
Product: KATANA
enumeration:
Config data length = 188
enumeration:
Configuration Descriptor:
  09 02 BC 00 04 01 00 C0 00 
    NumInterfaces = 4
    ConfigurationValue = 1
  09 04 00 00 00 FF FF 00 00 
    Interface = 0
    Number of endpoints = 0
    Class/Subclass/Protocol = 255 / 255 / 0
  09 04 01 00 00 FF 02 02 00 
    Interface = 1
    Number of endpoints = 0
    Class/Subclass/Protocol = 255 / 2 / 2
  06 24 F1 01 00 00 
  09 04 01 01 01 FF 02 02 00 
    Interface = 1
    Number of endpoints = 1
    Class/Subclass/Protocol = 255 / 2 / 2
  07 24 01 01 00 01 00 
  0B 24 02 01 04 04 18 01 44 AC 00 
  06 24 F1 04 16 00 
  07 05 0D 05 70 00 01 
    Endpoint = 13 OUT
    Type = Isochronous
    Max Size = 112
    Polling Interval = 1
  07 25 01 00 00 00 00 
  09 04 02 00 00 FF 02 01 00 
    Interface = 2
    Number of endpoints = 0
    Class/Subclass/Protocol = 255 / 2 / 1
  09 04 02 01 01 FF 02 01 00 
    Interface = 2
    Number of endpoints = 1
    Class/Subclass/Protocol = 255 / 2 / 1
  07 24 01 07 00 01 00 
  0B 24 02 01 04 04 18 01 44 AC 00 
  06 24 F1 04 16 00 
  07 05 8E 25 70 00 01 
    Endpoint = 14 IN
    Type = Isochronous
    Max Size = 112
    Polling Interval = 1
  07 25 01 00 00 00 00 
  09 04 03 00 02 FF 03 00 00 
    Interface = 3
    Number of endpoints = 2
    Class/Subclass/Protocol = 255 / 3 / 0
  06 24 F1 02 03 03 
  07 05 03 02 00 02 01 
    Endpoint = 3 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 1
  07 05 84 02 00 02 00 
    Endpoint = 4 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 0
  09 04 03 01 02 FF 03 00 00 
    Interface = 3
    Number of endpoints = 2
    Class/Subclass/Protocol = 255 / 3 / 0
  07 05 03 03 00 02 04 
    Endpoint = 3 OUT
    Type = Interrupt
    Max Size = 512
    Polling Interval = 4
  07 05 85 03 00 02 04 
    Endpoint = 5 IN
    Type = Interrupt
    Max Size = 512
    Polling Interval = 4
enumeration:
USBHub memory usage = 960
USBHub claim_device this=200023A0
USBHub memory usage = 960
USBHub claim_device this=20002760
Descriptor 4 = INTERFACE
MIDIDevice claim this=20001CC0
len = 179
  Interface is unknown (might be Yahama)
type: 4, len: 9
This interface is not MIDI
Descriptor 4 = INTERFACE
MIDIDevice claim this=20001CC0
len = 170
  Interface is unknown (might be Yahama)
type: 36, len: 6
    Unknown MIDI CS_INTERFACE descriptor!
Descriptor 36 =  ???
Descriptor 4 = INTERFACE
MIDIDevice claim this=20001CC0
len = 155
  Interface is unknown (might be Yahama)
type: 36, len: 7
    MIDI Header (ignored)
type: 36, len: 11
    MIDI IN Jack (ignored)
type: 36, len: 6
    Unknown MIDI CS_INTERFACE descriptor!
Descriptor 36 =  ???
Descriptor 36 =  ???
Descriptor 36 =  ???
Descriptor 5 = ENDPOINT
Descriptor 37 =  ???
Descriptor 4 = INTERFACE
MIDIDevice claim this=20001CC0
len = 108
  Interface is unknown (might be Yahama)
type: 4, len: 9
This interface is not MIDI
Descriptor 4 = INTERFACE
MIDIDevice claim this=20001CC0
len = 99
  Interface is unknown (might be Yahama)
type: 36, len: 7
    MIDI Header (ignored)
type: 36, len: 11
    MIDI IN Jack (ignored)
type: 36, len: 6
    Unknown MIDI CS_INTERFACE descriptor!
Descriptor 36 =  ???
Descriptor 36 =  ???
Descriptor 36 =  ???
Descriptor 5 = ENDPOINT
Descriptor 37 =  ???
Descriptor 4 = INTERFACE
MIDIDevice claim this=20001CC0
len = 52
  Interface is unknown (might be Yahama)
type: 36, len: 6
    Roland vendor-specific (ignored)
type: 5, len: 7
    MIDI Endpoint: 3
      tx_size = 512
type: 5, len: 7
    MIDI Endpoint: 84
      rx_size = 512
type: 4, len: 9
Descriptor 36 =  ???
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
Descriptor 4 = INTERFACE
MIDIDevice claim this=20001CC0
len = 23
  Interface is unknown (might be Yahama)
type: 5, len: 7
    MIDI Endpoint: 3
      tx_size = 512
type: 5, len: 7
    MIDI Endpoint: 85
      rx_size = 512
This interface is not MIDI
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT

I think the following means that the device was registered as a midi device right ?
Code:
...
Descriptor 4 = INTERFACE
MIDIDevice claim this=20001CC0
len = 52
  Interface is unknown (might be Yahama)
type: 36, len: 6
    Roland vendor-specific (ignored)
type: 5, len: 7
    MIDI Endpoint: 3
      tx_size = 512
type: 5, len: 7
    MIDI Endpoint: 84
      rx_size = 512
type: 4, len: 9
Descriptor 36 =  ???
...
 
It’s close but I can see the issue with these lines here:
Code:
 Descriptor 4 = INTERFACE
MIDIDevice claim this=20001CC0
len = 99
  Interface is unknown (might be Yahama)
type: 36, len: 7
    MIDI Header (ignored)
type: 36, len: 11
    MIDI IN Jack (ignored)
type: 36, len: 6
    [COLOR="#FF0000"]Unknown MIDI CS_INTERFACE descriptor![/COLOR]
Where it says unknown descriptor that’s where it fails.


From your lsusb information it corresponds to this interface and the unknown part is the 3rd unrecognized line.
Code:
 Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       1
      bNumEndpoints           1
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      2
      bInterfaceProtocol      1
      iInterface              0
      ** UNRECOGNIZED:  07 24 01 07 00 01 00
      ** UNRECOGNIZED:  0b 24 02 01 04 04 18 01 44 ac 00
     [COLOR="#FF0000"] ** UNRECOGNIZED:  06 24 f1 04 16 00[/COLOR]
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x8e  EP 14 IN
        bmAttributes           37
          Transfer Type            Isochronous
          Synch Type               Asynchronous
          Usage Type               Implicit feedback Data
        wMaxPacketSize     0x0070  1x 112 bytes
        bInterval               1

From looking through the host code here you can see where it comes close to matching.
Code:
 else if (subtype == 0xF1 && [COLOR="#FF0000"]p[3] == 2[/COLOR]) {
				// see Linux sound/usb/quirks.c create_roland_midi_quirk()
				println("    Roland vendor-specific (ignored)");
				ismidi = true;
			}
You can add another copy of this else if statement to match your Katana and it should pass.
Code:
 else if (subtype == 0xF1 && [COLOR="#FF0000"]p[3] == 4[/COLOR]) {
				// see Linux sound/usb/quirks.c create_roland_midi_quirk()
				println("    Roland/Boss vendor-specific (ignored)");
				ismidi = true;
			}
 
Right, so as expected I'm now discovering 3 MIDI devices, which matches what Linux reports.

Code:
MIDIDevice claim this=20001CC0
len = 155
  Interface is unknown (might be Yahama)
type: 36, len: 7
    MIDI Header (ignored)
type: 36, len: 11
    MIDI IN Jack (ignored)
type: 36, len: 6
    Roland vendor-specific (ignored)
type: 5, len: 7

MIDIDevice claim this=20001CC0
len = 99
  Interface is unknown (might be Yahama)
type: 36, len: 7
    MIDI Header (ignored)
type: 36, len: 11
    MIDI IN Jack (ignored)
type: 36, len: 6
    Roland vendor-specific (ignored)
type: 5, len: 7

MIDIDevice claim this=20001CC0
len = 52
  Interface is unknown (might be Yahama)
type: 36, len: 6
    Roland vendor-specific (ignored)
type: 5, len: 7
    MIDI Endpoint: 3
      tx_size = 512
type: 5, len: 7
    MIDI Endpoint: 84
      rx_size = 512
type: 4, len: 9

How would the MIDIDevice driver deals with the 3 devices now ? Do I need to declare 3 MIDIDevice in my code ? Because when I do that I then see everything reported 3 times, like if all 3 MIDI devices where getting associated with all the 3 MIDIDevice.
I'm not sure how I can address each individual MIDI device.
Also, is there a way to check what is associated to the MIDIDevice ? Something like midi1.is_connected() or midi1.get_descriptor() ?
 
Right, quick update guys, I got it to work in the end without making any update to the library. Here's what I coded to change the Reverb mode every second for example :

Code:
#include "USBHost_t36.h"

const byte editor[15] = {0xF0, 0x41, 0x00, 0x00, 0x00, 0x00, 0x33, 0x12, 0x7F, 0x00, 0x00, 0x01, 0x01, 0x7F, 0xF7};
const byte reverb[15] = {0xF0, 0x41, 0x00, 0x00, 0x00, 0x00, 0x33, 0x12, 0x7F, 0x01, 0x01, 0x05, 0x00, 0x7A, 0xF7};

USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
MIDIDevice_BigBuffer midi1(myusb);


void setup() {
  Serial.begin(115200);
  delay(1500);
  myusb.begin();
  Serial.println("Ready");
}

void loop() {
  myusb.Task();

  midi1.sendSysEx(15, editor, true);
  midi1.send_now();
  delay(100);
  midi1.sendSysEx(15, reverb, true);
  midi1.send_now();
  delay(100);

  delay(1000);

}

I think the trick was to execute the send_now after each command and wait for a bit.
 
You can do an if statement to tell if something is connected like this:
Code:
if(midi1){
//Do something here
}

The other things you can do are these to help identify devices, but I don't believe there is anything to get the individual midi port names if a device has more than one:
Code:
midi1.idVendor(); //2 byte vendor id
midi1.idProduct(); //2 byte product id
midi1.manufacturer(); //Null-terminated manufacturer string
midi1.product(); //Null-terminated product string
midi1.serialNumber(); //Null-terminated serial number string
 
Status
Not open for further replies.
Back
Top