USB Device HID Class#

This section describes the Human Interface Device (HID) class supported by Silicon Labs USB Device.

The HID class encompasses devices used by humans to control computer operations, such as keyboards, mice, pointing devices, and game devices.

The HID class can also be used in a composite device that contains controls such as knobs, switches, buttons, and sliders. For example, mute and volume controls in an audio headset are controlled by the HID function of the headset. HID class can exchange data for any purpose using only control and interrupt transfers.

The HID class is one of the oldest and most widely-used USB classes. All the major host operating systems provide a native driver to manage HID devices, which is why a variety of vendor-specific devices work with the HID class. This class also includes various types of output items such as LEDs, audio, tactile feedback, etc.

The HID implementation complies with the following specifications:

  • Device Class Definition for Human Interface Devices (HID), 6/27/01, Version 1.11.

  • Universal Serial Bus HID Usage Tables, 10/28/2004, Version 1.12.

USB Device HID Class Overview#

Overview#

A HID device is composed of the following endpoints:

  • A pair of control IN and OUT endpoints called the default endpoint

  • An interrupt IN endpoint

  • An optional interrupt OUT endpoint

The table below describes the usage of the different endpoints:

Table - HID Class Endpoints Usage#

Endpoint

Direction

Usage

Control IN

Device-to-host

Standard requests for enumeration, class-specific requests, and data communication (Input, Feature reports sent to the host with GET_REPORT request).

Control OUT

Host-to-device

Standard requests for enumeration, class-specific requests and data communication (Output, Feature reports received from the host with SET_REPORT request).

Interrupt IN

Device-to-host

Data communication (Input and Feature reports).

Interrupt OUT

Host-to-device

Data communication (Output and Feature reports).

Report#

A host and a HID device exchange data using reports. A report contains formatted data giving information about controls and other physical entities of the HID device. A control is manipulable by the user and operates an aspect of the device. For example, a control can be a button on a mouse or a keyboard, a switch, etc. Other entities inform the user about the state of certain device’s features. For example, LEDs on a keyboard notify the user about the caps lock on, the numeric keypad active, etc.

The format and the use of a report data is understood by the host by analyzing the content of a Report descriptor. Analyzing the content is done by a parser. The Report descriptor describes data provided by each control in a device. It is composed of items which are pieces of information about the device and consist of a 1-byte prefix and variable-length data. For more details about the item format, refer to “Device Class Definition for Human Interface Devices (HID) Version 1.11”, section 5.6 and 6.2.2.

There are three principal types of items:

  • Main item defines or groups certain types of data fields.

  • Global item describes data characteristics of a control.

  • Local item describes data characteristics of a control.

Each item type is defined by different functions. An item function can also be called a tag. An item function can be seen as a sub-item that belongs to one of the three principal item types. The table below provides a brief overview of the item’s functions in each item type. For a complete description of the items in each category, see “Device Class Definition for Human Interface Devices (HID) Version 1.11”, section 6.2.2.

Table - Item’s Function Description for Each Item Type#

Item Type

Item Function

Description

Main

Input

Describes information about the data provided by one or more physical controls.

Main

Output

Describes data sent to the device.

Main

Feature

Describes device configuration information sent to or received from the device which influences the overall behavior of the device or one of its components.

Main

Collection

Group related items (Input, Output or Feature).

Main

End of Collection

Closes a collection.

Global

Usage Page

Identifies a function available within the device.

Global

Logical Minimum

Defines the lower limit of the reported values in logical units.

Global

Logical Maximum

Defines the upper limit of the reported values in logical units.

Global

Physical Minimum

Defines the lower limit of the reported values in physical units, that is the Logical Minimum expressed in physical units.

Global

Physical Maximum

Defines the upper limit of the reported values in physical units, that is the Logical Maximum expressed in physical units.

Global

Unit Exponent

Indicates the unit exponent in base 10. The exponent ranges from -8 to +7.

Global

Unit

Indicates the unit of the reported values. For instance, length, mass, temperature units, etc.

Global

Report Size

Indicates the size of the report fields in bits.

Global

Report ID

Indicates the prefix added to a particular report.

Global

Report Count

Indicates the number of data fields for an item.

Global

Push

Places a copy of the global item state table on the CPU stack.

Global

Pop

Replaces the item state table with the last structure from the stack.

Local

Usage

Represents an index to designate a specific Usage within a Usage Page. It indicates the vendor’s suggested use for a specific control or group of controls. A usage supplies information to an application developer about what a control is actually measuring.

Local

Usage Minimum

Defines the starting usage associated with an array or bitmap.

Local

Usage Maximum

Defines the ending usage associated with an array or bitmap.

Local

Designator Index

Determines the body part used for a control. Index points to a designator in the Physical descriptor.

Local

Designator Minimum

Defines the index of the starting designator associated with an array or bitmap.

Local

Designator Maximum

Defines the index of the ending designator associated with an array or bitmap.

Local

String Index

String index for a String descriptor. It allows a string to be associated with a particular item or control.

Local

String Minimum

Specifies the first string index when assigning a group of sequential strings to controls in an array or bitmap.

Local

String Maximum

Specifies the last string index when assigning a group of sequential strings to controls in an array or bitmap.

Local

Delimiter

Defines the beginning or end of a set of local items.

A control’s data must define at least the following items:

  • Input, Output or Feature Main items

  • Usage Local item

  • Usage Page Global item

  • Logical Minimum Global item

  • Logical Maximum Global item

  • Report Size Global item

  • Report Count Global item

The table below shows the representation of a Mouse Report descriptor content from a host HID parser perspective. The mouse has three buttons (left, right, and wheel). The code presented in the example below is a code implementation corresponding to this mouse Report descriptor representation.

Figure - Report Descriptor Content from a Host HID Parser View#

Figure 9 Report Descriptor Content from a Host HID Parser View

(1) The Usage Page item function specifies the general function of the device. In this example, the HID device belongs to a generic desktop control.

(2) The Collection Application groups Main items that have a common purpose and may be familiar to applications. In the diagram, the group is composed of three Input Main items. For this collection, the suggested use for the controls is a mouse as indicated by the Usage item.

(3) Nested collections may be used to give more details about the use of a single control or group of controls to applications. In this example, the Collection Physical, nested into the Collection Application, is composed of the same three Input items forming the Collection Application. The Collection Physical is used for a set of data items that represent data points collected at one geometric point. In the example, the suggested use is a pointer as indicated by the Usage item. Here the pointer usage refers to the mouse position coordinates and the system software will translate the mouse coordinates in movement of the screen cursor.

(4) Nested usage pages are also possible and give more details about a certain aspect within the general function of the device. In this case, two Inputs items are grouped and correspond to the buttons of the mouse. One Input item defines the three buttons of the mouse (right, left and wheel) in terms of number of data fields for the item (Report Count item), size of a data field (Report Size item) and possible values for each data field (Usage Minimum and Maximum, Logical Minimum and Maximum items). The other Input item is a 13-bit constant allowing the Input report data to be aligned on a byte boundary. This Input item is used only for padding purpose.

(5) Another nested usage page referring to a generic desktop control is defined for the mouse position coordinates. For this usage page, the Input item describes the data fields corresponding to the x- and y-axis as specified by the two Usage items.

After analyzing the previous mouse Report descriptor content, the host’s HID parser is able to interpret the Input report data sent by the device with an interrupt IN transfer or in response to a GET_REPORT request. The Input report data corresponding to the mouse Report descriptor shown in Figure - Report Descriptor Content from a Host HID Parser View is shown in the table below. The total size of the report data is 4 bytes. Different types of reports may be sent over the same endpoint. For the purpose of distinguishing the different types of reports, a 1-byte report ID prefix is added to the data report. If a report ID was used in the example of the mouse report, the total size of the report data would be 5 bytes.

Table - Input Report Sent to Host and Corresponding to the State of a 3-Buttons Mouse#

Bit Offset

Bit Count

Description

0

1

Button 1 (left button).

1

1

Button 2 (right button).

2

1

Button 3 (wheel button).

3

13

Not used.

16

8

Position on axis X.

24

8

Position on axis Y.

A Physical descriptor indicates the part or parts of the body intended to activate a control or controls. An application may use this information to assign a functionality to the control of a device. A Physical descriptor is an optional class-specific descriptor and most devices have little gain for using it. Refer to “Device Class Definition for Human Interface Devices (HID) Version 1.11” section 6.2.3 for more details about this descriptor.

USB Device HID Class Resource Needs from Core#

Each time you add a HID class instance to a USB configuration via a call to the function sl_usbd_hid_add_to_configuration(), the following resources will be allocated from the core.

Resource

Quantity

Interfaces

1

Alternate interfaces

1

Endpoints

1 (2 if interrupt OUT endpoint is enabled)

Interface groups

0

Note that those numbers are per configuration. When setting up your SL_USBD_INTERFACE_QUANTITY, SL_USBD_ALT_INTERFACE_QUANTITY, SL_USBD_INTERFACE_GROUP_QUANTITY and SL_USBD_DESCRIPTOR_QUANTITY configuration values, don't forget to take into account on how many configurations the class will be added. For the SL_USBD_OPEN_ENDPOINTS_QUANTITY configuration value, since endpoints are opened only when a configuration is set by the host, you just need to take into account the number of needed endpoints for a class instance.

USB Device HID Class Configuration#

Two groups of configuration parameters are used to configure the HID class:

USB Device HID Class Application-Specific Configurations#

First, to use the Silicon Labs USB device HID class module, adjust the HID compile-time configuration defines according to your application needs. They are regrouped inside the sl_usbd_core_config.h header file under the HID section. They can be divided into two sections, the quantity configurations and the HID task configurations. The quantity configurations purpose is to inform the USB device module about how many USB HID objects to allocate.

The table below describes each configuration define.

Table - USB Device HID Configuration Defines#

Configuration Name

Description

Default Value

SL_USBD_HID_CLASS_INSTANCE_QUANTITY

Number of class instances you will allocate via a call to the function sl_usbd_hid_create_instance().

2

SL_USBD_HID_CONFIGURATION_QUANTITY

Number of configurations. HID class instances can be added to one or more configurations via a call to the function sl_usbd_hid_add_to_configuration().

1

SL_USBD_HID_REPORT_ID_QUANTITY

Configures the total number of report IDs to allocate.

2

SL_USBD_HID_PUSH_POP_ITEM_QUANTITY

Configures the total number of Push/Pop items to allocate.

0

SL_USBD_HID_TIMER_TASK_STACK_SIZE

The timer task handles all the timer-based HID operations. This configuration allows you to set the stack size (in number of bytes).

2048

SL_USBD_HID_TIMER_TASK_PRIORITY

Priority of HID task. his is a CMSIS-RTOS2 priority.

osPriorityHigh

USB Device HID Class Instance Configurations#

This section defines the configurations related to the HID class instances.

Class Instance Creation#

Creating a HID class instance is done by calling the function sl_usbd_hid_create_instance(), which takes several configuration arguments that are described below.

subclass#

Code of the HID subclass. Possible values are:

  • SL_USBD_HID_SUBCLASS_NONE

  • SL_USBD_HID_SUBCLASS_BOOT

A HID device that uses the boot subclass must use standard report formats. For more information on the subclass codes, see section 4.2 of HID specification revision 1.11.

protocol#

Protocol used by the HID device. Possible values are:

  • SL_USBD_HID_PROTOCOL_NONE

  • SL_USBD_HID_PROTOCOL_KBD

  • SL_USBD_HID_PROTOCOL_MOUSE

If your HID function is a mouse, the protocol should be set to SL_USBD_HID_PROTOCOL_MOUSE. If it is a keyboard, it should be set to SL_USBD_HID_PROTOCOL_KBD. Otherwise, the protocol should be set to SL_USBD_HID_PROTOCOL_NONE. For more information on the subclass codes, see section 4.3 of HID specification revision 1.11.

country_code#

ID of the country code. Possible values are:

  • SL_USBD_HID_COUNTRY_CODE_NOT_SUPPORTED

  • SL_USBD_HID_COUNTRY_CODE_ARABIC

  • SL_USBD_HID_COUNTRY_CODE_BELGIAN

  • SL_USBD_HID_COUNTRY_CODE_CANADIAN_BILINGUAL

  • SL_USBD_HID_COUNTRY_CODE_CANADIAN_FRENCH

  • SL_USBD_HID_COUNTRY_CODE_CZECH_REPUBLIC

  • SL_USBD_HID_COUNTRY_CODE_DANISH

  • SL_USBD_HID_COUNTRY_CODE_FINNISH

  • SL_USBD_HID_COUNTRY_CODE_FRENCH

  • SL_USBD_HID_COUNTRY_CODE_GERMAN

  • SL_USBD_HID_COUNTRY_CODE_GREEK

  • SL_USBD_HID_COUNTRY_CODE_HEBREW

  • SL_USBD_HID_COUNTRY_CODE_HUNGARY

  • SL_USBD_HID_COUNTRY_CODE_INTERNATIONAL

  • SL_USBD_HID_COUNTRY_CODE_ITALIAN

  • SL_USBD_HID_COUNTRY_CODE_JAPAN_KATAKANA

  • SL_USBD_HID_COUNTRY_CODE_KOREAN

  • SL_USBD_HID_COUNTRY_CODE_LATIN_AMERICAN

  • SL_USBD_HID_COUNTRY_CODE_NETHERLANDS_DUTCH

  • SL_USBD_HID_COUNTRY_CODE_NORWEGIAN

  • SL_USBD_HID_COUNTRY_CODE_PERSIAN_FARSI

  • SL_USBD_HID_COUNTRY_CODE_POLAND

  • SL_USBD_HID_COUNTRY_CODE_PORTUGUESE

  • SL_USBD_HID_COUNTRY_CODE_RUSSIA

  • SL_USBD_HID_COUNTRY_CODE_SLOVAKIA

  • SL_USBD_HID_COUNTRY_CODE_SPANISH

  • SL_USBD_HID_COUNTRY_CODE_SWEDISH

  • SL_USBD_HID_COUNTRY_CODE_SWISS_FRENCH

  • SL_USBD_HID_COUNTRY_CODE_SWISS_GERMAN

  • SL_USBD_HID_COUNTRY_CODE_SWITZERLAND

  • SL_USBD_HID_COUNTRY_CODE_TAIWAN

  • SL_USBD_HID_COUNTRY_CODE_TURKISH_Q

  • SL_USBD_HID_COUNTRY_CODE_UK

  • SL_USBD_HID_COUNTRY_CODE_US

  • SL_USBD_HID_COUNTRY_CODE_YUGOSLAVIA

  • SL_USBD_HID_COUNTRY_CODE_TURKISH_F

The country code identifies which country the hardware is localized for. Most hardware is not localized and therefore this value would be SL_USBD_HID_COUNTRY_CODE_NOT_SUPPORTED(0). However, keyboards may use the field to indicate the language of the key caps.

For more information on the country codes, see section 6.2.1 of HID specification revision 1.11.

interval_in and interval_out#

interval_in and interval_out represent the polling interval of the IN interrupt endpoint and the OUT interrupt endpoint.

This represents the polling interval of the endpoint, in milliseconds. Setting this value depends on how frequently your device is susceptible to generate a new report for the host. For instance, if a report is generated every 16 milliseconds, the interval should be 16 or less.

The value must be a power of 2 (1, 2, 4, 8, 16, etc.).

interval_out value is ignored if ctrl_rd_en is set to true.

p_hid_callback#

p_hid_callback is a pointer to a structure of type sl_usbd_hid_callbacks_t. Its purpose is to give the HID Class a set of callback functions to be called when a HID event occurs.

Not all callbacks are mandatory and a null pointer (NULL) can be passed in the callbacks structure variable when the callback is not needed.

The table below describes each configuration field available in this configuration structure.

Table - sl_usbd_hid_callbacks_t Configuration Structure#

Fields

Description

Function Signature

.enable

Called when the USB class instance is enabled successfully.

void app_usbd_hid_enable(uint8_t class_nbr);

.disable

Called when the USB class instance is disabled.

void app_usbd_hid_disable(uint8_t class_nbr);

.get_report_desc

Called during the HID Instance creation to pass your report descriptor. For each of your HID functions, you must provide a report descriptor. The report descriptor indicates to the host how the periodic report that will be sent by the device should be parsed. Writing your own report descriptor can be challenging, and that is why there are some resources to help. This is the only mandatory callback function.

void app_usbd_hid_get_report_desc(uint8_t class_nbr, const uint8_t *p_report_ptr, uint16_tp_report_len);

.get_phy_desc

Called during the HID Instance creation to pass your physical descriptor. The physical descriptor is a descriptor that provides information about the specific part or parts of the human body that are activating a control or controls. For more information on physical descriptors, see section 6.2.3 of HID specification revision 1.11. The physical descriptor is optional and most of the time ignored. The buffer passed here can be set to NULL and the length set to 0.

void app_usbd_hid_get_phy_desc(uint8_t class_nbr, const uint8_t *p_report_ptr, uint16_tp_report_len);

.set_output_report

Called when the host sets a report as described in your report descriptor (when it sends a report).

void app_usbd_hid_set_output_report(uint8_t class_nbr, uint8_t report_id, uint8_t *p_report_buf, uint16_t report_len);

.get_feature_report

Called when the host requests a feature report as described in your report descriptor.

void app_usbd_hid_get_feature_report(uint8_t class_nbr, uint8_t report_id, uint8_t *p_report_buf, uint16_t report_len);

.set_feature_report

Called when the host sets a feature report as described in your report descriptor.

void app_usbd_hid_set_feature_report(uint8_t class_nbr, uint8_t report_id, uint8_t *p_report_buf, uint16_t report_len);

.get_protocol

Retrieves current active protocol.

void app_usbd_hid_get_protocol(uint8_t class_nbr, uint8_t *p_protocol);

.set_protocol

Sets current active protocol.

void app_usbd_hid_set_protocol(uint8_t class_nbr, uint8_t protocol);

HID Class Report Descriptor Example#

Silicon Labs' HID class sample application provides an example of a report descriptor for a simple mouse. The example below shows a mouse report descriptor.

Example - Mouse Report Descriptor#
static  uint8_t  app_usbd_hid_report_desc[] = {                                          (1) (2)
  SL_USBD_HID_GLOBAL_USAGE_PAGE    + 1, SL_USBD_HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROLS,
  SL_USBD_HID_LOCAL_USAGE          + 1, SL_USBD_HID_CA_MOUSE,                            (3)
  SL_USBD_HID_MAIN_COLLECTION      + 1, SL_USBD_HID_COLLECTION_APPLICATION,              (4)
  SL_USBD_HID_LOCAL_USAGE          + 1, SL_USBD_HID_CP_POINTER,                          (5)
  SL_USBD_HID_MAIN_COLLECTION      + 1, SL_USBD_HID_COLLECTION_PHYSICAL,                 (6)
  SL_USBD_HID_GLOBAL_USAGE_PAGE    + 1, SL_USBD_HID_USAGE_PAGE_BUTTON,                   (7)
  SL_USBD_HID_LOCAL_USAGE_MIN      + 1, 0x01,
  SL_USBD_HID_LOCAL_USAGE_MAX      + 1, 0x03,
  SL_USBD_HID_GLOBAL_LOG_MIN       + 1, 0x00,
  SL_USBD_HID_GLOBAL_LOG_MAX       + 1, 0x01,
  SL_USBD_HID_GLOBAL_REPORT_COUNT  + 1, 0x03,
  SL_USBD_HID_GLOBAL_REPORT_SIZE   + 1, 0x01,
  SL_USBD_HID_MAIN_INPUT           + 1, SL_USBD_HID_MAIN_DATA     |
                                        SL_USBD_HID_MAIN_VARIABLE |
                                        SL_USBD_HID_MAIN_ABSOLUTE,
  SL_USBD_HID_GLOBAL_REPORT_COUNT  + 1, 0x01,                                            (8)
  SL_USBD_HID_GLOBAL_REPORT_SIZE   + 1, 0x0D,
  SL_USBD_HID_MAIN_INPUT           + 1, SL_USBD_HID_MAIN_CONSTANT,
                                                                                         (9)
  SL_USBD_HID_GLOBAL_USAGE_PAGE    + 1, SL_USBD_HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROLS,
  SL_USBD_HID_LOCAL_USAGE          + 1, SL_USBD_HID_DV_X,
  SL_USBD_HID_LOCAL_USAGE          + 1, SL_USBD_HID_DV_Y,
  SL_USBD_HID_GLOBAL_LOG_MIN       + 1, 0x81,
  SL_USBD_HID_GLOBAL_LOG_MAX       + 1, 0x7F,
  SL_USBD_HID_GLOBAL_REPORT_SIZE   + 1, 0x08,
  SL_USBD_HID_GLOBAL_REPORT_COUNT  + 1, 0x02,
  SL_USBD_HID_MAIN_INPUT           + 1, SL_USBD_HID_MAIN_DATA     |
                                        SL_USBD_HID_MAIN_VARIABLE |
                                        SL_USBD_HID_MAIN_RELATIVE,
  SL_USBD_HID_MAIN_ENDCOLLECTION,                                                        (10)
  SL_USBD_HID_MAIN_ENDCOLLECTION                                                         (11)
};

(1) The table representing a mouse report descriptor is initialized in such way that each line corresponds to a short item. The latter is formed from a 1-byte prefix and a 1-byte data. Refer to “Device Class Definition for Human Interface Devices (HID) Version 1.11”, sections 5.3 and 6.2.2.2 for more details about short items format. This table content corresponds to the mouse report descriptor content viewed by a host HID parser in Figure - Report Descriptor Content from a Host HID Parser View.

(2) The Generic Desktop Usage Page is used.

(3) Within the Generic Desktop Usage Page, the usage tag suggests that the group of controls is for controlling a mouse. A mouse collection typically consists of two axes (X and Y) and one, two, or three buttons.

(4) The mouse collection is started.

(5) Within the mouse collection, a usage tag suggests more specifically that the mouse controls belong to the pointer collection. A pointer collection is a collection of axes that generates a value to direct, indicate, or point user intentions to an application.

(6) The pointer collection is started.

(7) The Buttons Usage Page defines an Input item composed of three 1-bit fields. Each 1-bit field represents the mouse’s button 1, 2 and 3 respectively and can return a value of 0 or 1.

(8) The Input Item for the Buttons Usage Page is padded with 13 other bits.

(9) Another Generic Desktop Usage Page is indicated for describing the mouse position with the axes X and Y. The Input item is composed of two 8-bit fields whose value can be between -127 and 127.

(10) The pointer collection is closed.

(11) The mouse collection is closed.

USB.org HID Page#

The USB Implementers Forum (USB-IF) provides a tool called "HID Descriptor Tool" along with other information on the report descriptor format. Seehttp://www.usb.org/developers/hidpage/ for more information.

USB Device HID Class Programming Guide#

This section explains how to use the HID class.

Initializing the USB Device HID Class#

To add HID Class functionality to your device, you must first initialize the class by calling the function sl_usbd_hid_init().

The example below shows how to call sl_usbd_hid_init() using default arguments. For more information on the configuration arguments to pass to sl_usbd_hid_init(), see USB Device HID Class Application Specific Configurations .

Example - Calling sl_usbd_hid_init()#
sl_status_t  status;

status = sl_usbd_hid_init();
if (status != SL_STATUS_OK) {
  /* An error occurred. Error handling should be added here. */
}

Adding a USB Device HID Class Instance to Your Device#

To add HID class functionality to your device, you must create an instance, then add it to your device's configuration(s).

Creating a HID Class Instance#

Create a HID class instance by calling the function sl_usbd_hid_create_instance().

The example below shows how to create a simple mouse function via sl_usbd_hid_create_instance() using default arguments. For more information on the configuration arguments to pass to sl_usbd_hid_create_instance(), see USB Device HID Class Instance Configurations .

Example - Adding a Mouse Function via sl_usbd_hid_create_instance()#
/* Global constants.  */
static  const  uint8_t  app_usbd_hid_mouse_report_desc[] = {
    SL_USBD_HID_GLOBAL_USAGE_PAGE   + 1, SL_USBD_HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROLS,
    SL_USBD_HID_LOCAL_USAGE         + 1, SL_USBD_HID_CA_MOUSE,
    SL_USBD_HID_MAIN_COLLECTION     + 1, SL_USBD_HID_COLLECTION_APPLICATION,
    SL_USBD_HID_LOCAL_USAGE         + 1, SL_USBD_HID_CP_POINTER,
    SL_USBD_HID_MAIN_COLLECTION     + 1, SL_USBD_HID_COLLECTION_PHYSICAL,
    SL_USBD_HID_GLOBAL_USAGE_PAGE   + 1, SL_USBD_HID_USAGE_PAGE_BUTTON,
    SL_USBD_HID_LOCAL_USAGE_MIN     + 1, 0x01,
    SL_USBD_HID_LOCAL_USAGE_MAX     + 1, 0x03,
    SL_USBD_HID_GLOBAL_LOG_MIN      + 1, 0x00,
    SL_USBD_HID_GLOBAL_LOG_MAX      + 1, 0x01,
    SL_USBD_HID_GLOBAL_REPORT_COUNT + 1, 0x03,
    SL_USBD_HID_GLOBAL_REPORT_SIZE  + 1, 0x01,
    SL_USBD_HID_MAIN_INPUT          + 1, SL_USBD_HID_MAIN_DATA | SL_USBD_HID_MAIN_VARIABLE | SL_USBD_HID_MAIN_ABSOLUTE,
    SL_USBD_HID_GLOBAL_REPORT_COUNT + 1, 0x01,
    SL_USBD_HID_GLOBAL_REPORT_SIZE  + 1, 0x0D,
    SL_USBD_HID_MAIN_INPUT          + 1, SL_USBD_HID_MAIN_CONSTANT,
    SL_USBD_HID_GLOBAL_USAGE_PAGE   + 1, SL_USBD_HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROLS,
    SL_USBD_HID_LOCAL_USAGE         + 1, SL_USBD_HID_DV_X,
    SL_USBD_HID_LOCAL_USAGE         + 1, SL_USBD_HID_DV_Y,
    SL_USBD_HID_GLOBAL_LOG_MIN      + 1, 0x81,
    SL_USBD_HID_GLOBAL_LOG_MAX      + 1, 0x7F,
    SL_USBD_HID_GLOBAL_REPORT_SIZE  + 1, 0x08,
    SL_USBD_HID_GLOBAL_REPORT_COUNT + 1, 0x02,
    SL_USBD_HID_MAIN_INPUT          + 1, SL_USBD_HID_MAIN_DATA | SL_USBD_HID_MAIN_VARIABLE | SL_USBD_HID_MAIN_RELATIVE,
    SL_USBD_HID_MAIN_ENDCOLLECTION,
    SL_USBD_HID_MAIN_ENDCOLLECTION
};

/* Local variables.*/
uint8_t      class_nbr;
sl_status_t  status;

sl_usbd_hid_callbacks_t app_usbd_hid_callbacks = {
  NULL,
  NULL,
  app_usbd_hid_get_report_desc,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL
};

void app_usbd_hid_get_report_desc(uint8_t       class_nbr,
                                  const uint8_t **p_report_ptr,
                                  uint16_t      *p_report_len)
{
  (void)class_nbr;

  *p_report_ptr = app_usbd_hid_mouse_report_desc;
  *p_report_len = sizeof(app_usbd_hid_mouse_report_desc);
}

status = sl_usbd_hid_create_instance(SL_USBD_HID_SUBCLASS_BOOT,
                                     SL_USBD_HID_PROTOCOL_MOUSE,
                                     SL_USBD_HID_COUNTRY_CODE_NOT_SUPPORTED,
                                     Ex_USBD_HID_Mouse_ReportDesc,
                                     sizeof(Ex_USBD_HID_Mouse_ReportDesc),
                                     2u,
                                     2u,
                                     true,
                                     &app_usbd_hid_callbacks,
                                     &class_nbr);
if (status != SL_STATUS_OK) {
  /* An error occurred. Error handling should be added here. */
}

Adding the HID Class Instance to Your Device's Configuration(s)#

After you have created a HID class instance, you can add it to a configuration by calling the function sl_usbd_hid_add_to_configuration().

The example below shows how to call sl_usbd_hid_add_to_configuration().

Example - Calling sl_usbd_hid_add_to_configuration()#
sl_status_t  status;

sl_usbd_hid_add_to_configuration(class_nbr,           (1)
                                 config_nbr_fs);      (2)
if (status != SL_STATUS_OK) {
  /* An error occurred. Error handling should be added here. */
}

(1) Class number to add to the configuration returned by sl_usbd_hid_create_instance().

(2) Configuration number (here adding it to a Full-Speed configuration).

Communicating Using the USB Device HID Class#

Class Instance Communication#

The HID class offers the following functions to communicate with the host.

Table - HID Communication API Summary#

Function name

Operation

sl_usbd_hid_read_sync()

Receives data from the host through interrupt OUT endpoint. This function is blocking.

sl_usbd_hid_write_sync()

Sends data to the host through interrupt IN endpoint. This function is blocking.

Synchronous Communication#

Synchronous communication means that the transfer is blocking. Upon the function call, the applications blocks until the transfer is completed with or without an error. A timeout can be specified to avoid waiting forever.

The example below shows a read and write that receives data from the host using the interrupt OUT endpoint and sends data to the host using the interrupt IN endpoint.

Example - Synchronous HID Read and Write#
__ALIGNED(4) uint8_t  rx_buf[2];
__ALIGNED(4) uint8_t  tx_buf[2];
uint32_t              xfer_len;
sl_status_t           status;

status = sl_usbd_hid_read_sync(class_nbr,                                         (1)
                               (void *)rx_buf,                                    (2)
                               2u,
                               0u,                                                (3)
                               &xfer_len);
if (status != SL_STATUS_OK) {
  /* An error occurred. Error handling should be added here. */
}

status = sl_usbd_hid_write_sync(class_nbr,                                         (1)
                                (void *)tx_buf,                                    (4)
                                2u,
                                0u,                                                (3)
                                &xfer_len);
if (status != SL_STATUS_OK) {
  /* An error occurred. Error handling should be added here. */
}

(1) The class instance number created from sl_usbd_hid_create_instance() provides an internal reference for the HID class to route the transfer to the proper interrupt OUT or IN endpoint.

(2) The application must ensure that the buffer provided to the function is large enough to accommodate all the data. Otherwise, synchronization issues might happen. Internally, the read operation is done either with the control endpoint or with the interrupt endpoint, depending on the control read flag set when calling sl_usbd_hid_create_instance().

(3) To avoid an infinite blocking situation, a timeout expressed in milliseconds can be specified. A value of ‘0’ makes the application task wait forever.

(4) The application provides the initialized transmit buffer.

HID Periodic Input Reports Task#

To save bandwidth, the host has the ability to silence reports from an interrupt IN endpoint by limiting the reporting frequency. To do so, the host must send the SET_IDLE request. The HID class implemented by Silicon Labs contains an internal task that respects the reporting frequency limitation that you can apply to one or several input reports. Figure - Periodic Input Reports Task shows the functioning of the periodic input reports tasks.

Figure - Periodic Input Reports Task#

Figure 11 Periodic Input Reports Task

(1) The device receives a SET_IDLE request. This request specifies an idle duration for a given report ID. For more details about the SET_IDLE request, see “Device Class Definition for Human Interface Devices (HID) Version 1.11”, section 7.2.4. A report ID allows you to distinguish among the different types of reports sent from the same endpoint.

(2) A report ID structure (allocated during the HID class initialization phase) is updated with the idle duration. An idle duration counter is initialized with the idle duration value. The report ID structure is inserted at the end of a linked list containing input reports ID structures. The idle duration value is expressed in 4-ms unit which gives a range of 4 to 1020 ms. If the idle duration is less than the polling interval of the interrupt IN endpoint, the reports are generated at the polling interval.

(3) Every 4 ms, the periodic input report task browses the input reports ID list. For each input report ID, the task performs one of two possible operations. The duration of the task period matches the 4-ms unit used for the idle duration. If no SET_IDLE requests have been sent by the host, the input reports ID list is empty and the task has nothing to process. The task processes only report IDs that are different from 0 and with an idle duration greater than 0.

(4) For a given input report ID, the task verifies if the idle duration has elapsed. If the idle duration has not elapsed, the counter is decremented and no input report is sent to the host.

(5) If the idle duration has elapsed (that is, the idle duration counter has reached zero), an input report is sent to the host by calling the sl_usbd_hid_write_sync() function via the interrupt IN endpoint.

(6) The input report data sent by the task comes from an internal data buffer allocated for each input report described in the Report descriptor. An application task can call the sl_usbd_hid_write_sync() function to send an input report. After sending the input report data, sl_usbd_hid_write_sync() updates the internal buffer associated to an input report ID with the data just sent. Then, the periodic input reports task always sends the same input report data after each idle duration elapsed and until the application task updates the data in the internal buffer. There is some locking mechanism to avoid corruption of the input report ID data in the event of a modification happening at the exact time of transmission done by the periodic input report task.