USB HID Mouse
This example controls the data reported to the PC via USB to change the direction and position of the cursor on the PC monitor.
Requirements
The sample supports the following development kits:
Hardware Platforms |
Board Name |
---|---|
RTL87x2G HDK |
RTL87x2G EVB |
For more requirements, please refer to: Quick Start
Configurations
The example configurable macros are as follows:
DLPS_EN
: Configure this macro to select whether or not the USB enters DLPS after the SUSPEND state,1
means DLPS is allowed,0
means DLPS is not allowed.REMOTE_WAKEUP_EN
: Configure this macro to select whether or not to configure the Remote Wakeup test process,1
indicates that Remote Wakeup is configured, and0
indicates that Remote Wakeup is not configured.
Note
If REMOTE_WAKEUP_EN
is set to 1, connect P0_6 and VCC, press the reset button to re-initialise the IC, and wait for the PC to enter into the sleep state and then connect P0_6 and VDD, you can observe that the screen of the PC is illuminated, which means that the Remote Wakeup is successful.
Building and Downloading
This sample can be found in the SDK folder:
Project file: samples\module_sample\usb\usb_hid_mouse\proj\mdk
Project file: samples\module_sample\usb\usb_hid_mouse\proj\gcc
To build and run the sample, follow the steps listed below:
Open the sample project file.
To build the target, follow the steps listed in Generating App Image in Quick Start.
After a successful compilation, the app bin
app_MP_xxx.bin
will be generated in the directorymdk\bin
orgcc\bin
.To download the app bin into the EVB board, follow the steps listed in MP Tool Download in Quick Start.
Press the reset button on the EVB board and it will start running.
Experimental Verification
Code Overview
This chapter will be introduced according to the following several parts:
Peripheral initialization will be introduced in chapter Initialization.
Functional implementation after initialization will be introduced in chapter Functional implementation.
Source Code Directory
Project directory:
sdk\samples\usb\usb_hid_mouse\proj
Source code directory:
sdk\samples\usb\usb_hid_mouse\src
Source files are currently categorized into several groups as below:
└── Project: input_polling
└── secure_only_app
└── Device includes startup code
├── startup_rtl.c
└── system_rtl.c
├── CMSIS includes CMSIS header files
├── CMSE Library Non-secure callable lib
└── Lib includes all binary symbol files that user application is built on
├── usb.lib
└── usb_hal.lib
├── Peripheral includes all peripheral drivers and module code used by the application
└── APP includes the ble_peripheral user application implementation
├── main_ns.c
├── app_task.c
├── app_usb.c
├── usb_dev.c
└── usb_hid.c
Initialization
Call app_usb_init
to initialize the USB module, including: registering the callback function, initializing the USB device and configuration descriptor, initializing the USB interface and endpoints, and initializing the HID.
usb_dm_cb_register(app_usb_dm_cb);
usb_spd_cb_register(app_usb_spd_cb);
T_USB_CORE_CONFIG config = {.speed = USB_HIGH_SPEED, .class_set = {.hid_enable = 1, .uac_enable = 0}};
usb_dm_core_init(config);
usb_dev_init();
usb_hid_init();
app_usb_start();
app_usb_init
contains the following flow:
usb_dm_cb_register()
: Register callback function for USB dynamic management to implement viewing the current USB status inapp_usb_dm_cb
.typedef enum { USB_PDN = 0, USB_ATTACHED = 1, USB_POWERED = 2, USB_DEFAULT = 3, USB_ADDRESSED = 4, USB_CONFIGURED = 5, USB_SUSPENDED = 6, } T_USB_POWER_STATE;
Note
For the Configurations of USB status, refer to Troubleshooting.
usb_spd_cb_register()
: Register callback function to obtain USB speed: It is possible to receive information on whether the currently enumerated USB speed is Full Speed or High Speed.usb_dm_core_init()
: Set USB speed and the required USB functionality: Set the speed to USB_HIGH_SPEED and set hid_enable to 1.usb_dev_init
: Initialize the USB device-related descriptors.static T_USB_DEVICE_DESC usb_dev_desc = { // The following items are defined in device descriptor. .idVendor = 0x0bda, .idProduct = 0x8762, .bcdDevice = 0x0200, .iManufacturer = STRING_ID_MANUFACTURER, .iProduct = STRING_ID_PRODUCT, .iSerialNumber = STRING_ID_SERIALNUM, } static T_USB_CONFIG_DESC usb_cfg_desc = { // The following items are defined in config descriptor. .bNumInterfaces = 2, .bmAttributes = 0xA, // remote wake up .bcdDevice = 0x0200, .bMaxPower = 0x32, // The unit is 2mA }
Note
For the Configurations of USB descriptors, refer to Troubleshooting.
usb_hid_init
: initialize USB HID descriptors and register callback functions.Configure USB HID interface, endpoint descriptors, and report descriptors.
The interface descriptor is set as follows:
static T_USB_INTERFACE_DESC hid_std_if_desc = { .bLength = sizeof(T_USB_INTERFACE_DESC), .bDescriptorType = USB_DESC_TYPE_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_CODE_HID, .bInterfaceSubClass = 1, // Is boot interface supported .bInterfaceProtocol = 2, .iInterface = 0, };
The endpoint descriptor is set as follows:
static T_USB_ENDPOINT_DESC int_in_ep_desc_fs = { .bLength = sizeof(T_USB_ENDPOINT_DESC), .bDescriptorType = USB_DESC_TYPE_ENDPOINT, .bEndpointAddress = USB_DIR_IN | 0x01, .bmAttributes = USB_EP_TYPE_INT, .wMaxPacketSize = 0x40, .bInterval = 1, }; static T_USB_ENDPOINT_DESC int_in_ep_desc_hs = { .bLength = sizeof(T_USB_ENDPOINT_DESC), .bDescriptorType = USB_DESC_TYPE_ENDPOINT, .bEndpointAddress = USB_DIR_IN | 0x01, .bmAttributes = USB_EP_TYPE_INT, .wMaxPacketSize = 0x40, .bInterval = 4, };
The HID descriptor is set as follows:
static T_HID_CS_IF_DESC hid_cs_if_desc = { .bLength = sizeof(T_HID_CS_IF_DESC), .bDescriptorType = DESC_TYPE_HID, .bcdHID = 0x0110, .bCountryCode = 0, .bNumDescriptors = 1, .desc[0] = { .bDescriptorType = DESC_TYPE_REPORT, .wDescriptorLength = sizeof(report_descs), }, };
The HID report descriptor is set as follows:
static const char report_descs[] = { 0x06, 0x0B, 0xFF, // Usage Page (Vendor Defined 0xFF0B) 0x0A, 0x04, 0x01, // Usage (0x0104) 0xA1, 0x01, // Collection (Application) // 8-bit data 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8) 0x95, 0x3c, // Report Count (60) 0x85, REPORT_ID_CFU_FEATURE, // Report ID (0x2A) 0x09, 0x60, // Usage (0x60) 0x82, 0x02, 0x01, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Buffered Bytes) 0x09, USAGE_ID_CFU_PAYLOAD_OUTPUT, // Usage (0x61) 0x92, 0x02, 0x01, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes) 0x09, USAGE_ID_CFU_FEATURE, // Usage (0x62) 0xB2, 0x02, 0x01, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes) 0x85, REPORT_ID_CFU_FEATURE_EX, // Report ID (0x2B) 0x09, USAGE_ID_CFU_FEATURE_EX, // Usage (0x65) 0xB2, 0x02, 0x01, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes) // 32-bit data 0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483649) 0x27, 0xFF, 0xFF, 0xFF, 0x7F, // Logical Maximum (2147483646) 0x75, 0x20, // Report Size (32) 0x95, 0x04, // Report Count (4) 0x85, REPORT_ID_CFU_PAYLOAD_INPUT, // Report ID (0x2C) 0x19, USAGE_ID_CFU_PAYLOAD_INPUT_MIN,// Usage Minimum (0x66) 0x29, USAGE_ID_CFU_PAYLOAD_INPUT_MAX,// Usage Maximum (0x69) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x85, REPORT_ID_CFU_OFFER_INPUT, // Report ID (0x2D) 0x19, USAGE_ID_CFU_OFFER_INPUT_MIN, // Usage Minimum (0x8A) 0x29, USAGE_ID_CFU_OFFER_INPUT_MAX, // Usage Maximum (0x8D) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x19, USAGE_ID_CFU_OFFER_OUTPUT_MIN,// Usage Minimum (0x8E) 0x29, USAGE_ID_CFU_OFFER_OUTPUT_MAX,// Usage Maximum (0x91) 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) main item*/ 0x09, 0x02, /* USAGE (Mouse) */ 0xa1, 0x01, /* COLLECTION (Application) */ 0x85, MOUSE_REPORT_ID, /* REPORT_ID (2) */ 0x09, 0x01, /* USAGE (Pointer) */ 0xa1, 0x00, /* COLLECTION (Physical) */ 0x05, 0x09, /* USAGE_PAGE (Button) */ 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ 0x29, 0x05, /* USAGE_MAXIMUM (Button 5) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 0x95, 0x05, /* REPORT_COUNT (5) */ 0x75, 0x01, /* REPORT_SIZE (1) */ 0x81, 0x02, /* INPUT (Data,Var,Abs) */ 0x95, 0x01, /* REPORT_COUNT (1) */ 0x75, 0x03, /* REPORT_SIZE (3) */ 0x81, 0x01, /* INPUT (Cnst,Var,Abs) */ 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) main item*/ 0x09, 0x30, /* USAGE (X) */ 0x09, 0x31, /* USAGE (Y) */ 0x16, 0x01, 0x80, /* LOGICAL_MINIMUM (-32767) */ 0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (32767) */ 0x75, 0x10, /* REPORT_SIZE (16) */ 0x95, 0x02, /* REPORT_COUNT (2) */ 0x81, 0x06, /* INPUT (Data,Var,Rel) */ 0x09, 0x38, /* USAGE (Wheel) */ 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x95, 0x01, /* REPORT_COUNT (1) */ 0x81, 0x06, /* INPUT (Data,Var,Rel) */ 0x05, 0x0c, /* USAGE_PAGE (Consumer)*/ 0x0a, 0x38, 0x02, /* USAGE (AC Pan) */ 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x95, 0x01, /* REPORT_COUNT (1) */ 0x81, 0x06, /* INPUT (Data,Var,Rel) */ 0xc0, /* END_COLLECTION */ 0xc0, /* END_COLLECTION */ 0x06, 0x01, 0xff, /* USAGE_PAGE (vendor) */ 0x09, 0x01, /* USAGE (vendor) */ 0xa1, 0x01, /* COLLECTION (Application) */ 0x85, VENDOR_REPORT_ID, /* REPORT_ID (0x10) */ 0x19, 0x00, /* USAGE_MINIMUM (0) */ 0x29, 0xff, /* USAGE_MAXIMUM (0xff) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (0xff) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x95, 0x04, /* REPORT_COUNT (4) */ 0x81, 0x02, /* INPUT (Data,Var,Abs) */ 0xc0, /* END_COLLECTION */ };
Registering callback functions for USB interface related requests.
T_USB_HID_DRIVER_CBS cbs; cbs.get_report = usb_hid_get_report; cbs.set_report = usb_hid_set_report; cbs.get_protocol = usb_hid_get_protocol; cbs.set_protocol = usb_hid_set_protocol; cbs.get_idle = usb_hid_get_idle; cbs.set_idle = usb_hid_set_idle; usb_hid_driver_cbs_register(inst, &cbs);
Initialize USB HID driver.
app_usb_start
: Call the app_usb_start function to start the USB task.To control the mouse to send data, it is possible to call
app_cfu_usb_send_data
to upload the data to the PC.app_cfu_usb_send_data
has three parameters: USB report ID, data pointer, and data length.The initial call to this function requires a
app_cfu_tpl_open
to initialize the USB cache queue for report data.
bool app_cfu_usb_send_data(uint8_t report_id, uint8_t *data, uint16_t len) { uint8_t *header = NULL; uint16_t data_len = sizeof(report_id) + len; bool ret = false; header = malloc(data_len); if (!header) { APP_PRINT_ERROR0("app_cfu_usb_send_data: no memory for data"); return ret; } header[0] = report_id; memcpy(&header[1], data, len); app_cfu_xmit(header, data_len); free(header); return ret; }
Functional Implementation
After initializing USB, call the app_cfu_usb_send_data
function to report the data to the PC.
uint8_t Report[7] = {0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t ReportLen = 7;
app_cfu_usb_send_data(0x01, Report, ReportLen);
Troubleshooting
USB Status Notes
USB_PDN
: Default state after USB power-up.USB_ATTACHED
: Enabled USB but did not turn on the USB clock.USB_POWERED
: Enabled and turned on the USB clock.USB_ADDRESSED
: The USB device has been assigned an address.USB_CONFIGURED
: The USB device has been configured, entering this state, generally considered USB enumeration is successful.USB_SUSPENDED
: The USB device has entered the suspend state.
USB Device Descriptor
- idVendor
Set idVendor as 0x0bda. The vendor ID number has a length of two bytes, and in this example, 0x0bda has been selected as the vendor ID number.
- idProduct
Set idProduct as 0x8762. The product ID number has a length of two bytes, and in this example, 0x8762 has been selected as the product ID number.
- bcdDevice
Set bcdDevice as 0x0200. The device’s version number has a length of 2 bytes, and in this example, 0x0200 has been selected as the version number. When the same product is upgraded, the device’s version number can be modified to distinguish it.
- pManufacturerStr
Set pManufacturerStr as RealTek. This parameter is a string that describes the manufacturer.
- pProductStr
Set pProductStr as USB HID Device. This parameter is a string that describes the product.
- pSerialNumberStr
Set pSerialNumberStr as L"0123456789A". This parameter is a string that describes the device’s serial number.
USB Configuration Descriptor
- bNumInterfaces
Set pNumInterfaces as 2, i.e. This device supports 2 interfaces.
- bmAttributes
Set bmAttributes as 0xA0, i.e. This device supports remote wakeup feature.
- bMaxPower
Set bMaxPower as 0x32, i.e. The device draws a maximum current of 100mA from the bus, with a unit of 2mA.