USB Host PID D-Input Rumble: Block Load Feature Report returns all zeros on PXN V9 Gen2 using STM32 USBH
- Device Under Test: PXN V9 Gen2 Steering Wheel (operating in native D-Input mode)
-
Hardware Platform: STM32F446RE Nucleo Board acting as a USB Host.
-
Toolchain: STM32CubeIDE.
-
Driver Framework: Custom embedded USB Host HID stack implemented by extending and adapting the native
usbh_hid.clibrary provided by the STM32Cube firmware package. -
Analysis Tools: Wireshark with a USBPcap
I am attempting to initialize a force feedback (rumble) effect sequence from the STM32 host. According to the USB PID specification, the transaction sequence rules:
-
Send Create New Effect Report (Report ID 0x05) via a Control Out transfer.
-
Read PID Block Load Report (Report ID 0x06) via a Control In transfer to retrieve the allocated
Effect Block Index.
The Symptom: When performing the Control In transfer to fetch Report ID 0x06, the data payload returned to the STM32 memory buffer is entirely filled with 0x00 bytes instead of a valid allocation status or a non-zero block index handle. No asynchronous data packets are visible or triggered on the Interrupt IN pipe either
The Result
DEBUG : [FFB] Actuators enabled
DEBUG : [FFB] Create Effect sent
[FFB] Block Load: 00 00 00 00
[FFB] Index=0 Status=0
ERROR: [FFB] Error state
what i expect
Upon receiving a valid Create New Effect command, the steering wheel's internal PID state engine should populate the PID Block Load Report (0x06) with a Block Load Success status flag (logical value mapping within 1–3) and provide a valid Effect Block Index handle (between 1 and 14). This token is required so the host application can proceed with downloading force parameters.
-
Why not use X-Input? While X-Input handles rumble seamlessly out of the box via simple Xbox packet emulation, the hardware has a strict limitation in that mode: the external H-pattern gear shifter attachment fails to transmit correct positional data. In X-Input, it only flags center-top and bottom inputs, missing the left-top and right-top gates entirely. Native D-Input implementation is required to read the full layout of the shifter.
-
Descriptor Verification: Prior to writing the firmware, I audited the HID report descriptor (extract attached below) captured via Wireshark. I confirmed that both Report ID 0x05 and Report ID 0x06 are strictly classified as Feature Reports.
Capture HID Report
Usage (Create New Effect Report)
Collection (Logical)
Report ID (0x05)
Usage (Effect Type)
Collection (Logical)
Usage (ET Constant Force)
Usage (ET Ramp)
Usage (ET Square)
Usage (ET Sine)
Usage (ET Triangle)
Usage (ET Sawtooth Up)
Usage (ET Sawtooth Down)
Usage (ET Spring)
Usage (ET Damper)
Usage (ET Inertia)
Usage (ET Friction)
Usage (ET Custom Force Data)
Logical Maximum (12)
Logical Minimum (1)
Physical Minimum (1)
Physical Maximum (12)
Report Size (8)
Report Count (1)
Feature (Data,Array,Abs)
End Collection
Usage Page (Generic Desktop Controls)
Usage (Byte Count)
Logical Minimum (0)
Logical Maximum (511)
Physical Minimum (0)
Physical Maximum (511)
Report Size (10)
Report Count (1)
Feature (Data,Var,Abs)
Report Size (6)
Feature (Const,Array,Abs)
End Collection
Usage Page (Physical Interface Device (PID))
Usage (PID Block Load Report)
Collection (Logical)
Report ID (0x06)
Usage (Effect Block Index)
Logical Maximum (14)
Logical Minimum (1)
Physical Minimum (1)
Physical Maximum (14)
Report Size (8)
Report Count (1)
Feature (Data,Var,Abs)
Usage (Block Load Status)
Collection (Logical)
Usage (Block Load Success)
Usage (Block Load Full)
Usage (Block Load Error)
Logical Maximum (3)
Logical Minimum (1)
Physical Minimum (1)
Physical Maximum (3)
Report Size (8)
Report Count (1)
Feature (Data,Array,Abs)
End Collection
Usage (RAM Pool Available)
Logical Minimum (0)
Logical Maximum (65535)
Physical Minimum (0)
Physical Maximum (65535)
Report Size (16)
Report Count (1)
Feature (Data,Array,Abs)
End Collection
The Question
- Is there an explicit vendor-defined handshake or standard state command (such as sending a
PID Device Controlon Report ID 0x0c withDC Enable Actuators) that must be dispatched by the STM32 host before the internal allocation mechanism responds on Report ID 0x06?
