USB Human Interface Device (HID) Class Device Implementation with MPLAB® Harmony v2

This page shows the unique attributes for an MPLAB® Harmony USB Human Interface Device (HID) project. To get the most out of this page it is useful to have reviewed the USB Device Page showing the Harmony features common to all device projects. After finishing this page you should be able to more easily follow the step-by-step description of Developer Help's example HID project.

HID Report

HIDs respond to host requests by returning a data element called an HID Report. The length and format of the HID Report are set by the HID Report Descriptor. It is the responsibility of the application to format the HID Report in compliance with the HID Report Descriptor.

The sample Harmony USB projects use some of the most common HID Report examples including a mouse, a keyboard, and a user-defined protocol. The examples below are the HID Report formats for a simple three-button mouse and a gamepad controller.

HID Report format when usage page = generic desktop control and usage = mouse
bit 7 bit 6 bit 5 bit 4 bit 3 bit 3 bit 1 bit 0
Byte 0 - - - - - - - - - - - - - - - Left Button Middle Button Right Button
Byte 1 X axis relative movement as signed char
Byte 2 Y axis relative movement as signed char

HID Report format when usage page = generic desktop control and usage = gamepad
bit 7 bit 6 bit 5 bit 4 bit 3 bit 3 bit 1 bit 0
Byte 0 Button Button Button Button Button Button Button Button
Byte 1 Button Button Button Button Button Button Button Button
Byte 2 Left X axis as signed char
Byte 3 Left Y as signed char
Byte 4 Right X axis as signed char
Byte 5 Right Y as signed char

HID Report Descriptor

The HID Report Descriptor resides in the device and defines the format in which the device will send messages to the host. This information is shared with the host during enumeration.

The example below shows the code defining an HID Report Descriptor for a simple three-button mouse. The report indicates three bytes will be sent:

  • The first byte contains three single elements which are input variables and five 1-bit inputs which are constants (i.e. padding).
  • The second and third bytes each have a range of -127 to +127 and their input is variable (set by the applications).

Device Descriptor Table

The device descriptor table is the mechanism by which a device informs the host of the communication expectations of the device. The descriptor table is read from the device by the host during the enumeration process. There is very little room for a variance with the descriptor table for an HID. The USB standard for HID dictates much of the descriptor table contents. All HID Descriptor tables have these common attributes:

  1. At least one interface must exist with the class code for an HID.
  2. The HID interface will have exactly two data endpoints (Endpoint1 IN and Endpoint1 OUT).
  3. Both endpoints will have Interrupt Transfer types, be 64-bytes in length, and be scheduled to be polled every frame.

USB specifications allow the developer to select the Vendor/Product ID numbers, power consumption figures, as well as any identification text strings used.

Below is an example of a device descriptor for a single configuration HID. The device configuration has a maximum power consumption of 50 ma, and a Vendor ID/Product ID (VID/PID) of 0x0480/0x0000. There are two identifying text strings for this device.

Driver Event Handler

Harmony USB projects schedule a HID Driver Task (either DRV_USBFS_Tasks or DRV_USBHS_Tasks) to run on each iteration of the main while loop. When the device is enumerated, a user-written function is designated as the HID Driver Event Handler by USB_DEVICE_HID_EventHandlerSet().

DriverEventHandler.svg

The Driver Task monitors the communication between the host and the device. When certain events are detected, the user-written event handler is called. The event handler will then process the following events:

HID Events Detected by Driver Function Description
USB_DEVICE_HID_EVENT_GET_REPORT A GET REPORT command received from the host.
USB_DEVICE_HID_EVENT_SET_REPORT A SET REPORT command received from the host.
USB_DEVICE_HID_EVENT_REPORT_SENT The data in Endpoint1 IN has successfully been
sent to the host.
USB_DEVICE_HID_EVENT_REPORT_RECEIVED A data packet has been received from the host
and has been placed in Endpoint 1 OUT.
USB_DEVICE_HID_EVENT_SET_IDLE A SET IDLE command received from the host. The
device will set the new idle rate.
USB_DEVICE_HID_EVENT_GET_IDLE A GET IDLE command received from host. The device
responds by sending the current idle rate value.
USB_DEVICE_HID_EVENT_SET_PROTOCOL A SET PROTOCOL command received from host
device will accept the new protocol value.
USB_DEVICE_HID_EVENT_GET_PROTOCOL A GET PROTOCOL command received. The device
returns the value of the current protocol.
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT The host has sent a control packet
to the device.
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED The host has a received a control
packet response from the device.
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_ABORTED The host has aborted a control transfer.

How is the Driver Event Handler used in an Application?

One of the most common usages of the HID Event Handler is to inform the application of either the receipt or the successful transmission of an HID Report. The code below shows an application program working with the sample event handler to track the transmission of a report.

Sample HID Event Handler:

// Application HID Event Handler Code
void APP_USBDeviceHIDEventHandler(USB_DEVICE_HID_INDEX hidInstance,
USB_DEVICE_HID_EVENT event, void * eventData, uintptr_t userData)
{
switch(event)
{

case USB_DEVICE_HID_EVENT_REPORT_SENT:
appdata.SendBufferEmpty = TRUE ; // Set a flag for the application program.
break ;

}
}

// Registering the HID Event Handler
USB_DEVICE_HID_EventHandlerSet(USB_DEVICE_HID_INDEX_0,
APP_USBDeviceHIDEventHandler, (uintptr_t)&appdata) ;

An Application Communicating with the Sample HID Event Handler:

void APP_MyCommuncationTask(void)
{
switch(commdata.state)
{

case SEND_DATA_TO_HOST:
if (appdata.SendBufferEmpty == TRUE) // Can the data be sent?
{
USB_DEVICE_HID_ReportSend(
USB_DEVICE_HID_INDEX_0,
&hidTransferHandle ,
&appReport[0], sizeof(appReport)); // initiate sending the HID Report.
appdata.SendBufferEmpty = FALSE ; // Clear the flag
commdata.state = WAIT_FOR_HID_REPORT_TO_BE_SENT ;
}
break;

case WAIT_FOR_HID_REPORT_TO_BE_SENT:
if (appdata.SendbufferEmpty == TRUE) // Did EventHandler Set the flag?
commdata.state = DATA_SENT: // If so, the data was sent
break ;

case DATA_SENT:

}
}

 Learn More

 
Harmony USB Device Architecture Tutorial
Learn more >
 
Example Code and Projects
Learn more >
© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.