USB powered hub with Teensy 4.1 host not working correctly

steeley

Well-known member
Trying to figure out this Teensy USB host stuff, but found no documentation on it so here is the issue.
I'm on Teensyduino 1.56 Arduino 1.8.19

I want to connect some other Teensy( 3 x 3.2s) devices over USB serial via a 4-port powered hub. They just send some serial data over USB serial back to T4.1 host
This works perfectly if I connect to the T4.1 host without the hub. Connect/disconnect, send/receive data etc - all good.

The issue is when I use the hub connected to the T4.1 host. I can plug in a t3.2 to the huband its ok .
However when I disconnect the t there is no 'disconnect' message.
Replugging it and it does not connect back to the host. No connect message, nothing.
The only way to get it to works is unplug the hub and the t3.2 and replug the whole thing which is obviously of no practical use.

Connecting the hub and T.3.2 to my MacBook and it seems fine.

I'm using the example from USBHOST-T36 - 'Serial' - not that easy to understand - seems to have a load of stuff for some robot device which
I removed as it had no use for my testing.

My T4.1 sketch is shown below. Any ideas on how to fix this ?

TIA

Code:
// Simple test of USB Host Mouse/Keyboard
//
// This example is in the public domain

#include "USBHost_t36.h"
#define USBBAUD 115200
uint32_t baud = USBBAUD;
uint32_t format = USBHOST_SERIAL_8N1;
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHIDParser hid1(myusb);
USBHIDParser hid2(myusb);
USBHIDParser hid3(myusb);

// There is now two versions of the USBSerial class, that are both derived from a common Base class
// The difference is on how large of transfers that it can handle.  This is controlled by
// the device descriptor, where up to now we handled those up to 64 byte USB transfers.
// But there are now new devices that support larger transfer like 512 bytes.  This for example
// includes the Teensy 4.x boards.  For these we need the big buffer version. 
// uncomment one of the following defines for userial
//USBSerial userial(myusb);  // works only for those Serial devices who transfer <=64 bytes (like T3.x, FTDI...)
USBSerial_BigBuffer userial(myusb, 1); // Handles anything up to 512 bytes
//USBSerial_BigBuffer userial(myusb); // Handles up to 512 but by default only for those > 64 bytes


USBDriver *drivers[] = {&hub1, &hub2, &hid1, &hid2, &hid3, &userial};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
const char * driver_names[CNT_DEVICES] = {"Hub1", "Hub2",  "HID1", "HID2", "HID3", "USERIAL1" };
bool driver_active[CNT_DEVICES] = {false, false, false, false};

void setup()
{
  pinMode(13, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  for (int i = 0; i < 5; i++) {
    digitalWrite(2, HIGH);
    delayMicroseconds(50);
    digitalWrite(2, LOW);
    delayMicroseconds(50);
  }
  while (!Serial && (millis() < 5000)) ; // wait for Arduino Serial Monitor
  Serial.println("\n\nUSB Host Testing - Serial");
  myusb.begin();
 // Serial1.begin(115200);  // We will echo stuff Through Serial1...

}


void loop()
{
  digitalWrite(13, !digitalRead(13));
  myusb.Task();
  // Print out information about different devices.
  for (uint8_t i = 0; i < CNT_DEVICES; i++) {
    if (*drivers[i] != driver_active[i]) {
      if (driver_active[i]) {
        Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]);
        driver_active[i] = false;
      } else {
        Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct());
        driver_active[i] = true;

        const uint8_t *psz = drivers[i]->manufacturer();
        if (psz && *psz) Serial.printf("  manufacturer: %s\n", psz);
        psz = drivers[i]->product();
        if (psz && *psz) Serial.printf("  product: %s\n", psz);
        psz = drivers[i]->serialNumber();
        if (psz && *psz) Serial.printf("  Serial: %s\n", psz);

        // If this is a new Serial device.
        if (drivers[i] == &userial) {
          // Lets try first outputting something to our USerial to see if it will go out...
          userial.begin(baud);
        }
      }
    }
  }


  while (userial.available()) { // from usb device to ??
//    Serial.println("USerial Available");
    Serial.write(userial.read());
  }

  while (Serial.available()) { // from host to usb device
//    Serial.println("USerial Available");
     userial.write(Serial.read());
  }
  
}
 
I've just tried a a really old unpowered USB (1.1??) hub and it seems to sort of work now.

The hub I was originally using was a Transcend USB 2.0 hub - which always seems to work ok when connect to laptop desktop etc.

Do I need to do something special to get a USB 2.0 hub to work?

Also - do I need multiple serial usb classes to support more that 1 t.3.2 as a serial device?

TIA
 
Any chance you could try other USB 2.0 or 3.0 hubs? If it's a problem limited to just 1 particular hub, maybe I could talk you into sending me that troublesome hub? Or if that exact model is still available for purchase (sadly, manufacturers tend to change the internals of these sorts of products after a year or two) can you tell me where to buy one?

Here's a blog article I wrote the last time I investigated a problem with a particular hub.

https://www.pjrc.com/usb-hub-bug-hunting-lessons-learned/

In the end, it did turn out to be a subtle bug in USBHost_t36 buried deep within ehci.cpp. The article shows a deep dive into the details.


And to answer this specific question

Also - do I need multiple serial usb classes to support more that 1 t.3.2 as a serial device?

Yes, you do.
 
Thanks for the speedy reply Paul. Sorry I just noticed I read the info on the Transcend hub incorrectly. Its actually a USB 3.0 hub. TS-HUB3K:
https://www.transcend-info.com/Products/No-402
Been around for a few years and seems to be readily available.

Can send it if needed - I'm not in the US but happy to post by snail mail if required, and if it helps others who are using USB.
I'm going to try a Startech ST4200USB 'industrial' USB 2.0 hub which looks like a good starting point.

Re: separate USB serial classes:
Does the Teensy USB host stack automatically manage the serial devices - (tell which is which) or do I need to do that myself?
I will need to handle 6 serial devices only, no mice or keyboards or other USB devices.
Hopefully I can figure it out.
 
Further testing with some other USB devices - Raspberry Pico will NOT work with Teensy 4.1 USB Host through any kind of hub.
Details shown below:

test:
Teensyduino 1.56 Arduino 1.8.19
Startech ST4200USB 4 port hub (powered)
Teensy 4.1 with USB host serial example (without robot code)

Teensy 3.5
Direct to T4.1 host = OK
Via hub = OK

Raspberry Pico
Direct to T4.1 host = OK
Via hub = No, stops host working, needs reboot.

M5-Atom(ESP32)
Direct to T4.1 host = OK
Via hub = OK

Using HIDDeviceInfo example:

Pico direct to T4.1:
Code:
USBDeviceInfo claim this=2000CAC8

****************************************
** Device Level **
  vid=2E8A
  pid=A
  bDeviceClass = 2
  bDeviceSubClass = 2
  bDeviceProtocol = 1
08 0B 00 02 02 02 00 00 09 04 00 00 01 02 02 00 04 05 24 00 20 01 05 24 01 00 01 04 24 02 02 05
24 06 00 01 07 05 81 03 08 00 10 09 04 01 00 02 0A 00 00 00 07 05 02 02 40 00 00 07 05 82 02 40
00 00 

USBDeviceInfo claim this=2000CAC8

****************************************
** Interface Level **
09 04 00 00 01 02 02 00 04 05 24 00 20 01 05 24 01 00 01 04 24 02 02 05 24 06 00 01 07 05 81 03
08 00 10 09 04 01 00 02 0A 00 00 00 07 05 02 02 40 00 00 07 05 82 02 40 00 00 
 bInterfaceNumber = 0
 number end points = 1
 bInterfaceClass =    2
 bInterfaceSubClass = 2
    Communicatons and CDC
 bInterfaceProtocol = 0

USBDeviceInfo claim this=2000CAC8

****************************************
** Interface Level **
09 04 01 00 02 0A 00 00 00 07 05 02 02 40 00 00 07 05 82 02 40 00 00

Pico Via hub:

Code:
USBDeviceInfo claim this=2000CAC8

****************************************
** Device Level **
  vid=932
  pid=4
  bDeviceClass = 2
  bDeviceSubClass = 2
  bDeviceProtocol = 1
09 04 00 00 01 09 00 00 00 07 05 81 03 01 00 0C 04 05 24 00 20 01 05 24 01 00 01 04 24 02 02 05
24 06 00 01 07 05 81 03 08 00 10 09 04 01 00 02 0A 00 00 00 07 05 02 02 40 00 00 07 05 82 02 40
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

USBDeviceInfo claim this=2000CAC8

****************************************
** Interface Level **
09 04 00 00 01 09 00 00 00 07 05 81 03 01 00 0C 04 05 24 00 20 01 05 24 01 00 01 04 24 02 02 05
24 06 00 01 07 05 81 03 08 00 10 09 04 01 00 02 0A 00 00 00 07 05 02 02 40 00 00 07 05 82 02 40
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0
 
I've just tried a Raspberry Pico running MicroPython and it DOES work through a hub, so I guess there is some
odd combination of Arduino on Pico, and Serial USB comms via a hub to Teensy USB Host.

Thanks macrosii - interesting stuff. I'm using genuine Pico boards.
 
Last edited:
Yes I'm using all genuine boards.
I went with Circuitpython as its easy to add a second serial interface. You can do that in Micropython but you have to compile the mods yourself (for the pico) which I have not tried yet.
I have not had any issued with T3.2 serial.
Out of interest try turning on the Debug option in the library, uncomment //#define USBHOST_PRINT_DEBUG in USBHost_t36.h
What I then see is the teensy4.1 locks up in a loop trying to get the device descriptor.
 
Yes I can see it has issues with some devices through hubs.

Unfortunately its not useful to me me if this does not work.
 
Back
Top