Lakeview Research home > USB Central > USB Developer's FAQ
USB Developers FAQ
Frequently asked questions relating to designing hardware and writing program code for devices that communicate on the Universal Serial Bus (USB)
by Jan Axelson
This FAQ contains questions frequently asked on the USB Developers Forum and other questions I've received by e-mail. This FAQ is a supplement to the information in my USB pages. Suggestions and contributions welcome via
For more questions and answers, see my HID FAQ and Mass Storage 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 typically appears 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. This 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. This assumes that your device can fit the requirements and limitations of one of these drivers. 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. (High-speed HIDs support fast transfer rates.) For transferring large amounts of data where speed isn't essential, you'll probably want to 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. Buy an EZ-Link or similar USB bridge device. These devices contain two USB devices. Each device connects to a different PC. Data sent to one device is passed to the other device, which sends it on to the other PC. The connection typically appears like 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) NET2280EVB Adapter Card. The PC provides the driver software for the device.
4. Control a USB device from a parallel port on one PC using the DevaSys USBLPT-PD11.
5. Some Windows CE PCs can function as a host or device.
How can I connect my USB drive, Flash-memory card, printer, keyboard, mouse, or other USB peripheral 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. These are possible solutions:
1. Add an embedded host controller to your microcontroller circuit.
2. Use a peripheral with USB On-The-Go capability. The peripheral can then function as both a device and a host.
3. Use a Delkin USB Bridge or similar product to transfer files between devices.
4. Connect your microcontroller and the peripheral to a PC or other general USB host.
USB Versions
Must USB 2.0 devices be high speed?
No, a 2.0 device can be low, full, or high speed.
How can I make a 1.x device 2.0-compliant?
In the device descriptor, set bcdUSB to 0200h. The default interface must request no isochronous bandwidth. A 2.0-compliant low-speed cable must have the same inner shield and drain wire required for full and high speed cables.
USB 1.1 adds interrupt OUT transfers. Also see this document from Mindshare: Changes from USB Revision 1.0 to USB Revision 1.1.
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 MaxPacketSize is 512, the device is using high speed. Otherwise, it's full speed. If an interrupt endpoint has a MaxPacketSize greater than 64, it's high speed. If it's between 9 and 64, it may be full or high speed. If it's 8 or less, it may be any speed. If an isochronous endpoint has a MaxPacketSize 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 transactions.
For high-speed interrupt endpoints, the interval is calculated differently. According to the USB 2.0 spec, 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 many device manufacturers 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?
Which device classes does Windows support?
See 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 0 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 info.
For better performance, use a controller whose vendor provides a virtual COM port driver, such as FTDI or take a look at MCCI's USB Serial Drivers.
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. From 7.2.1 in the USB spec:
No device shall supply (source) current on VBUS at its upstream
facing port at any time. From VBUS on its
upstream facing port, a device may only draw (sink) current. They may
not provide power to the pull-up resistor
on D+/D- unless VBUS is present (see Section 7.1.5). When VBUS is removed,
the device must remove power
from the D+/D- pull-up resistor within 10 seconds.
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.
Can I use a Pocket PC as a USB host?
Toshiba (and probably others) make Pocket PCs with host capability:
http://www.pocketpccentral.net/toshiba405.htm
Other Pocket PCs can become hosts with the addition of a host CF card:
http://www.ratocsystems.com/english/products/subpages/cfu1u.html
Also see Microsoft's Windows CE .NET documentation for info about USB programming.
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 good Usenet post on the subject: 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 Windows DDK 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 software key, or driver key. You can obtain the driver 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.
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 should handle larger amounts by using multiple URBs. A 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?
This method 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);
