PaulStoffregen / USBHost_t36

USB Host Library for Teensy 3.6 and 4.0
170 stars 87 forks source link

Support for using both USB1 and USB2 in host mode #61

Open lukehutch opened 3 years ago

lukehutch commented 3 years ago

This pull request enables the use of USB1 in host mode on Teensy 4.x. (Both USB1 and USB2 are host-mode-capable.) The changes should be backwards compatible.

This patch creates a new class, USBHostPort, which factors out all port-specific memory allocations and methods from non-port-specific host methods, and then changes USB register access code to require a host port number parameter specific to a given USBHostPort instance.

There is a new constructor USBHost(uint8_t host_port), and calling the constructor USBHost() is equivalent to calling USBHost(2) for backwards compatibility. To get USB1 working in host mode, you can instead construct USBHost(1). The USBMODE of USB1 is changed to host mode when the USBHost(1) instance is initialized.

The PR is not quite ready for merge -- I need help with one issue: Currently asynch-scheduled transfers are not triggering the isr() method, and I can't figure out why. Test code:

  USBHost host;
  host.begin();
  msController drive(host);

  uint8_t mscError;
  if((mscError = drive.mscInit())) {
    Serial.printf(F("Init err: %d\n"), mscError);
  } else {
    Serial.printf(F("Init OK\n"));
  }

For some reason this works with the trunk version of the library, but the isr() callback is never called for async-scheduled transfers, i.e. where (stat & USBHS_USBSTS_UAI) is nonzero in the isr() function. However, isr() is still called for other non-async transfer types.

Can somebody please help identify why these changes may be causing async interrupts to be dropped? I haven't fundamentally changed the functionality of any of the code. I have tried extensively to debug this, but I don't understand why this is happening.

Relevant code:

USBHost::begin() correctly sets up the isr() callback using:

attachInterruptVector(IRQ_USBHS_(host_port), usb_host_port->isr_callback);

new_Pipe() correctly enables async scheduling:

    USBHS_USBCMD_(host_port) |= USBHS_USBCMD_ASE; // enable async schedule

queue_Control_Transfer() correctly calls init_qTD(status, NULL, 0, status_direction, 1, true), i.e. irq == true, which should trigger the async callback to run after the transfer is complete.

What am I missing here?