Jan Axelson's Lakeview Research

LVR.COM is moving to JANAXELSON.COM

JANAXELSON.COM is live now. (Try it!).
Please update your bookmarks and links.
After June 1, 2014, this site will be available ONLY at janaxelson.com and links to content at lvr.com will no longer work.

Home > USB Central > USB Developer's FAQ

USB Developers FAQ

Also see:

HID FAQ | Mass Storage FAQ | USB 3.0 Developers FAQ

Basics

How can I read or write to a USB port on a PC?

Applications don't access ports; they can only access a specific device attached to a port.

A USB port is very different from a PC's parallel or serial port. Each parallel and serial port has a series of port addresses that are unique to that port. With an appropriate driver, an application can read and write to these port addresses.

A USB port is a port on a shared bus. The ports do not have unique port addresses as parallel and serial ports do. Traffic sent to a single device may appear at multiple ports. When a device attaches to a USB port, the operating system requests information from the device and assigns a bus address and a class driver or device driver that applications can use to communicate with the device. Lower-level drivers provided by the operating system manage the details of communicating on the bus.

How do I access USB devices from Windows applications?

How an application communicates with a USB device depends on the device driver that Windows has assigned to the device. The choice of driver in turn depends on finding a match between the information in the descriptors that Windows retrieves on device attachment or bootup and the information stored in the PC's INF files. Typically, the application doesn't have to know whether the device uses USB or another interface. For example, applications access files on a drive in the same way whether the drive uses USB, IEEE-1394, SCSI, ATAPI, or another interface. The interface-specific details are handled at a lower level. Some devices use drivers included with Windows. Others use a vendor-specific driver that he user must install.

What device driver should my device use?

The easiest approach is to use a driver supported by the operating systems of the computers your device will attach to. To do so, your device must fit the requirements and limitations of the driver. For vendor-specific device types that exchange data at low to moderate rates, one option is the HID class, which supports control and interrupt transfers. For transferring large amounts of data where speed isn't essential, use bulk transfers, possibly using mass-storage-class drivers or a vendor-specific driver.

How can I connect two PCs via USB?

Every USB communication is between a host and a device. The USB support included in every PC is for a USB host. To connect two PCs via USB, you can do any of the following:

1. Use a USB bridge cable such as the EZ-Link. The bridge contain two USB devices with a shared buffer. Each device connects to a different PC. On receiving data from a host, a device writes the data to the shared buffer, and the other device sends the data to its host. Bridges typically use a network driver and appear as a network connection between the PCs.

2. Connect a USB/RS-232 adapter to each PC and connect the RS-232 ports in a null-modem connection. Use COM-port functions to communicate.

3. Install a device card in one PC. An example is PLX Technology's (formerly Netchip) NET2283RDK Adapter Card. The PC provides the driver software for the device.

4. Some Windows CE PCs can function as either a host or device.

How can I connect my USB drive, printer, keyboard, mouse, or other USB device to my microcontroller circuit?

Every USB communication is between a host and a device. Almost all microcontrollers with USB capability are devices. Peripherals are also devices. To access a USB peripheral, the microcontroller circuit must contain an embedded host controller.

USB Versions

Must all USB 2.0 devices be high speed?

No, a 2.0 device can be low, full, or high speed.

How can I make a USB 1.x device USB 2.0-compliant?

In the device descriptor, set bcdUSB to 0200h. The default interface must request no isochronous bandwidth. A USB 2.0-compliant low-speed cable must have the same inner shield and drain wire required for full and high speed cables.

What is the difference between USB 1.0 and USB 1.1?

A major difference is that USB 1.1 adds interrupt OUT transfers.

How can I tell what speed a device is using?

Normally applications have no need to know device speed. However, there are some indicators. If a bulk endpoint's wMaxPacketSize is 512, the device is using high speed. Otherwise, it's full speed. If an interrupt endpoint has a wMaxPacketSize greater than 64, it's high speed. If the value is between 9 and 64, it may be full or high speed. If the value is 8 or less, it may be any speed. If an isochronous endpoint has a wMaxPacketSize of 1024, it's high speed. Otherwise, it may be full or high speed. If a device has a bulk or isochronous endpoint, it's not low speed. A configuration string may also contain speed information.

Why isn't the host polling my device's high-speed interrupt endpoint at the correct rate?

For low- and full-speed interrupt endpoints, the descriptor's bInterval value indicates the requested maximum number of milliseconds between transaction attempts.

For high-speed interrupt endpoints, the interval is calculated differently. According to the USB 2.0 specification, bInterval must be between 1 and 16, the interval is in units of 125 microseconds, and the interval's value equals 2^(bInterval-1) (with ^ indicating the exponent operator). In other words, if bInterval = 4, the interval is 2^(4-1), or 2^3, or eight 125-microsecond periods, which means that the device is requesting a minimum of one poll per millisecond.

Reports are that some device providers are using full-speed bInterval values in high-speed descriptors. Reports also say that under Windows, a device may receive its intended polling rate (rather than its requested polling rate) in spite of this error. Other operating systems are likely to attempt to provide the requested polling rate, or may report an illegal bInterval value.

Device Classes

Where can I find the specifications for USB device classes?

USB-IF Device Class Documents

Which device classes does Windows support?

USB Drivers Included with Windows.

What driver should I use for a a virtual COM port (to access the device the same as an RS-232 serial device)?

One option is to use Windows' Communications driver. The firmware should define the device as CDC/ACM (Communications Device Class/Abstract Control Model). The device uses endpoint zero and bulk IN and bulk OUT endpoints. In the INF file, set Class=Ports. For Windows 2000 and Windows XP, describe the hardware driver (usbser.sys) as a functional driver, not as a lower filter driver. For Windows 98 and Windows Me, declare "usbser.sys,ccport.sys" as the device drivers.

Reports are that the Windows driver is slow (640Kbit/sec) and the WM_DEVICECHANGE notifications don't work properly on Windows 2000. More information.

For better performance, use a dedicated-function controller whose vendor provides a virtual COM port driver.

Power

Must a self-powered device have a connection to the VBUS line in the cable?

Yes. The device must switch in the pull up on D- or D+ only when VBUS is present. See section 7.2.1 in the USB 2.0 specification.

Hosts

Why does my device work with UHCI hosts but not OHCI hosts?

OHCI hosts may do multiple stages of a control transfer in a single frame, while UCHI hosts do each stage in a different frame. Every USB device should function under both host types.

Why doesn't my high-speed, high-bandwidth device transfer data at the requested rate?

Windows XP's EHCI driver doesn't support high-bandwidth interrupt transfers (transfers with more than one packet per microframe). Windows does support high-bandwidth isochronous transfers.

Devices on the Bus

How can my application detect when my device is attached or removed?

To find out when a device has been attached or removed, catch the WM_DEVICECHANGE messege with the parameter DBT_DEVNODES_CHANGED. Then use SetupDi_ functions to find out what device was attached or removed. A Usenet post on the subject is USB Device Insertion/Removal Event Notification. Also see my example code.

How can my application reset, disable, or restart a USB device?

The DevCon example in the WDK is a command-line utility that shows how to enable, disable, restart, update, remove and query devices using the SetupAPI and CfgMgr32 API functions.

How can I determine which port my device is attached to?

Under Windows, every device has a unique driver key, also called the software key. You can obtain the key from a device using SetupDi functions, and obtain the same key from a hub port using undocumented DeviceIoControl codes. When you have a match, you know which port the device is attached to.

To retrieve the driver key name for a device, call SetupDiGetClassDevs and SetupDiEnumDeviceInfo, then use SetupDiGetDeviceRegistryPropertyA with Property set to SPDRP_DRIVER.

To retrieve the driver key name for a hub port, first find the hubs with SetupDi_ functions and GUID_DEVINTERFACE_USB_HUB.

Obtain a handle to a hub with CreateFile.

Get the number of ports on the hub with IOCTL_USB_GET_NODE_INFORMATION (undocumented IO control code in usbioctl.h).

Find out if a device is attached to a port with IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX.

For each attached device, get the driver key name with IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME (undocumented IO control code in usbioctl.h).

I have two or more identical devices attached to a host. How can I tell which is which?

Store a serial number in the device descriptor or use another vendor-specific identifier. For HID-class devices, applications can read the serial number with the HidD_GetSerialNumberString function.

I've made changes to my device's firmware but Windows doesn't seem to recognize the changes.

With the device attached, remove the device in Windows Device Manager. Then detach and reattach the device.

Is there a limit to the maximum size of a transfer?

See Maximum size of USB transfers on various operating systems (Microsoft Knowledge Base Article 832430).

These values are the maximum amount of data a WDM driver can request to send or receive in a single USB Request Block (URB). An application may request to send or receive more or less than this amount. The driver can handle larger amounts by using multiple URBs. A specific device may have stricter limits on transfer size.

During device testing, we attach many devices that are identical except for the serial numbers. How can I prevent Windows from asking to install a new driver every time a device is attached?

The method described below causes Windows 2000 and XP to ignore a device's serial number. It's recommended for test environments only.

This registry key controls whether Windows uses or ignores device serial numbers:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\UsbFlags]

It's possible to ignore all serial numbers, though this approach is NOT recommended. To ignore all serial numbers, in the above key, change this value to zero:

GlobalDisableSerNumGen = 1

To ignore the serial number for an individual device, create an entry under the above ...\UsbFlags key. The name must start with "IgnoreHWSerNum" followed by the vendor and product ID of the device. A value of 1 = "disable the serial number."

Example (Vendor ID = 0925h, Product ID = 016Ah):

IgnoreHWSerNum0925016A= 1

(Thanks to Dieter Fauth for this answer.)

How is the USB data CRC value calculated?

Here are two examples.

Example 1 from Ron Hemphill.

Example 2 from Barry Twycross:

This is not suitable for use as production code; it is very inefficient:

UInt16 CRC16(void *buffer, UInt32 count) 
{ 
    UInt8 *bp; 
    UInt32 poly, a, b, newBit, lostBit; int i; 
    poly = 0x8005; 
    a = 0xffff; 
    bp = buffer; 
    while(count--) 
    { 
        b = *(bp++); 
        for(i = 0; i<8; i++) 
        { 
            a <<= 1; 
            newBit = (b & 1); 
            b >>= 1; 
            lostBit = a >> 16; 
            if(newBit != lostBit) 
            { 
                    a ^= poly; 
            } 
            a &= 0xffff; 
        } 
    } 
return(a^0xffff); 

}

Partner Links

***