Low-Level USB Errors with eXplorerKit

All technical discussions and projects around startKIT
Post Reply
XCoreXploits
Junior Member
Posts: 4
Joined: Tue Oct 18, 2016 2:56 am

Low-Level USB Errors with eXplorerKit

Post by XCoreXploits »

Hi Folks,

I recently got a hold of an xCore-200 eXplorekit and have been developing a USB-based system with the device. I'm starting with trying to get the device to appear as a USB microphone so it can generate audio tones to the computer. I have code based on the xud usb lib examples and the device specification from the USB Audio standard PDF.

When I plug in the device, I do not get desirable results. Windows says the device descriptor request failed. Thus, I put in a lot of debug printf() statements both in my code and the xud library. I traced down to the USB_StandardRequests, and found that we are in fact correctly routing the device request (which windows is sending on the order of once per second), but that the relevant call to the XUD_DoGetRequest function within USB_StandardRequests is failing with an error. The relevant code is:

Code: Select all

                                else if(devDescLength_hs != 0)
                                {
                                    /* Return high-speed device descriptor, if no FS desc, send the HS desc */
                                    /* Do get request (send descriptor then 0 length status stage) */
                                    printf("Do the high-speed usb\n");
                                    return XUD_DoGetRequest(ep_out, ep_in, devDesc_hs, devDescLength_hs, sp.wLength);
                                }
A deeper dive into the XUD_DoGetRequest() function reveals that it is failing at XUD_SetData.

Here is my main program:

Code: Select all

XUD_Result_t ControlInterfaceClassRequests(XUD_ep ep_out, XUD_ep ep_in, USB_SetupPacket_t sp)
{
    unsigned int buffer[32];
    printf("Ignore control %x\n", sp.bRequest);
    //return XUD_RES_OKAY;
    if (sp.bRequest == 0x21)
        return XUD_DoGetRequest(ep_out, ep_in, (buffer, unsigned char[]), 7, sp.wLength);
    return XUD_DoSetRequestStatus(ep_in);
}

void EndPoint0(chanend chan_ep0_out, chanend chan_ep0_in)
{

    printf("Starting\n");

    USB_SetupPacket_t sp;

    unsigned bmRequestType;
    XUD_BusSpeed_t usbBusSpeed;
    XUD_ep ep0_out = XUD_InitEp(chan_ep0_out, XUD_EPTYPE_CTL | XUD_STATUS_ENABLE);
    XUD_ep ep0_in  = XUD_InitEp(chan_ep0_in, XUD_EPTYPE_CTL | XUD_STATUS_ENABLE);

    printf("Started!\n");

    while(1)
    {
        // Returns XUD_RES_OKAY on success, XUD_RES_RST for USB reset
        XUD_Result_t result = USB_GetSetupPacket(ep0_out, ep0_in, sp);
        if (result == XUD_RES_OKAY) {
            result = XUD_RES_ERR;
            bmRequestType = (sp.bmRequestType.Direction<<7) |
                            (sp.bmRequestType.Type<<5) |
                            (sp.bmRequestType.Recipient);

            printf("Setup packet: %u - %u - %u - %u - %u\n", bmRequestType, USB_BMREQ_H2D_CLASS_INT,
                    USB_BMREQ_D2H_CLASS_INT, USB_BMREQ_H2D_STANDARD_DEV, USB_BMREQ_D2H_STANDARD_DEV);
            printf("Setup packet request = %u, index = %u, len = %u, value = %u\n",
                    sp.bRequest, sp.wIndex, sp.wLength, sp.wValue);

            if ((bmRequestType == USB_BMREQ_H2D_STANDARD_DEV)
                   && (sp.bRequest == USB_SET_ADDRESS)) {
                // Host has set device address, value contained in sp.wValue
            }

            switch(bmRequestType) {
                /* Direction: Device-to-host and Host-to-device
                 * Type: Class
                 * Recipient: Interface
                 */
                case USB_BMREQ_H2D_CLASS_INT:
                case USB_BMREQ_D2H_CLASS_INT:
                    /* Inspect for CDC Communications Class interface num */
                    if(sp.wIndex == 0) {
                        /* Returns  XUD_RES_OKAY if handled,
                         *          XUD_RES_ERR if not handled,
                         *          XUD_RES_RST for bus reset */
                        result = ControlInterfaceClassRequests(ep0_out, ep0_in, sp);
                    }
                    break;
            }
        }

        if (result == XUD_RES_ERR) {
            /* Returns  XUD_RES_OKAY if handled okay,
             *          XUD_RES_ERR if request was not handled (STALLed),
             *          XUD_RES_RST for USB Reset */
            printf("Do standard\n");
            unsafe {
                result = USB_StandardRequests(ep0_out, ep0_in, devDesc,
                        sizeof(devDesc), cfgDesc, sizeof(cfgDesc),
                        null, 0, null, 0, stringDescriptors,
                        sizeof(stringDescriptors)/sizeof(stringDescriptors[0]),
                        sp, usbBusSpeed);
            }
            printf("Result = %d\n", result);
        }

        if (result == XUD_RES_RST) {
            usbBusSpeed = XUD_ResetEndpoint(ep0_out, ep0_in);
        }
    }
}


#define CHANNELS_OUT 2
#define CHANNELS_IN 2

void microphone_channel(chanend c_ep1, chanend c_ep2) {
    char buffer[] = {0, 0, 0, 0};
    int counter = 0;
    int state = 0;

    XUD_ep c_ep = XUD_InitEp(c_ep1, XUD_EPTYPE_ISO);
    XUD_ep c_epo = XUD_InitEp(c_ep2, XUD_EPTYPE_ISO);

    //while (1) {
//        XUD_SetBuffer(c_ep, buffer, 4) < 0;
    //}
}


int main(void) {
    chan c_ep_out[CHANNELS_OUT], c_ep_in[CHANNELS_IN];
    par {
        on USB_TILE: xud(c_ep_out, CHANNELS_OUT, c_ep_in, CHANNELS_IN,
                         null, XUD_SPEED_HS, XUD_PWR_SELF);
        on USB_TILE: EndPoint0(c_ep_out[0], c_ep_in[0]);
        on USB_TILE: microphone_channel(c_ep_out[1], c_ep_in[1]);
    }
    return 0;
}
Note: I tried different channel types for the extra channel and different out and in channel count. Did not solve the problem.

Here is the descriptors:

Code: Select all



/* Definition of Descriptors */
/* USB Device Descriptor */
static unsigned char devDesc[] =
{
    0x12,                  /* 0  bLength */
    USB_DESCTYPE_DEVICE,   /* 1  bdescriptorType - Device*/
    0x00,                  /* 2  bcdUSB version */
    0x01,                  /* 3  bcdUSB version */
    0x00,                  /* 4  bDeviceClass - USB CDC Class */
    0x00,                  /* 5  bDeviceSubClass  - Specified by interface */
    0x00,                  /* 6  bDeviceProtocol  - Specified by interface */
    0x08,                  /* 7  bMaxPacketSize for EP0 - max = 64*/
    (VENDOR_ID & 0xFF),    /* 8  idVendor */
    (VENDOR_ID >> 8),      /* 9  idVendor */
    (PRODUCT_ID & 0xFF),   /* 10 idProduct */
    (PRODUCT_ID >> 8),     /* 11 idProduct */
    (BCD_DEVICE & 0xFF),   /* 12 bcdDevice */
    (BCD_DEVICE >> 8),     /* 13 bcdDevice */
    0x01,                  /* 14 iManufacturer - index of string*/
    0x02,                  /* 15 iProduct  - index of string*/
    0x03,                  /* 16 iSerialNumber  - index of string*/
    0x01                   /* 17 bNumConfigurations */
};

/* USB Configuration Descriptor */
static unsigned char cfgDesc[0x64] = {

  0x09,                       /* 0  bLength */
  USB_DESCTYPE_CONFIGURATION, /* 1  bDescriptortype - Configuration*/
  0x64, 0x00,                 /* 2  wTotalLength */
  0x02,                       /* 4  bNumInterfaces */
  0x01,                       /* 5  bConfigurationValue */
  0x00,                       /* 6  iConfiguration - index of string */
  0x80,                       /* 7  bmAttributes - Bus powered */
  0xFF,                       /* 8  bMaxPower - 1000mA */

  /* Audio Control interface */
  0x09,                       /* 0  bLength */
  0x04,                       /* 1  bDescriptorType - Interface */
  0x00,                       /* 2  bInterfaceNumber - Interface 0 */
  0x00,                       /* 3  bAlternateSetting */
  0x00,                       /* 4  bNumEndpoints */
  0x01,                       /* 5  bInterfaceClass */
  0x01,                       /* 6  bInterfaceSubClass */
  0x00,                       /* 7  bInterfaceProtocol */
  0x00,                       /* 8  iInterface - No string descriptor */

  /* Header Functional descriptor */
  0x09,                      /* 0  bLength */
  0x24,                      /* 1  bDescriptortype, CS_INTERFACE */
  0x01,                      /* 2  bDescriptorsubtype, HEADER */
  0x00, 0x01,                /* 3  bcdADC */
  0x1E, 0x00,                /* 5  wTotalLength */
  0x01,                      /* 7  number of streaming interfaces */
  0x01,                      /* 8  AudioStreaming interface 1 */

  /* Input Terminal descriptor */
  0x0C,                      /* 0  bLength */
  0x24,                      /* 1  bDescriptortype, CS_INTERFACE */
  0x02,                      /* 2  bDescriptorsubtype, INPUT_TERMINAL */
  0x01,                      /* 3  bTerminalID */
  0x01, 0x02,                /* 4  wTerminalType (microphone) */
  0x00,                      /* 6  bAssocTerminal */
  0x01,                      /* 7  bNbrChannels */
  0x00, 0x00,                /* 8  wChannelConfig */
  0x00,                      /* 10 iChannelNames */
  0x00,                      /* 10 iTerminal */

  /* Output Terminal descriptor */
  0x09,                      /* 0  bLength */
  0x24,                      /* 1  bDescriptortype, CS_INTERFACE */
  0x03,                      /* 2  OUTPUT_TERMINAL */
  0x02,                      /* 3  bTerminalID */
  0x01, 0x01,                /* 4  wTerminalType (usb streaming) */
  0x00,                      /* 6  bAssocTerminal */
  0x01,                      /* 7  bSourceID */
  0x00,                      /* 8  iTerminal */

  /* Standard AS Interface Descriptor (OFF) */
  0x09,                      /* 0  bLength */
  0x04,                      /* 1  bDescriptortype, INTERFACE */
  0x01,                      /* 2  bInterfaceNumber */
  0x00,                      /* 3  bAnternateSetting */
  0x00,                      /* 4  bNumEndpoints */
  0x01,                      /* 5  bInterfaceClass (AUDIO) */
  0x02,                      /* 6  bInterfaceSubclass (AUDIO_STREAMING) */
  0x00,                      /* 7  bInterface */
  0x00,                      /* 8  bNumEndpoints */

  /* Standard AS Interface Descriptor (ON) */
  0x09,                      /* 0  bLength */
  0x04,                      /* 1  bDescriptortype, INTERFACE */
  0x01,                      /* 2  bInterfaceNumber */
  0x01,                      /* 3  bAnternateSetting */
  0x01,                      /* 4  bNumEndpoints */
  0x01,                      /* 5  bInterfaceClass (AUDIO) */
  0x02,                      /* 6  bInterfaceSubclass (AUDIO_STREAMING) */
  0x00,                      /* 7  bInterface */
  0x00,                      /* 8  bNumEndpoints */

  /* Class-specific AS General Interface */
  0x07,                      /* 0  bLength */
  0x24,                      /* 1  bDescriptorType, CS_INTERFACE */
  0x01,                      /* 2  bDescriptorSubtype, GENERAL */
  0x02,                      /* 3  bTerminalLink */
  0x01,                      /* 4  bDelay */
  0x01, 0x00,                /* 5  wFormatTag */

  /* Type I Format Type */
  0x0B,                      /* 0 bLength */
  0x24,                      /* 1  bDescriptorType, CS_INTERFACE */
  0x02,                      /* 2  bDescriptorSubtype, FORMAT_TYPE */
  0x01,                      /* 3  bFormatType, FORMAT_TYPE_I */
  0x01,                      /* 4  bNbrChannels */
  0x02,                      /* 5  bSubFrameSize */
  0x10,                      /* 6  bBitResolution */
  0x01,                      /* 7  bSamFreqType */
  0x40, 0x1f, 0x00,          /* 8  tSamFreq */

  /* USB Microphone Standard Endpoint Descriptor */
  0x09,                      /* 0  bLength */
  0x05,                      /* 1  bDescriptorType, ENDPOINT */
  0x81,                      /* 2  bEndpointAddress, IN ENDPOINT 1 */
  0x01,                      /* 3  bmAttributes */
  0x10, 0x00,                /* 4  wMaxPacketSize */
  0x01,                      /* 6  bInterval */
  0x00,                      /* 7  bRefresh */
  0x00,                      /* 8  bSynchAddress */

  /* Class-specific Audio Data Endpoint Descriptor */
  0x07,                      /* 0  bLength */
  0x25,                      /* 1  bDescriptorType, CS_ENDPOINT */
  0x01,                      /* 2  bDescriptorSubtype, GENERAL */
  0x00,                      /* 3  bmAttributes */
  0x00,                      /* 4  bLockDelayUnits */
  0x00, 0x00,                /* 5  wLockDelay */
};

unsafe{
  /* String table - unsafe as accessed via shared memory */
  static char * unsafe stringDescriptors[]=
  {
    "\x09\x04",             /* Language ID string (US English) */
    "Test Co",                 /* iManufacturer */
    "Test Audio Board", /* iProduct */
    "0123456789"            /* iSerialNumber */
    "Config",               /* iConfiguration string */
  };
}
Now, I'm extremely new to XMOS, so it is very likely I overlooked something simple in the USB configuration and start-up procedure. If there's something obvious, any help would be appreciated.

Thanks!


henk
Respected Member
Posts: 347
Joined: Wed Jan 27, 2016 5:21 pm

Post by henk »

Hi XCoreXploits,

Two things come to mind

(1) putting print statements in the USB library may break it - or will break it if you print over JTAG.

(2) are you sure that Windows has the right driver? Default windows does not come with a USB Audio driver.

You can try the latter by running a standard USB audio stack.

Cheers,
Henk
XCoreXploits
Junior Member
Posts: 4
Joined: Tue Oct 18, 2016 2:56 am

Post by XCoreXploits »

(1) putting print statements in the USB library may break it - or will break it if you print over JTAG.
I ripped out all the prints, and it still did not work. I thought this would be the case, since it failed before I put the prints in to the codebase. What do you mean "will break it if you print over JTAG?" Will it fail because the two USB devices interact in some weird way? Or will the time to printf over JTAG jam up the usb timing?
(2) are you sure that Windows has the right driver? Default windows does not come with a USB Audio driver.
It's configured to load the USB 1.0 audio stack, which as far as I understand work by default with Windows. However, it is failing before Windows can load the driver, since the system cannot read the descriptor from the device. As far as I know, failing to read the descriptor means Windows does not even know the USB device is an audio device.

Thanks for the ideas.
henk
Respected Member
Posts: 347
Joined: Wed Jan 27, 2016 5:21 pm

Post by henk »

Hi,

Elaborating on printing and USB.

Any JTAG access (including print) when using USB anywhere in the device will break its timing - badly.

Printing over XSCOPE will work from any non USB-thread; from the USB threads you will be able to send small bits of data out in the right places - but too much I/O or I/O in the wrong place can still break timing.

Cheers,
Henk
Post Reply