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:

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:

  1. 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.

  2. 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, and 0 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:

  1. Open the sample project file.

  2. To build the target, follow the steps listed in Generating App Image in Quick Start.

  3. After a successful compilation, the app bin app_MP_xxx.bin will be generated in the directory mdk\bin or gcc\bin.

  4. To download the app bin into the EVB board, follow the steps listed in MP Tool Download in Quick Start.

  5. Press the reset button on the EVB board and it will start running.

Experimental Verification

When the USB data cable of the RTL87x2G development board is plugged into a PC, an additional HID-mouse device will be identified in the mouse section of the Device Manager.
By checking the PID and VID settings of this device, it can be determined whether the USB device connection was successful.
If the x-axis data of the reported data is set to 1, and the function for reporting the data is called multiple times, it can be observed that the mouse continuously moves to the right on the screen.

Code Overview

This chapter will be introduced according to the following several parts:

  1. Source code directory.

  2. Peripheral initialization will be introduced in chapter Initialization.

  3. Functional implementation after initialization will be introduced in chapter Functional implementation.

Source Code Directory

  1. Project directory: sdk\samples\usb\usb_hid_mouse\proj

  2. 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:

  1. usb_dm_cb_register(): Register callback function for USB dynamic management to implement viewing the current USB status in app_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.

  2. 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.

  3. 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.

  4. 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.

  5. usb_hid_init: initialize USB HID descriptors and register callback functions.

    1. Configure USB HID interface, endpoint descriptors, and report descriptors.

      1. 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,
        };
        
      2. 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,
        };
        
      3. 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),
            },
        
        };
        
      4. 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 */
        };
        
    2. 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);
      
    3. Initialize USB HID driver.

  6. app_usb_start: Call the app_usb_start function to start the USB task.

  7. To control the mouse to send data, it is possible to call app_cfu_usb_send_data to upload the data to the PC.

    1. app_cfu_usb_send_data has three parameters: USB report ID, data pointer, and data length.

    2. 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.