-
Notifications
You must be signed in to change notification settings - Fork 0
USBX demo device hid Keyboard
MAY edited this page Dec 15, 2025
·
2 revisions
- Purpose: Demonstrates a USB HID Keyboard device implemented with Eclipse ThreadX USBX.
- Variants: demo_device_hid_keyboard_rtos.c and demo_device_hid_keyboard_standalone.c.
-
Targets: MCU platforms with a USB Device Controller (e.g., STM32H7). Platform glue is provided by your board layer via
board_setup()andusb_device_dcd_initialize().
- Device role: Enumerates as a HID Keyboard on a host PC.
- Typing demo: Periodically sends key codes (6-key rollover array) to the host.
- LED feedback: Host can control LEDs (Num Lock, Caps Lock, etc.) via Output reports handled in callbacks.
-
Boot subclass: Optional (
DEMO_HID_BOOT_DEVICE); enable for BIOS/UEFI compatibility.
-
RTOS: demo_device_hid_keyboard_rtos.c — uses ThreadX (
tx_kernel_enter,tx_application_define,ux_utility_thread_create). -
Standalone: demo_device_hid_keyboard_standalone.c — uses USBX standalone scheduler (
ux_system_tasks_run) andux_demo_device_hid_task()in the main loop.
- Define
UX_DEVICE_SIDE_ONLY. - Provide platform functions:
board_setup()andusb_device_dcd_initialize(void*)(DCD/PHY clocks, GPIO, interrupts, VBUS, etc.). - Link against Eclipse ThreadX USBX device stack and the device controller driver for your MCU.
- ThreadX kernel port for your MCU; call
tx_kernel_enter()inmain()and implementtx_application_define()to initialize USBX and start the HID thread.
- Define
UX_STANDALONE. - Set
UX_PERIODIC_RATEto 1000 (1ms tick) in your configuration if not already. - In
main(), runux_system_tasks_run()repeatedly and callux_demo_device_hid_task().
- VID/PID: 0x070A / 0x4090 (sample values; adjust for your product).
-
EP0: 64 bytes (
UX_DEMO_MAX_EP0_SIZE = 0x40). - Configuration: 1 interface, self-powered, max power 100 mA.
- Interface: HID, Subclass Boot (optional), Protocol 0x01 (Keyboard).
-
Endpoint: Interrupt IN
0x81, packet size 8,bInterval = 8(FS 8ms/HS 16ms effective). - HID Report: 8-bit modifiers, 1 reserved byte, 6-key rollover array; LED Output bits with padding.
- Modifiers: 8 bits (Left/Right Ctrl/Shift/Alt/GUI), logical 0..1.
- Reserved: 1 byte.
- Key Array: 6 bytes (6-key rollover), key codes in Usage Page Keyboard (0..101).
- LED Output: 5 bits (Num, Caps, Scroll, Compose, Kana), then 3 bits padding to byte align.
- Resulting report layouts:
- Input (to host): [Byte0] Modifiers, [Byte1] Reserved, [Byte2..7] 6-key array.
- Output (from host): [Byte0] LED bits (Num=bit0, Caps=bit1, …), [Byte1] padding.
Keyboard HID report bytes
/* hid_keyboard_report[] */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xA1, 0x01, // COLLECTION (Application)
/* Modifiers */
0x05, 0x07, // USAGE_PAGE (Key Codes)
0x19, 0xE0, // USAGE_MINIMUM (Left Control)
0x29, 0xE7, // USAGE_MAXIMUM (Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8) -> 8 modifiers
0x81, 0x02, // INPUT (Data,Var,Abs)
/* Reserved byte */
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x01, // INPUT (Constant)
/* Key array (6-key rollover) */
0x05, 0x07, // USAGE_PAGE (Key Codes)
0x19, 0x00, // USAGE_MINIMUM (0)
0x29, 0x65, // USAGE_MAXIMUM (101)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x00, // INPUT (Data, Array)
/* LED outputs */
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x05, // REPORT_COUNT (5)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
/* LED padding */
0x75, 0x03, // REPORT_SIZE (3)
0x95, 0x01, // REPORT_COUNT (1)
0x91, 0x01, // OUTPUT (Constant)
0xC0 // END_COLLECTION- Device descriptor:
-
bcdUSB = 0x0200(USB 2.0), class/subclass/protocol = 0 (interface-defined). -
bMaxPacketSize0 = 64. -
idVendor = 0x070A,idProduct = 0x4090(demo values),iManufacturer = 1,iProduct = 2,iSerialNumber = 3. -
bNumConfigurations = 1.
-
- Device qualifier descriptor (HS build): mirrors device characteristics for the other speed.
- Configuration descriptor:
-
wTotalLength = 0x22(34 bytes across config + interface + HID + endpoint). -
bmAttributes = 0xC0(self-powered),bMaxPower = 0x32(100 mA units of 2 mA). -
bNumInterfaces = 1,bConfigurationValue = 1.
-
- Interface descriptor:
-
bInterfaceClass = 0x03(HID),bInterfaceSubClass= Boot ifDEMO_HID_BOOT_DEVICE,bInterfaceProtocol = 0x01(Keyboard). -
bNumEndpoints = 1(INT IN).
-
- HID descriptor:
-
bcdHID = 0x0110(HID 1.11),bCountryCode = 33(US),bNumDescriptors = 1. - Report descriptor type
0x22, length matchessizeof(hid_keyboard_report).
-
- Endpoint descriptor (Interrupt IN):
-
bEndpointAddress = 0x81(IN, EP1),bmAttributes = 0x03(Interrupt). -
wMaxPacketSize = 8bytes. -
bInterval = 8→ FS: 8 ms; HS: 16 ms.
-
USB Device descriptor framework (FS)
/* Device descriptor */
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB (2.00)
0x00, // bDeviceClass (interface-defined)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 (64)
0x0A, 0x07, // idVendor (0x070A)
0x90, 0x40, // idProduct (0x4090)
0x00, 0x00, // bcdDevice
0x01, // iManufacturer
0x02, // iProduct
0x03, // iSerialNumber
0x01, // bNumConfigurations
/* Configuration */
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x22, 0x00, // wTotalLength (34)
0x01, // bNumInterfaces
0x01, // bConfigurationValue
0x04, // iConfiguration
0xC0, // bmAttributes (self-powered)
0x32, // bMaxPower (100 mA)
/* Interface */
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber
0x00, // bAlternateSetting
0x01, // bNumEndpoints
0x03, // bInterfaceClass (HID)
0x01, // bInterfaceSubClass (Boot) if enabled
0x01, // bInterfaceProtocol (Keyboard)
0x06, // iInterface
/* HID */
0x09, // bLength
0x21, // bDescriptorType (HID)
0x10, 0x01, // bcdHID (1.10)
0x21, // bCountryCode (US)
0x01, // bNumDescriptors
0x22, // bReportDescriptorType
/* wDescriptorLength (report size) inserted here: LSB,MSB at build time */
0x00, 0x00,
/* Endpoint (IN) */
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN, EP1)
0x03, // bmAttributes (Interrupt)
0x08, 0x00, // wMaxPacketSize (8)
0x08, // bInterval (8)USB Device descriptor framework (HS)
/* Device descriptor */
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB (2.00)
0x00, // bDeviceClass (interface-defined)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 (64)
0x0A, 0x07, // idVendor (0x070A)
0x90, 0x40, // idProduct (0x4090)
0x00, 0x00, // bcdDevice
0x01, // iManufacturer
0x02, // iProduct
0x03, // iSerialNumber
0x01, // bNumConfigurations
/* Device Qualifier */
0x0A, // bLength
0x06, // bDescriptorType (Device Qualifier)
0x00, 0x02, // bcdUSB (2.00)
0x00, // bDeviceClass (interface-defined)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 (64)
0x01, // bNumConfigurations
0x00, // bReserved
/* HS Configuration */
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x22, 0x00, // wTotalLength (34)
0x01, // bNumInterfaces
0x01, // bConfigurationValue
0x05, // iConfiguration (sample HS index)
0xC0, // bmAttributes (self-powered)
0x19, // bMaxPower (100 mA)
/* Interface */
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber
0x00, // bAlternateSetting
0x01, // bNumEndpoints
0x03, // bInterfaceClass (HID)
0x01, // bInterfaceSubClass (Boot) if enabled
0x01, // bInterfaceProtocol (Keyboard)
0x06, // iInterface
/* HID */
0x09, // bLength
0x21, // bDescriptorType (HID)
0x10, 0x01, // bcdHID (1.10)
0x21, // bCountryCode (US)
0x01, // bNumDescriptors
0x22, // bReportDescriptorType
/* wDescriptorLength (report size) inserted by build: LSB,MSB */
0x00, 0x00,
/* Endpoint (IN) */
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN, EP1)
0x03, // bmAttributes (Interrupt)
0x08, 0x00, // wMaxPacketSize (8)
0x08, // bInterval (8)-
board_setup()→ clocks, pins, cache, UART (optional), USB power. -
tx_kernel_enter()→ ThreadX start. -
tx_application_define():-
ux_system_initialize()with a static pool (UX_DEVICE_MEMORY_STACK_SIZE, default 7 KB). -
ux_device_stack_initialize()with HS/FS device + string frameworks. - HID class register:
_ux_system_slave_class_hid_name→ux_device_class_hid_entrywith callbacks. - Create demo thread →
ux_demo_device_hid_thread_entry().
-
- In thread:
-
usb_device_dcd_initialize(UX_NULL)to register the DCD. - When configured (
UX_DEVICE_CONFIGURED) and instance ready, send keyboard input reports.
-
-
board_setup(). -
ux_application_define():- Same USBX init + HID registration as RTOS variant.
-
usb_device_dcd_initialize(UX_NULL).
-
main()loop:-
ux_system_tasks_run(); callux_demo_device_hid_task()to emit keyboard input reports when configured.
-
-
ux_demo_device_hid_instance_activate: Stores the class instance pointer on activation so the app can send input reports viaux_device_class_hid_event_set()once the device is configured. -
ux_demo_device_hid_instance_deactivate: Clears the stored instance on deactivation to prevent sending after disconnect or configuration change. -
ux_demo_device_hid_callback: Handles host-to-device HID Output/Feature reports. Parse LED bits inevent->ux_device_class_hid_event_buffer[0]and update flags (e.g.,caps_lock_flag,num_lock_flag). -
ux_demo_device_hid_get_callback: Provides device-to-host data for GET_REPORT if needed; usually not required for boot keyboards. -
ux_demo_error_callback: Registered viaux_utility_error_callback_register()for diagnostics.
Notes:
- The sample sets ux_device_class_hid_parameter_report_id = UX_FALSE (single report, no Report ID byte). If you enable report IDs, ensure buffers account for the extra ID prefix.
- Keep callbacks non-blocking; offload work to a thread/task or main loop.
-
UX_DEVICE_MEMORY_STACK_SIZE(default 7*1024). -
DEMO_HID_BOOT_DEVICE: enable for BIOS/UEFI compatibility. - Key cadence/delay: adjust demo timing (e.g., periodic delay) to control typing rate.
- To optimize your application, user can flow this defines config in
ux_user.h
#define UX_DEVICE_ENDPOINT_BUFFER_OWNER 1
#define UX_DEVICE_CLASS_HID_ZERO_COPY
#define UX_DEVICE_CLASS_HID_EVENT_BUFFER_LENGTH 8
#define UX_DEVICE_CLASS_HID_MAX_EVENTS_QUEUE 2
#define UX_DEVICE_ALTERNATE_SETTING_SUPPORT_DISABLE
#define UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE
#define UX_MAX_DEVICE_ENDPOINTS 1 /* Interrupt endpoint. */
#define UX_MAX_DEVICE_INTERFACES 1 /* HID interface. */
#define UX_MAX_SLAVE_INTERFACES 1
#define UX_MAX_SLAVE_CLASS_DRIVER 1
#define UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH 64 /* > 62 for descriptors enumeration. */
#define UX_SLAVE_REQUEST_DATA_MAX_LENGTH 8
#define UX_NAME_REFERENCED_BY_POINTER- On connection to a PC, the device enumerates as “HID Keyboard Demo”.
- Periodically sends key codes (e.g., 'a' key code
0x04) in the input report; host displays characters accordingly. - Caps/Num Lock LEDs update on the device when the host toggles them via Output report.
- Ensure your DCD driver and low-level BSP match your MCU and USB instance (FS/HS, ULPI/Embedded PHY).
- Provide proper NVIC priorities and ISR bindings for the DCD driver.
- For HS with external PHY, verify 60 MHz ULPI clock and VBUS sensing.
- Toolchain/IDE: IAR EWARM, Keil uVision, or Arm GCC + CMake/Ninja.
- Include ThreadX and USBX sources/ports for your Cortex-M core.
- Add one of the demo sources to your application and ensure:
-
UX_DEVICE_SIDE_ONLY(andUX_STANDALONEfor the standalone variant). - Board layer implements
board_setup()andusb_device_dcd_initialize().
-
Example minimal main (RTOS variant is self-contained in the sample): see demo_device_hid_keyboard_rtos.c.
- Not enumerating:
- Check D+ (FS) or HS PHY signals and power; verify
usb_device_dcd_initialize()registers the controller. - Confirm
UX_DEVICE_CONFIGUREDbecomes true; inspectux_demo_error_callback()logs.
- Check D+ (FS) or HS PHY signals and power; verify
- No characters or incorrect keys:
- Verify key codes in the 6-byte array and modifier bits; ensure correct HID Usage IDs.
- Ensure report length and endpoint configuration match the host expectations.
- LED not toggling:
- Confirm Output report handling in
ux_demo_device_hid_callback()updates LED flags and any GPIOs.
- Confirm Output report handling in
- USBX code repository: https://github.com/eclipse-threadx/usbx/
- USBX Documentation: https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/usbx/overview-usbx.md