Search code examples
usbhidstm32f1

HID REPORT is not aligned with the bytes


I'm currently creating a HID device with a STM32 to work with windows, and I struggle a lot with the Report. I always have an "this device cannot start - error 10, the report is not aligned with the bytes" (well it is directly translated from french, not sure if it could be say as so in english).

My report is as below

__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
  /* USER CODE BEGIN 0 */
  0x05, 0x01,    //         UsagePage(Generic Desktop[0x0001])
  0x09, 0x07,    //         UsageId(Keypad[0x0007])
  // Block of usage
  0xA1, 0x01,    //         Collection(Application)
  0x85, 0x01,    //         ReportId(1)
  0x05, 0x09,    //         UsagePage(Button[0x0009])
  0x19, 0x01,    //         UsageIdMin(Button 1[0x0001])
  0x29, 0x17,    //         UsageIdMax(Button 23[0x0017])
  0x15, 0x00,    //         LogicalMinimum(0)
  0x25, 0x01,    //         LogicalMaximum(1)
  0x75, 0x17,    //         ReportSize(1)
  0x95, 0x1,    //          ReportCount(23)
  0x81, 0x02,    //         Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField)
  // usage page for other elements (leds or encoders)
  0x95, 0x01,    //         ReportCount(1)
  0x75, 0x06,    //         ReportSize(23)
  0x81, 0x03,    //         Input(Constant, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField)
  /* USER CODE END 0 */
  0xC0    /*     END_COLLECTION              */
};

i defined my report as 31 Bytes length (same for the buffer).

But it does not work and as a noob i still do not know why..

thanks for looking


Solution

  • I have access to a PC now. I think your issue is that you have defined a 23-bit field followed by a 6-bit pad giving a total width of 29 bits which is not a multiple of 8-bits.

    Try redefining your report descriptor as follows:

    __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
    {
      /* USER CODE BEGIN 0 */
      0x05, 0x01,    //         UsagePage(Generic Desktop[0x0001])
      0x09, 0x07,    //         UsageId(Keypad[0x0007])
      // Block of usage
      0xA1, 0x01,    //         Collection(Application)
      0x85, 0x01,    //         ReportId(1)
      0x05, 0x09,    //         UsagePage(Button[0x0009])
      0x19, 0x01,    //         UsageIdMin(Button 1[0x0001])
      0x29, 0x17,    //         UsageIdMax(Button 23[0x0017])
      0x15, 0x00,    //         LogicalMinimum(0)
      0x25, 0x01,    //         LogicalMaximum(1)
      0x75, 0x01,    //         ReportSize(1)
      0x95, 0x17,    //         ReportCount(23)
      0x81, 0x02,    //         Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField)
      // usage page for other elements (leds or encoders)
      0x95, 0x01,    //         ReportCount(1)
      0x81, 0x03,    //         Input(Constant, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField)
      /* USER CODE END 0 */
      0xC0    /*     END_COLLECTION              */
    };
    

    Note that each report size is now 1 bit, but there are 23 button bits and 1 pad bit giving a total of 24 bits (3 bytes). The 1-byte report id prepends the report giving a total buffer size (i.e. structure size) of a nice round 4 bytes.

    When I decode that using hidrdd I get:

    //--------------------------------------------------------------------------------
    // Decoded Application Collection
    //--------------------------------------------------------------------------------
    
    /*
    05 01        (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page 
    09 07        (LOCAL)  USAGE              0x00010007 Keypad (Application Collection)  
    A1 01        (MAIN)   COLLECTION         0x01 Application (Usage=0x00010007: Page=Generic Desktop Page, Usage=Keypad, Type=Application Collection)
    85 01          (GLOBAL) REPORT_ID          0x01 (1)  
    05 09          (GLOBAL) USAGE_PAGE         0x0009 Button Page 
    19 01          (LOCAL)  USAGE_MINIMUM      0x00090001 Button 1 Primary/trigger (Selector, On/Off Control, Momentary Control, or One Shot Control)  
    29 17          (LOCAL)  USAGE_MAXIMUM      0x00090017 Button 23 (Selector, On/Off Control, Momentary Control, or One Shot Control)  
    15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0)  <-- Info: Consider replacing 15 00 with 14
    25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)  
    75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field  
    95 17          (GLOBAL) REPORT_COUNT       0x17 (23) Number of fields  
    81 02          (MAIN)   INPUT              0x00000002 (23 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields  
    81 03          (MAIN)   INPUT              0x00000003 (1 field x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    C0           (MAIN)   END_COLLECTION     Application 
    */
    
    // All structure fields should be byte-aligned...
    #pragma pack(push,1)
    
    //--------------------------------------------------------------------------------
    // Button Page inputReport 01 (Device --> Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x01 (1)
                                                         // Collection: CA:Keypad
      uint8_t  BTN_KeypadButton1 : 1;                    // Usage 0x00090001: Button 1 Primary/trigger, Value = 0 to 1
      uint8_t  BTN_KeypadButton2 : 1;                    // Usage 0x00090002: Button 2 Secondary, Value = 0 to 1
      uint8_t  BTN_KeypadButton3 : 1;                    // Usage 0x00090003: Button 3 Tertiary, Value = 0 to 1
      uint8_t  BTN_KeypadButton4 : 1;                    // Usage 0x00090004: Button 4, Value = 0 to 1
      uint8_t  BTN_KeypadButton5 : 1;                    // Usage 0x00090005: Button 5, Value = 0 to 1
      uint8_t  BTN_KeypadButton6 : 1;                    // Usage 0x00090006: Button 6, Value = 0 to 1
      uint8_t  BTN_KeypadButton7 : 1;                    // Usage 0x00090007: Button 7, Value = 0 to 1
      uint8_t  BTN_KeypadButton8 : 1;                    // Usage 0x00090008: Button 8, Value = 0 to 1
      uint8_t  BTN_KeypadButton9 : 1;                    // Usage 0x00090009: Button 9, Value = 0 to 1
      uint8_t  BTN_KeypadButton10 : 1;                   // Usage 0x0009000A: Button 10, Value = 0 to 1
      uint8_t  BTN_KeypadButton11 : 1;                   // Usage 0x0009000B: Button 11, Value = 0 to 1
      uint8_t  BTN_KeypadButton12 : 1;                   // Usage 0x0009000C: Button 12, Value = 0 to 1
      uint8_t  BTN_KeypadButton13 : 1;                   // Usage 0x0009000D: Button 13, Value = 0 to 1
      uint8_t  BTN_KeypadButton14 : 1;                   // Usage 0x0009000E: Button 14, Value = 0 to 1
      uint8_t  BTN_KeypadButton15 : 1;                   // Usage 0x0009000F: Button 15, Value = 0 to 1
      uint8_t  BTN_KeypadButton16 : 1;                   // Usage 0x00090010: Button 16, Value = 0 to 1
      uint8_t  BTN_KeypadButton17 : 1;                   // Usage 0x00090011: Button 17, Value = 0 to 1
      uint8_t  BTN_KeypadButton18 : 1;                   // Usage 0x00090012: Button 18, Value = 0 to 1
      uint8_t  BTN_KeypadButton19 : 1;                   // Usage 0x00090013: Button 19, Value = 0 to 1
      uint8_t  BTN_KeypadButton20 : 1;                   // Usage 0x00090014: Button 20, Value = 0 to 1
      uint8_t  BTN_KeypadButton21 : 1;                   // Usage 0x00090015: Button 21, Value = 0 to 1
      uint8_t  BTN_KeypadButton22 : 1;                   // Usage 0x00090016: Button 22, Value = 0 to 1
      uint8_t  BTN_KeypadButton23 : 1;                   // Usage 0x00090017: Button 23, Value = 0 to 1
      uint8_t  : 1;                                      // Pad
    } inputReport01_t;
    
    #pragma pack(pop)