Introduction

Version 3 of the USB target code has needed a number of detail changes to cope with the addition of a hardware layer for STM32F0x2 devices. The ST USB engine is very different from those of the NXP LPC devices, especially in the interrupt handling.

Version 2 of the USB target code has been refactored, and is not directly compatible with the code in version 1. The major difference is that code dealing with Endpoint 0 has been moved to a separate file which is compiled after the class drivers. Other changes include refactoring of the primary USB interrupt to reduce interrupt overhead, provision for DMA-driven systems (recommended), improved error detection (especially for drives) and additional hardware drivers.

To avoid the need for custom host drivers, several standard USB classes are provided. The most common of these are the Mass Storage Class (MSC) used by memory sticks, and the Communications Device Class (CDC) used by USB serial converters which are often referred to as VCOM (Virtual COM) devices. Examples of both classes are provided.

The USB system presented here is built in four main layers

In addition to these layers, the code contains configuration options in MSCconfig.fth and CDCconfig.fth. You can use these as models for other configurations. A sample composite device is configured in CdcMscConfig.fth, which also contains code for handling USB serial numbers.

The Mass Storage Class depends on the disk interface used by the FATfiler code. The standard example is for an LPC2148 (Olimex P2148 hardware) using the SPI driver in ARM\Drivers\spiLPC2148hard.fth. You can read, write and format the drive from a host PC.

The Communications Device Class provides a Generic I/O device which can be used in the same way as any other device. You can even use it as the Forth console. Under Windows, no driver is required, but a ".inf" file is required. An example for NXP processors is provided in Examples\USB\mpevcom.inf. Note that the examples use a sample VID and PID pair. For distribution of your products, you must obtain a VID (Vendor ID number) from http://www.usb.org.

The code is entirely written in high level Forth for 32 bit systems. The primary tests for hardware and class drivers are performed using Windows 7 and Windows XP, service pack 3. Windows XP Service Pack 3 is required for reliable use of composite devices that rely on Windows XP services.

Setting up for USB development

USB is one of those protocols that doesn't work until almost everything works. You need a protocol analyser. Just as nobody does anything serious with TCP/IP without learning to use Wireshark (was Ethereal), so nobody who is being paid to develop USB systems can do without a USB analyser. We used a Beagle USB 12 from TotalPhase Systems (http://www.totalphase.com) and it was worth every penny.

Every silicon vendor provides sample USB sample code. Don't expect it to be pretty, well commented or bug-free.

There are a number of books about USB device development. The ones we have used are:
USB Design by example, John Hyde,
USB Mass Storage, Jan Axelson.

Jan Axelson has a number of USB books available. Her website is at http://www.lvr.com.

MSC Class driver

Most USB devices are single application. However, most embedded systems use SD or CompactFlash cards for mass storage, and want to use the Mass Storage drive to access the files on the SD card. To do this requires a FAT file system as well as a USB driver. The majority of memory sticks use FAT16 or FAT32 file systems. These are provided by the MPE FATfiler which comes with all Developer editions of MPE Forth cross compilers for 32 bit targets.

Most sample MSC drivers do everything in the interrupt routine, including the drive sector read/write routines. This causes excessive time in the interrupt routine, preventing your real-time task from operating properly. To overcome this, we have split the load into a USB interrupt handler and a task controlled by the interrupt handler. The MSC driver only needs raw sector read/write routines, which must be interlocked, e.g. by a semaphore, with the other task(s) that use the sector interface.

Despite all this, we have seen the USB interrupt routine use 80% of the CPU time at peak USB load on a 60MHz ARM interfacing to a slow (2Mbps) SPI driver for an SD/MMC card. For good real-time performane, tune your card and USB hardware routines. Use DMA hardware wherever possible after you have your hardware running reliably. Because of the number of different hardware systems that we have to support, we at MPE have to consider code portability a high priority.

When using SDHC cards (4Gb and above), note that these will normally be formatted using FAT32, for which the FAT table is huge. Windows appears to read the whole FAT table when a drive is recognised. With USB full-speed devices (12 Mbps), this takes a long time. Start up and format for FAT16 are much quicker. As an example, the FAT size for a 512Mb FAT16 card is 242 sectors with 16 sectors per cluster, whereas for a 4Gb FAT32 card, the FAT size is 7658 sectors with 8 sectors per cluster.

Windows does not require a .INF file for MSC devices.

CDC Class Driver

The Communications Device Class (CDC) can be used for a wide range of devices including modems and Ethernet simulations. The code we supply only supports the ACM subclass, which is the one used for serial port emulations and modems. Only a limited set of control functions are implemented beyond providing a stub. If you need them, expand them to suit your requirements.

There are two USB interfaces, a control interface with an interrupt in endpoint, and a data interface with a bulk in and and bulk out endpoint per COM channel.

The COM channel(s) are implemented as the ends of CQUEUE structures. These queues should be large enough to hold the number of bytes accumulated during a USB poll interval. The poll interval is defined in the endpoint descriptor for the control interface. By default, this is set to 1, indicating a poll interval of 1 ms.

Under Windows, a .INF file is required for any USB device that includes a CDC class driver. The PID and VID (see below) must match those in your USB device descriptors, as must the manufacturer string.

Composite devices

The file CdcMscConfig.fth contains a USB configuration for a composite Communications Device Class (CDC) and Mass Storage Class (MSC) application.

The trick for composite devices is to use an Interface Aggregation Descriptor (IAD) for each instance of any class with more than one interface, e.g. CDC. Read the source code in CdcMscConfig.fth for the gory details!

Running composite devices on Windows without using a custom driver can be problematic. Vista is fine, but XP SP2 is not. For XP, either upgrade to SP3 or install hotfixes. It seems you need

USB Vendor IDs

USB devices are identified by a Vendor ID (VID), Product ID (PID) and a serial number. The primary source of Vendor IDs is http://www.usb.org. If you only need a few, it may be possible to buy a block from a third party, e.g. http://www.voti.nl/shop/catalog.html?USB-PID-10.

According to the USB rules, VIDs are not transferable without written permission. For development, MPE uses VID=0D59 with PID=FFF0..FFFF. It is not our intention to use the PID range FFF8..FFFF.

Compiling the code

Edit the file xxxConfig.fth as required. The default is for a Mass Storage Class driver. Depending on the hardware and its driver, you may have to force DMA buffers into a particular memory range. The MSC class driver requires sector read and write routines and the FAT filing system.

  include %UsbDir%\UsbDefs         \ USB definitions/equates
  include %UsbDir%\MscConfig       \ configuration file
\  include %UsbDir%\CDCconfig      \ USB configuration file
\  include %UsbDir%\CdcMscConfig   \ USB configuration file
  include %UsbDir%\UsbHwLPC2xxx    \ USB hardware layer for LPC2xxx
  include %UsbDir%\UsbBase         \ USB base operations
CDC? [if]
  include %UsbDir%\CdcDrv          \ Communications Device Class
[then]
MSC? [if]
  include %UsbDir%\MscDrv          \ Mass Storage Class
[then]
  include %UsbDir%\UsbEp0          \ USB Endpoint 0 layer

After compiling and flashing the code, power up the target, and type:

 startUSBsys

to start the USB and mass storage system. You should then be able to transfer files from the PC to the target. To see them, return to the Forth target prompt and type:

  dir

which will provide a simple directory listing.

Testing with operating systems

The code here has been tested with Windows 7 and 10, Mac macOS 10.13 High Sierra, Debian Linux v16.04 for x86_64 Linux and Raspbian Jessie for ARM Linux.

Windows takes a lowest common denominator approach to the standard USB classes in order to operate with the largest number of devices. It is probably easiest to get a device working under Windows than any other operating system. However, getting something working under Windows is no guarantee that your device is standards-compliant or that it will work with other operating systems.

Linux expects that what is provided operates to specification and will reject non-compliant devices. However, it is reasonably tolerant of missing features.

Mac OS X is really fussy and makes few concessions. However, there are good USB analysis programs to help debugging. Composite devices can be difficult to write descriptors for. IAD support was only introduced in OS X 10.5.6. At least one of our clients detects an OS X host (first setup packet has wLength=8) and presents different USB descriptors for OS X. Note that recent Macs may no longer support Full Speed devices (the majority of embedded devices) and that a USB 2.0 hub is required. If you are powering the device from the hub, a powered hub is recommended.