Introduction

The USB device protocol stack provides an API which makes it possible to create USB devices with a minimum of effort. The device stack supports control, bulk, interrupt and isochronous transfers.

The stack is highly configurable to suit various needs, it does also contain useful debugging features together with several demonstration projects to get you started fast.

We recommend that you read through this documentation, then proceed to build and test a few example projects before you start designing your own device.

The device stack API

This section contains brief descriptions of the functions in the API. You will find detailed information on input and output parameters and return values by clicking on the hyperlinked function names. It is also a good idea to study the code in the USB demonstration projects.

Your application code must include one header file: em_usb.h.

All functions defined in the API can be called from within interrupt handlers.

The USB stack use a hardware timer to keep track of time. TIMER0 is the default choice, refer to Configuring the device stack for other possibilities. Your application must not use the selected timer.

Pitfalls:
The USB peripheral will fill your receive buffers in quantities of WORD's (4 bytes). Transmit and receive buffers must be WORD aligned, in addition when allocating storage for receive buffers, round size up to next WORD boundary. If it is possible that the host will send more data than your device expects, round buffer size up to the next multiple of maxpacket size for the relevant endpoint to avoid data corruption.

Transmit buffers passed to USBD_Write() must be statically allocated because USBD_Write() only initiates the transfer. When the host decide to actually perform the transfer, your data must be available.

USBD_Init()
This function is called to register your device and all its properties with the device stack. The application must fill in a USBD_Init_TypeDef structure prior to calling. Refer to DeviceInitCallbacks for the optional callback functions defined within this structure. When this function has been called your device is ready to be enumerated by the USB host.

USBD_Read(), USBD_Write()
These functions initiate data transfers.
USBD_Read() initiate a transfer of data from host to device (an OUT transfer in USB terminology).
USBD_Write() initiate a transfer of data from device to host (an IN transfer).

When the USB host actually performs the transfer, your application will be notified by means of a callback function which you provide (optionally). Refer to TransferCallback for details of the callback functionality.

USBD_AbortTransfer(), USBD_AbortAllTransfers()
These functions terminate transfers that are initiated, but has not yet taken place. If a transfer is initiated with USBD_Read()
or USBD_Write(), but the USB host never actually peform the transfers, these functions will deactivate the transfer setup to make the USB device endpoint hardware ready for new (and potentially) different transfers.

USBD_Connect(), USBD_Disconnect()
These functions turns the data-line (D+ or D-) pullup on or off. They can be used to force reenumeration. It's good practice to delay at least one second between USBD_Disconnect() and USBD_Connect() to allow the USB host to unload the currently active device driver.

USBD_StallEp(), USBD_UnStallEp()
These functions stalls or un-stalls an endpoint. This functionality may not be needed by your application, but the USB device stack use them in response to standard setup commands SET_FEATURE and CLEAR_FEATURE. They may be useful when implementing some USB classes, e.g. a mass storage device use them extensively.

USBD_RemoteWakeup()
Used in SUSPENDED state (see USB_Status_TypeDef) to signal resume to host. It's the applications responsibility to adhere to the USB standard which states that a device can not signal resume before it has been SUSPENDED for at least 5 ms. The function will also check the configuration descriptor defined by the application to see if it is legal for the device to signal resume.

USB_XferCompleteCb_TypeDef() is called when a transfer completes. It is called with three parameters, the status of the transfer, the number of bytes transferred and the number of bytes remaining. It may not always be needed to have a callback on transfer completion, but you should keep in mind that a transfer may be aborted when you least expect it. A transfer will be aborted if host stalls the endpoint, if host resets your device, if host unconfigures your device or if you unplug your device cable and the device is selfpowered. USB_XferCompleteCb_TypeDef() is also called if your application use USBD_AbortTransfer() or USBD_AbortAllTransfers()
calls.

Note

This callback is called from within an interrupt handler with interrupts disabled.

USBD_DeviceStateChangeCb_TypeDef() is called whenever the device state change. Useful for detecting e.g. SUSPENDED state change in order to reduce current consumption of buspowered devices. The USB HID keyboard example project has a good example on how to use this callback.

USBD_IsSelfPoweredCb_TypeDef() is called by the device stack when host queries the device with a standard setup GET_STATUS command to check if the device is currently selfpowered or buspowered. This feature is only applicable on selfpowered devices which also works when only buspower is available.

USBD_SetupCmdCb_TypeDef() is called each time a setup command is received from host. Use this callback to override or extend the default handling of standard setup commands, and to implement class or vendor specific setup commands. The USB HID keyboard example project has a good example on how to use this callback.

You are strongly encouraged to start application development with DEBUG_USB_API turned on. When DEBUG_USB_API is turned on and USER_PUTCHAR is defined, useful debugging information will be output on the development kit serial port. Compiling with the DEBUG_EFM_USER flag will also enable all asserts in both emlib and in the USB stack. If asserts are enabled and USER_PUTCHAR defined, assert texts will be output on the serial port.

Your application must include retargetserial.c if DEBUG_USB_API is defined and retargetio.c if USB_USE_PRINTF is defined. These files reside in the drivers directory in the software package for your development board. Refer to Energy-saving modes for energy-saving mode configurations.

Giant GG11 Gecko's are very flexible in terms of using different clock sources to clock the USB peripheral. The clock source selected must be 48MHz (2500 ppm). Select one of the following macros:

Energy-saving modes

The device stack provides two energy saving levels. The first level is to set the USB peripheral in energy saving mode, the next level is to enter Energy Mode 2 (EM2). These energy saving modes can be applied when the device is suspended by the USB host, or when when the device is not connected to a USB host. In addition to this an application can use energy modes EM1 and EM2. There are no restrictions on when EM1 can be entered, EM2 can only be entered when the USB device is suspended or detached from host.

Energy-saving modes are selected with a #define in usbconfig.h, default selection is to not use any energy saving modes.

There are three flags available, the flags can be or'ed together as shown above.

#define USB_PWRSAVE_MODE_ONSUSPEND
Set USB peripheral in low power mode on suspend.

#define USB_PWRSAVE_MODE_ONVBUSOFF
Set USB peripheral in low power mode when not attached to a host. This mode assumes that the internal voltage regulator is used and that the VREGI pin of the chip is connected to VBUS. This option can not be used with bus-powered devices.

#define USB_PWRSAVE_MODE_ENTEREM2
Enter EM2 when USB peripheral is in low power mode.

When the USB peripheral is set in low power mode, it must be clocked by a 32kHz clock. Both LFXO and LFRCO can be used, but only LFXO guarantee USB specification compliance. Selection is done with a #define in usbconfig.h.

#define USB_USBC_32kHz_CLK USB_USBC_32kHz_CLK_LFXO

Two flags are available, USB_USBC_32kHz_CLK_LFXO and USB_USBC_32kHz_CLK_LFRCO. USB_USBC_32kHz_CLK_LFRCO is selected by default.

Giant GG11 and Happy Gecko's have further energy saving modes (LEM). These are activated by default, but the clocksource of the LEM module is configurable.

In usbconfig.h:
#define USB_USBLEM_CLK USB_USBLEM_CLK_LFXO

Two clock sources are available, USB_USBLEM_CLK_LFXO and USB_USBLEM_CLK_LFRCO. Clock source USB_USBLEM_CLK_LFRCO is selected by default.

Vendor unique device example application

This example represents the most simple USB device imaginable. It's purpose is to turn user LED's on or off under control of vendor unique setup commands. The device will rely on libusb device driver on the host, a host application EFM32-LedApp.exe is bundled with the example.

Now we have to implement vendor unique USB setup commands to control the LED's (see callbacks variable above). Notice that the buffer variable below is statically allocated because USBD_Write() only initiates the transfer. When the host actually performs the transfer, the SetupCmd() function will have returned !

The host stack API

Introduction

This section contains brief descriptions of all functions in the API. You will find detailed information on input and output parameters and return values by clicking on the hyperlinked function names. It is also a good idea to study the code in the USB demonstration projects.

Your application code must include one header file: em_usb.h.

The functions in the API come in two flavours, they are either blocking or non-blocking. The blocking functions have an uppercase letter B at the end of the function name. Blocking functions can not be called when interrupts are disabled. Note that all API callback functions are called from within the USB peripheral interrupt handler with interrupts disabled.

The USB stack use a hardware timer to keep track of time. TIMER0 is the default choice, refer to Configuring the host stack for other possibilities. Your application must not use the selected timer.

Pitfalls:
An USB peripheral will fill host receive buffers in quantities of WORD's (4 bytes). When allocating storage for receive buffers, round size up to next WORD boundary. If it is possible that a device will send more data than host expects, round buffer size up to the next multiple of maxpacket size for the relevant endpoint to avoid buffer overflow.
Transmit and receive buffers must also be WORD aligned. Macros are available for allocating buffers, see UBUF and STATIC_UBUF.

Transmit buffers passed to non-blocking transfer functions must be statically allocated because these functions do not have their own buffers. The data in the transmit buffers must be valid until the transfer completes, times out or fails.

Enumeration and query functions

USBH_QueryDeviceB()
This function will read the device and configuration descriptors from a device at USB address 0. The application must allocate a buffer of sufficent size to hold the data. This data buffer can later be used by all USBH_Qxxx functions to retrieve pointers to any descriptor within any configuration descriptor. Data retrieved by this function must also be passed to USBH_InitDeviceData()
before normal device communication can start. Ref. section Device enumeration and configuration.

USBH_QGetConfigurationDescriptor()
Get a pointer to a given configuration descriptor. Parses through a data buffer which must have been previously populated by a call to USBH_QueryDeviceB().

USBH_QGetDeviceDescriptor()
Get a pointer to the device descriptor. Parses through a data buffer which must have been previously populated by a call to
USBH_QueryDeviceB().

USBH_QGetEndpointDescriptor()
Get a pointer to a given endpoint descriptor within a given interface within a given configuration. Parses through a data buffer which must have been previously populated by a call to USBH_QueryDeviceB().

USBH_QGetInterfaceDescriptor()
Get a pointer to an interface descriptor within a given configuration. Parses through a data buffer which must have been previously populated by a call to USBH_QueryDeviceB().

USBH_InitDeviceData()
Populates device and endpoint data structures with data which must have been retrieved from a device by a call to USBH_QueryDeviceB() . The application must allocate and provide device and endpoint data structures to the host stack. After this function is called the device and endpoint data structures can be used as parameters (handles) to other API functions as needed.

You are strongly encouraged to start application development with DEBUG_USB_API turned on. When DEBUG_USB_API is turned on and USER_PUTCHAR is defined, useful debugging information will be output on the development kit serial port. Compiling with the DEBUG_EFM_USER flag will also enable all asserts in both emlib and in the USB stack. If asserts are enabled and USER_PUTCHAR defined, assert texts will be output on the serial port.

You application must include retargetserial.c if DEBUG_USB_API is defined and retargetio.c if USB_USE_PRINTF is defined. These files reside in the drivers directory in the software package for your development board.

The host stack can be configured to monitor a GPIO input pin for detection of VBUS overcurrent or short circuit conditions. The stack will default to settings applicable to DK3750 for Classic Giant or SLSTK3701A for Giant 11. Override by using the following three #define's:

Select any GPIO port for USB_VBUSOVRCUR_PORT or USB_VBUSOVRCUR_PORT_NONE if no overcurrent circuitry in the hw design. For USB_VBUSOVRCUR_POLARITY use USB_VBUSOVRCUR_POLARITY_LOW or USB_VBUSOVRCUR_POLARITY_HIGH.