USBTMC Device Firmware Design (Example)

Author: Michael J. Bauer, 2007


1. USB Test and Measurement Class Specification (USBTMC), Rev 1.0 (2003),
2. USB Test and Measurement Class, Sub-class USB488 Specification (USB488), Rev 1.0 (2003)
3. IEEE Standard Digital Interface for Programmable Instrumentation, IEEE Std 488.1-1987,
4. IEEE Standard Codes, Formats, Protocols and Common Commands, IEEE Std 488.2-1992,
5. Virtual Instrument System Architecture (VISA) Specification,
6. Universal Serial Bus Specification, Rev 2.0 (April 2000),


This document describes the firmware realisation of a USB 'Test and Measurement Class' device, based on an Atmel ARM7 microcontroller (AT91SAM7Sxxx) with on-chip USB peripheral controller. The firmware architecture may serve to provide a framework upon which to develop new USBTMC device applications for this or other hardware platforms. For this purpose, a number of objectives were identified...


A further objective was to confine USB hardware platform dependencies to a separate low-level module, i.e. "hardware abstraction layer" (usbhal), to facilitate porting the USBTMC "stack" to other platforms.

Device Hardware Platform

The example USBTMC device firmware was developed and tested on an Atmel AT91SAM7S-EK evaluation board.

The example application uses four LED annunciators and a push-button switch as follows:
SW1 (PA19) : Button hits (falling edges on this input) are counted by the application.
LED1 (PA0) : "USB Status" -- Lit when a USB link is established; blinks during bus activity; off otherwise.
LED2 (PA1) : "Remote" -- Lit while the device is in Remote Control mode; off in Local mode.
LED3 (PA2) : "Ready" -- Responds to USBTMC command message and "Indicator Pulse" class request.
LED4 (PA3) : "Heartbeat" -- Flashes at 1Hz while the program is running normally.

Other PIO pins used by the application are:
PA13 = VBUS_DET input : High state signals VBUS voltage present at the USB socket
PA16 = USB_DP_PUP output : Low state connects a 1.5k pullup from D+ to Vcc (Attach/Detach control).

Note: PIO pin PA13 may be configured for use as the SPI 'MOSI' output signal. If your application requires the SPI bus, VBUS_DET must be disconnected from PA13 (open jumper JP2). The firmware can be easily modified to ignore VBUS_DET, or to use another PIO pin for this purpose. If the board is bus-powered, VBUS_DET is irrelevant, because it is always High while the board is powered up! If the board is "self-powered", however, the firmware application should respond appropriately when VBUS is applied or removed. (See function "check_usb_connection".)

Device Functional Specification

The device maintains a counter which accumulates the number of pulses (active transitions) detected on a digital input. The input signal is filtered, using a software algorithm, to remove "glitches", i.e. short transitions of less than 30ms duration, as would be appropriate for "de-bouncing" a contact-closure input (switch or relay). The maximum count value is 30,000. The counter value can be read or reset by means of USBTMC commands.

The device communicates with a host controller (PC) using the USBTMC/USB488 message protocol. All command and response messages are formatted in ASCII printable characters, except for the termination character (newline = 0x0A). Command messages conform to the IEEE488.2 format, more or less.

Command Set

The following IEEE488.2/SCPI common commands and queries are provided:

*IDN? The device responds with the IDN string:
"XYZ Company Ltd, SAM7-EK, 0, v#.#.###\n"
where # is a decimal digit comprising the firmware version number.
*RST The device "function layer" is reset. (IEEE is ambiguous about this command.)
*CLS The IEEE status reporting mechanism is cleared (event register bits reset).
*STB? The device reponds with the STB register value, in IEEE hexadecimal format (#Hxx).
*ESR? The device reponds with the ESR register value, in IEEE hexadecimal format (#Hxx).
*ESE bb The ESE register is set to the value given, which may be in decimal or hex format.

The following device-specific commands and queries are provided:

COUNT:READ? The device responds with the accumulated pulse count, in decimal integer format (ASCII string).
COUNT:RESET The pulse counter is reset to zero; the overflow error flag is cleared.
INDICATOR <n> The 'Ready' indicator LED is turned on (n=1) or off (n=0). Note: The 'Ready' LED state is also affected by the USB488 'Indicator Pulse' class request.
INDICATOR? The device responds with the state of the 'Ready' indicator, "ON" or "OFF".
PARAM:SET <n1>,<n2> Two "dummy configuration parameters" are set to the values given. The param's are represented by decimal integers in the range -10000 to +10000.
(The config. param's serve no purpose other than to demonstrate how to parse numeric arguments in an IEEE488.2 command message.)
PARAM:ENQ? The device responds with the values of the two "dummy configuration parameters", in decimal integer format.
BUSY? The device responds with the 'BUSY' status, "YES" or "NO".
DEBUG:FLAGS? The device responds with the USBTMC comm's debug flags, represented as a 32-bit word in IEEE hex format (#Hxxxxxxxx).

Message buffers

Separate buffers are allocated in RAM for command and response messages. Sizes of the command and response message buffers are settable by means of compiler directives to suit the application. (See Build Options in "system.h")
As the host is required to wait for a query response before sending a subsequent command or query, it would be possible to use a single memory buffer for both command and response messages. Allocating two separate buffers makes debugging easier, but is not as memory efficient as a single buffer.

Command and Query Errors

A message will be rejected if the command/query mnemonic is undefined, or if the wrong number of parameters is supplied. These errors are classed as "command errors" (CME). In the case of a query message, either of these errors will result in no response being generated, and if the host requests a response, a VISA time-out or protocol error will result.

A "query error" (QYE) will be flagged if the host requests a response without having first sent a query message, or if the host sends a new command following a query without first requesting a response to the query.

Message Protocol and Execution Errors

If the device receives a command message with a parameter value out of range, or having the wrong data type, the command will have no effect, and an "execution error" (EXE) will be flagged.

If the received message buffer overflows, the command will have no effect, and a "device-dependent error" (DDE) will be flagged.

The host should examine the device error status, i.e. read the STB register, after each command/query message is sent, to avoid loss of message synchronization between host and device.

LED annunciators (driven by the MCU)

LED1: "USB Status" Lit while the device is "configured" (as defined by the USB2.0 spec.), i.e. upon successful enumeration by the host PC;
Off when in the "bus reset" state;
Pulsing off and on at 10~20Hz (50~100ms) while there is bus activity, i.e. while packets are being received on the Control-Out or Bulk-Out endpoints.
LED2: "Remote" Lit while the device is in a Remote state (REMS, RWLS); otherwise off.
LED3: "Ready" Turned on or off, or pulsed momentarily, under control of the host PC.
Responds to "INDICATOR" command and USB488 "Indicator Pulse" class request.
LED4: "Heartbeat" Flashes at 1Hz to indicate "device is running properly", i.e. main kernel loop is executing and periodic timer interrupt is being serviced.

USB488 "Indicator Pulse" Class Request

On receiving a USB488 "Indicator Pulse" Class Request, the device toggles (inverts) the state of the 'READY' indicator LED and starts a 500ms timer. When the timer expires, the state of the 'READY' indicator is toggled again.

Device Status Reporting -- IEEE Status Register Model

Bit: 7 6 5 4 3 2 1 0
Status Byte (STB): OPR MSS ESB MAV X X X X
Event Status Enable reg (ESE):                

Status register bit definitions:

STB.OPR = Operation Status Register summary bit (not used in this example)
STB.MSS = Master Status Summary bit (logical OR of STB bits, except bit 6 itself)
STB.ESB = Event Status (ESR) summary Bit (logical OR of ESR bits, where corresp. ESE bit is set)
STB.MAV = Message Available (i.e. a query response is ready for transmission)

ESR.PON = Power ON (set by device power-on event)
ESR.URQ = User Request (not used in this example)
ESR.CME = Command Error (undefined mnemonic, bad syntax, or wrong number of param's)
ESR.EXE = Execution Error (command parameter is out of bounds, or wrong data type)
ESR.DDE = Device-Dependent Event (register) summary bit, or Device-Dependent Error
ESR.QYE = Query Error (e.g. the host requested a response without first sending a query message)
ESR.RTL = Returned-To-Local state (applies to RL1 capable devices only)
ESR.OPC = Operation Completed (not used in this example)

Notes on the IEEE status system

ESR bit 1 is defined as 'RQC' (Request Control) in the IEEE488 (GPIB) standard. Since a USBTMC device cannot be a host controller, it cannot "request control", so this bit may be redefined for another purpose. In this case, 'RTL' signals that the device has gone from a Remote state to a Local state, since the previous reading of ESR. In a "real world" application, a device may be switched from Remote to Local by a front-panel operation, or perhaps on occurrence of a critical error. The 'RTL' flag indicates to the host controller that such an event has occurred.

The 'Event status Summary Bit' (STB.ESB) signals that one or more bits in the Event Status Register (ESR) are set, but only where corresponding bits in the Event Status Enable (ESE) register are set. Reading the Event Status Register (via the *ESR? query) also clears it, after the value has been transmitted.

In this simple example, there is no 'Device Status Register' (DSR), so the ESR.DDE bit has been allocated to signal 'Device-Dependent Error'. In this example device, DDE signals a "command buffer overflow" error.

Firmware Implementation

The example firmware is comprised of 7 code modules: main, cli, usbtmc, usbreq, usbhal, periph and lowlevel. As this is a small example, the kernel routine, background "task" functions, command parser/interpreter and device-specific command functions have been lumped together in the 'main' module. In a real-life application, some or all of these functions may well be placed into separate modules.

The two higher-level modules of the USBTMC stack, 'usbtmc' and 'usbreq', are designed to be portable across various device applications and hardware platforms, requiring minimal customization, except for device descriptor, configuration and capability 'descriptors'.

The lowest level module of the USBTMC stack, 'usbhal', will require customization to suit a different USB peripheral controller. However, the USB "command interface" is designed as a generic set of functions, adaptable to a variety of USB hardware platforms. Two other modules, "lowlevel" and "periph", contain processor-specific and peripheral hardware-specific code (resp.).

A command-line user interface module (cli) is included for testing and debugging purposes. The CLI uses the SAM7 'DBGU' (Debug Port) for its I/O stream. The DBGU is configured for 38400 baud, N, 8, 1. The firmware also uses the DBGU port for "trace" output to assist debugging. Both the CLI and trace facilities are build options which may be omitted.

Annotation in the source code files should be read in conjuction with this document.

Host-side Application Software

The host controller requires application software compliant with the VISA specification. A VISA API library is available from National Instrument and Agilent Technologies. (These are free downloads -- refer to company websites.) The VISA API incorporates USBTMC host driver software. The driver adapts itself automatically to support each unique TMC device connected. Hence, it is not necessary to develop host-side USBTMC device driver software or driver information (*.inf) files.

Both the NI and Agilent VISA packages come with an interactive test utility which may be used to verify that a device is communicating correctly with the host controller.

VISA API libraries are provided in the form of linkable object code files. Libraries are available for Windows and Linux. For a Windows host, application software may be developed in Visual Basic or Visual C/C++. NI 'LabView' is another software application which supports USBTMC devices. National Instrument's VISA implementation supports a variety of instrument communication interfaces in addition to USB, i.e. GPIB (IEEE488), Serial, PXI, etc. Agilent Technologies' VISA implementation is lighter than NI VISA.