Moritz Kassner

Hi-Speed USB interfacing

How to talk to the computer very fast. Sometimes the serial link from device to computer is not fast enough. 9600 baud is 1,2kbye/sec (4.32 MB/h). The charm of RS232 is its simplicity, sometimes more badwidth is needed.

Inteface survey

Common wired interfaces:


LAN
100BaseT = 12.5 MByte/sec
Comments: Dedicated controllers as well as Integrated solutions are widely available.

1000baseT = 125 MByte/sec
Comments: Controllers and PHYs for embedded systems are rare.


USB
Low-Speed: 1.25 MByte/sec
Comments: Slow and deprecated

Full-Speed: 12.5 Mbyte/sec
Very wide spread, PHY often integrated in the uC (STM32F4 and many other Cortex M3+ devices), also easy to use: dedicated Uc with parallel interfaces exists (FTDI).

Hi-Speed: 60 MByte/sec
Uc s with USB controllers either in silicon (STM32F4) or software (XMOS) exist.

There is no easy-to use, fast and acceible comunication plattform.

Hi-Speed USB PHY

USB uses low voltage differetial signalling, its own protokoll and communications speed negotiation called chirping. All this his handled by the USB-PHY. This is not a standalone controller. All the USB protokol and communications have to be arranged by the Controller. UPLI is the communication standart between the PHY and Controller. It is a 8 bit data port and 3 line state lines. Singnalling rate is 60mhz. The PHY needs some perephiral electronics to make it work.

Schematics

PHY addon-board

USB communication Protokoll and Set-Up

Unlike RS232 USB comes with a ratstail of protocol and standarts. Bejond the three speed grades, devices need vendor and product ids, device-, configuration- and interface-descriptors and some kind of driver on the host side that knows how to talk to the device. I wrote a driver and took care of all of the above so that most people should be albe to use the binaries I made and appropriate the firmware to their needs. As an example of what Ive been through these here are the usb decriptors that are neccesary for device set-up. No code here yet, just descriptors.

	
	
// This is the Device Descriptor:
static unsigned char hiSpdDesc[] = { 
  0x12,                /* 0  bLength */
  0x01,                /* 1  bdescriptorType */ 
  0x00,                /* 2  bcdUSB */ 
  0x02,                /* 3  bcdUSB */ 
  0x00,                /* 4  bDeviceClass */ 
  0x00,                /* 5  bDeviceSubClass */ 
  0x00,                /* 6  bDeviceProtocol */ 
  0x40,                /* 7  bMaxPacketSize */ 
  0xb1,                /* 8  idVendor */ 
  0x20,                /* 9  idVendor */ 
  0x01,                /* 10 idProduct */ 
  0x01,                /* 11 idProduct */ 
  0x10,                /* 12 bcdDevice */
  0x00,                /* 13 bcdDevice */
  0x01,                /* 14 iManufacturer */
  0x02,                /* 15 iProduct */
  0x00,                /* 16 iSerialNumber */
  0x01                 /* 17 bNumConfigurations */
};

//this is the configuration descriptor
static unsigned char hiSpdConfDesc[] = {
  0x09,                /* 0  bLength */
  0x02,                /* 1  bDescriptortype */
  0x2E, 0x00,          /* 2  wTotalLength */ //num of descriptor bytes (low byte, hi byte)
  0x01,                /* 4  bNumInterfaces */
  0x01,                /* 5  bConfigurationValue */
  0x04,                /* 6  iConfiguration */
  0x80,                /* 7  bmAttributes */
  0xC8,                /* 8  bMaxPower */ //500mw

  0x09,                /* 0  bLength */
  0x04,                /* 1  bDescriptorType */ //Interface Descriptor
  0x00,                /* 2  bInterfacecNumber */
  0x00,                /* 3  bAlternateSetting */
  0x03,                /* 4: bNumEndpoints */
  0x00,                /* 5: bInterfaceClass */ //unknown to inhibit other driver to take over
  0x01,                /* 6: bInterfaceSubClass */ //unknown
  0x02,                /* 7: bInterfaceProtocol*/
  0x00,                /* 8  iInterface */

  0x07,                /* 0  bLength */
  0x05,                /* 1  bDescriptorType */
  0x01,                /* 2  bEndpointAddress */ //01 OUT
  0x02,                /* 3  bmAttributes  */
  0x20,                /* 4  wMaxPacketSize */ //32byte
  0x00,                /* 5  wMaxPacketSize */ //32byte
  0x00,                 /* 6  bInterval ingored for bulk */

  0x07,                /* 0  bLength */
  0x05,                /* 1  bDescriptorType */
  0x81,                /* 2  bEndpointAddress */ //81 IN
  0x02,                /* 3  bmAttributes  */ //bulk
  0x20,                /* 4  wMaxPacketSize */	//32byte
  0x00,                /* 5  wMaxPacketSize */ //32byte
  0x00,                 /* 6  bInterval ingored for bulk */

  0x07,                /* 0  bLength */
  0x05,                /* 1  bDescriptorType */
  0x82,                /* 2  bEndpointAddress */ //82 IN
  0x02,                /* 3  bmAttributes  */ //bulk
  0x00,                /* 4  wMaxPacketSize */
  0x02,                /* 5  wMaxPacketSize */ //512byte
  0x00,                 /* 6  bInterval ingored for bulk */

  0x07,                /* 0  bLength */
  0x05,                /* 1  bDescriptorType */
  0x83,                /* 2  bEndpointAddress */ //83 IN
  0x02,                /* 3  bmAttributes  */ //bulk
  0x00,                /* 4  wMaxPacketSize */
  0x02,                /* 5  wMaxPacketSize */ //512byte
  0x00                 /* 6  bInterval ingored for bulk */
};


unsigned char fullSpdDesc[] =
{
    0x0a,              /* 0  bLength */
    DEVICE_QUALIFIER,  /* 1  bDescriptorType */
    0x00,              /* 2  bcdUSB */
    0x02,              /* 3  bcdUSB */
    0x00,              /* 4  bDeviceClass */
    0x00,              /* 5  bDeviceSubClass */
    0x00,              /* 6  bDeviceProtocol */
    0x40,              /* 7  bMaxPacketSize */
    0x01,              /* 8  bNumConfigurations */
    0x00               /* 9  bReserved  */
};


unsigned char fullSpdConfDesc[] =
{
    0x09,              /* 0  bLength */
    OTHER_SPEED_CONFIGURATION,      /* 1  bDescriptorType */
    0x12,              /* 2  wTotalLength */
    0x00,              /* 3  wTotalLength */
    0x01,              /* 4  bNumInterface: Number of interfaces*/
    0x00,              /* 5  bConfigurationValue */
    0x00,              /* 6  iConfiguration */
    0x80,              /* 7  bmAttributes */
    0xC8,              /* 8  bMaxPower */

    0x09,              /* 0 bLength */
    0x04,              /* 1 bDescriptorType */
    0x00,              /* 2 bInterfaceNumber */
    0x00,              /* 3 bAlternateSetting */
    0x00,              /* 4 bNumEndpoints */
    0x00,              /* 5 bInterfaceClass */
    0x00,              /* 6 bInterfaceSubclass */
    0x00,              /* 7 bInterfaceProtocol */
    0x00,              /* 8 iInterface */

};

static unsigned char stringDescriptors[][40] = {
	"\009\004",                    // Language string
  	"FAB ",				           // iManufacturer
 	"USB to GPIO interface", 	   // iProduct
 	"", 			               // unused
 	"stdC"   			           // iConfiguration
};

	
	

USB priciples

Some things about usb are important to know when using it.
- USB is host-centric
- USB is packetized communication
- Endpoints are used to send data.
This means that a message is never lost (unless you do something terribly wrong). If you want to send information from a device you have to wait until the host gives you time to send it. This means that reads and writes are implemented as blocking functions on XMOS. On the host this depends on your implementation. Data is always send though endpoints, which are like pipes between your device and the software on the Host-computer.

XMOS Firmware

XMOS user group hase a software module that does USB handling. It exposes usefull functions the two most important are:

 
		xud_ep XUD_Init_Ep(chan_ep) //initialize endpoint that is connected to an Xmos channel
		int XUD_SetBuffer(c_ep,BUFFER, SIZE) //supply data that is to be send in a IN transaction
		int XUD_SetBuffer(c_ep,BUFFER, SIZE) //provide buffer that is filled by an OUT transaction
	

LibUSB on the host side

libUSB is a C-library supported in LIN/MAC/WIN. It makes USB communication possible without being a USB engineer. I have created a C program and a python module that calls the c functions using cTypes. 4 functions are used to communicated to the device Endpoints. Data is stored in Numpy arrays which have all we need: They can be set to the right data type, they use coninous storge, they can easyly be passed as pointers.

 
		open(DeviceAddressPointer)
		close(DeviceAddressPointer)
		read(DeviceAddressPointer, numpy_array_pointer,EP)
		write(DeviceAddressPointer, numpy_array_pointer,EP)
	

Benchmarking

Without a benchmark that shows speed there is no need to go though all this hassle if we could just use Serial communication.

The Oscilloscope screenshot shows the state of a output pin that is flashed every time 512byte are send through the USB interface.

36.000 Flashes is 500ms that is equvalent to a datarate of 36,8Mybte/sec. 30.720 times faster than 9600baud rs232.

Resources

SourceCode

Schematics