I'm trying to run the USB example described in AN00136 using the XP-SKC-U16 development board. At this point, I have been able to compile and run the example on the device. However, the device does not enumerate properly and Windows7 generates a "Device Descriptor Request Failed" error. To verify that the hardware is functional, I have used the version1.0 USB libraries and XMOS provided .cpp testbench to provide hardware verification.
I have also reviewed and compared the original and new USB libraries and can't spot anything wrong with the device descriptors or the configuration files. So far, I have been operating under the assumption that the host drivers are only loaded after successful enumeration of the device since Windows must have basic information available to know what driver is appropriate for the device.
Perhaps there is an issue with the high speed vs full speed descriptors used by the new xud() method? Is it also possible that the new lib_logging(2.0.1) lib_xassert(2.0.1) and lib_gpio have now violated the timing requirements specified by USB 2.0 standard?
Has anyone else had similar issues with the new library or have debugging suggestions? For completeness, I've posted the code that I have put onto the device. Keep in mind that the main.xc and endpoint.xc files have been combined in the code viewer below.
Regards,
Kyle
Code: Select all
// Copyright (c) 2016, XMOS Ltd, All rights reserved
#include "usb.h"
#include <platform.h>
#define XUD_EP_COUNT_OUT 2
#define XUD_EP_COUNT_IN 2
/* Prototype for Endpoint0 function in endpoint0.xc */
void Endpoint0(chanend c_ep0_out, chanend c_ep0_in);
#define BCD_DEVICE 0x1000
#define VENDOR_ID 0x20B1
#define PRODUCT_ID 0x00B1
#define MANUFACTURER_STR_INDEX 0x0001
#define PRODUCT_STR_INDEX 0x0002
/* Vendor specific class defines */
#define VENDOR_SPECIFIC_CLASS 0xFF
#define VENDOR_SPECIFIC_SUBCLASS 0xFF
#define VENDOR_SPECIFIC_PROTOCOL 0xFF
/* Device Descriptor */
static unsigned char devDesc[] =
{
0x12, /* 0 bLength */
USB_DESCTYPE_DEVICE, /* 1 bdescriptorType */
0x00, /* 2 bcdUSB */
0x02, /* 3 bcdUSB */
VENDOR_SPECIFIC_CLASS, /* 4 bDeviceClass */
VENDOR_SPECIFIC_SUBCLASS, /* 5 bDeviceSubClass */
VENDOR_SPECIFIC_PROTOCOL, /* 6 bDeviceProtocol */
0x40, /* 7 bMaxPacketSize */
(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 */
MANUFACTURER_STR_INDEX, /* 14 iManufacturer */
PRODUCT_STR_INDEX, /* 15 iProduct */
0x00, /* 16 iSerialNumber */
0x01 /* 17 bNumConfigurations */
};
/* Configuration Descriptor */
static unsigned char cfgDesc[] =
{
0x09, /* 0 bLength */
0x02, /* 1 bDescriptortype */
0x20, 0x00, /* 2 wTotalLength */
0x01, /* 4 bNumInterfaces */
0x01, /* 5 bConfigurationValue */
0x00, /* 6 iConfiguration */
0x80, /* 7 bmAttributes */
0xFA, /* 8 bMaxPower */
0x09, /* 0 bLength */
0x04, /* 1 bDescriptorType */
0x00, /* 2 bInterfacecNumber */
0x00, /* 3 bAlternateSetting */
0x02, /* 4: bNumEndpoints */
0xFF, /* 5: bInterfaceClass */
0xFF, /* 6: bInterfaceSubClass */
0xFF, /* 7: bInterfaceProtocol*/
0x03, /* 8 iInterface */
0x07, /* 0 bLength */
0x05, /* 1 bDescriptorType */
0x01, /* 2 bEndpointAddress */
0x02, /* 3 bmAttributes */
0x00, /* 4 wMaxPacketSize */
0x02, /* 5 wMaxPacketSize */
0x01, /* 6 bInterval */
0x07, /* 0 bLength */
0x05, /* 1 bDescriptorType */
0x81, /* 2 bEndpointAddress */
0x02, /* 3 bmAttributes */
0x00, /* 4 wMaxPacketSize */
0x02, /* 5 wMaxPacketSize */
0x01 /* 6 bInterval */
};
/* Set language string to US English */
#define STR_USENG 0x0409
/* String table */
unsafe
{
static char * unsafe stringDescriptors[] =
{
"\x09\x04", // Language ID string (US English)
"XMOS", // iManufacturer
"XMOS Custom Bulk Transfer Device", // iProduct
"Custom Interface", // iInterface
"Config" // iConfiguration
};
}
/* Endpoint 0 Task */
void Endpoint0(chanend chan_ep0_out, chanend chan_ep0_in)
{
USB_SetupPacket_t sp;
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);
while(1)
{
/* Returns XUD_RES_OKAY on success */
XUD_Result_t result = USB_GetSetupPacket(ep0_out, ep0_in, sp);
if(result == XUD_RES_OKAY)
{
/* Returns XUD_RES_OKAY if handled okay,
* XUD_RES_ERR if request was not handled (i.e. STALLed),
* XUD_RES_RST if USB Reset */
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);
}
/* USB bus reset detected, reset EP and get new bus speed */
if(result == XUD_RES_RST)
{
usbBusSpeed = XUD_ResetEndpoint(ep0_out, ep0_in);
}
}
}
#define BUFFER_SIZE 128
/* A basic endpoint function that receives 512-byte packets of data, processes
* them and sends them back to the host. If at any point an error is detected
* (return value < 0) then the process needs to be started again so that
* both host and device stay in sync.
*/
void bulk_endpoint(chanend chan_ep_from_host, chanend chan_ep_to_host)
{
int host_transfer_buf[BUFFER_SIZE];
unsigned host_transfer_length = 0;
XUD_Result_t result;
XUD_ep ep_from_host = XUD_InitEp(chan_ep_from_host, XUD_EPTYPE_BUL | XUD_STATUS_ENABLE);
XUD_ep ep_to_host = XUD_InitEp(chan_ep_to_host, XUD_EPTYPE_BUL | XUD_STATUS_ENABLE);
while(1)
{
/* Receive a buffer (512-bytes) of data from the host */
if((result = XUD_GetBuffer(ep_from_host, (host_transfer_buf, char[BUFFER_SIZE * 4]), host_transfer_length)) == XUD_RES_RST)
{
XUD_ResetEndpoint(ep_from_host, ep_to_host);
continue;
}
/* Perform basic processing (increment data) */
for (int i = 0; i < host_transfer_length/4; i++)
host_transfer_buf[i]++;
/* Send the modified buffer back to the host */
if((result = XUD_SetBuffer(ep_to_host, (host_transfer_buf, char[BUFFER_SIZE * 4]), host_transfer_length)) == XUD_RES_RST)
{
XUD_ResetEndpoint(ep_from_host, ep_to_host);
}
}
}
/* The main function runs three tasks: the XUD manager, Endpoint 0, and bulk
* endpoint. An array of channels is used for both IN and OUT endpoints,
* endpoint zero requires both, bulk endpoint requires an IN and an OUT endpoint
* to receive and send a data buffer to the host.
*/
int main()
{
chan c_ep_out[XUD_EP_COUNT_OUT], c_ep_in[XUD_EP_COUNT_IN];
par
{
on USB_TILE: xud(c_ep_out, XUD_EP_COUNT_OUT, c_ep_in, XUD_EP_COUNT_IN, null, XUD_SPEED_HS, XUD_PWR_BUS);
on USB_TILE: Endpoint0(c_ep_out[0], c_ep_in[0]);
on USB_TILE: bulk_endpoint(c_ep_out[1], c_ep_in[1]);
}
return 0;
}