This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430f550x Keyboard HID

Hi,

I have been trying to conver the USB HID Mouse example to a Keyboard HID, and have hit a bit of a wall.
I found this useful document that discusses this process on another MCU.

Working my way through it I have updated all the descriptors, and report formats, but so far have not been able to get Keyboard working.  The one thing I did notice is that on the MSP430 Mouse example the bDeviceProtocol is actually set to 0 (None) where it should be 2 for Mouse and 1 for keyboard.  Am I missing anything here?

Anyway, has anyone else successfully converted the HID Mouse example to HID Keyboard, or can anyone point me in the firection of other code I need to work through.

Many thanks!!

Rob.

  • > I found this useful document that discusses this process on another MCU.

    Thanks, I'm glad to hear my post is useful for you.

    > The one thing I did notice is that on the MSP430 Mouse example the bDeviceProtocol is actually set to 0 (None) where it should be 2 for Mouse and 1 for keyboard.

    Ah, I didn't write on this issue on above post.

    Maybe you refer to the triad (bInterfaceClass / bInterfaceSubclass / bInterfaceProtocol), on the interface descriptor.

    bInterfaceSubclass / bInterfaceProtocol fields are seen only by BIOS, just after PC powers up. BIOS recognizes a HID device as mouse or keyboard according to these fields.

    When OS runs after BIOS, these fields are ignored. HID class driver on the OS reads out the report descriptor on the device. The USAGE of the Top-Level Collection on the report descriptor determines the type of the HID device.

    > Working my way through it I have updated all the descriptors, and report formats, but so far have not been able to get Keyboard working.

    Delete old device instance(s) on Windows, whenever you change any descriptor of your device. OR, assign a new VID/PID (at least new PID) to the device.

    Windows hold device instance(s) on the registry for each USB device, which keep the information of descriptors. Device instance is indexed with VID/PID. Device instance is made at the first plug-in of the device, and it isn't updated when you change the descriptors. Therefore, modification of descriptors on the device causes conflict with the registry.

    To delete device instance, USBDeview is helpful
    http://www.nirsoft.net/utils/usb_devices_view.html

    - Plug-off your device, first. USBDeview lists up all registered USB devices, even without the device plug in.
    - Sort the list on USBDeview by Vendor ID (VID). For HID device, you may find two instances of the VID/PID of your device.
    - Delete (uninstall) all of them, by right click on the line.
    - Plug-in your device, and Windows make new device instance, which reflects updated descriptors.

    Of course, there are many pitfalls in USB device implementation.
    But try this one, first.

    Tsuneo

  • Hi Tsuneo,

    Nice to see you here!  Thanks for you reply, and the info wrt Silabs example.
    Good tip re USBDeview.  I was looking for something like this!  I can confirm that the VID/PID is new on my device.

    The problem is actually more fundamental, as I am ney even getting enumeration.  On windows I get a " ! USB Device Not Recognised" error when plugging in the device with the new keyboard descriptors.  It enumerates ok on Linux, although I get no keyboard data through the pipe.  I think Windows is much stricted on having sensible descriptors so I think the problem must be in there somewhere, but I just can't seem to locate it.

    The mouse example uses 2 endpoints, presumebly 1 for movement and the other for feedback to LED's (if any).   So I would presume that the keyboard also uses two endpoints (1x IN and 1x OUT), again with the OUT for LED's.  I notice that in you Silabs posts you advise to delete the OUT endpoint.  Can I leave this in, and how does it change the descriptors...  I have listed my descriptors below, can you see anything wrong?  I have left out the string descriptors as I'm pretty sure they are good.

    In particular I have changed wTotalLength... I changed it to 59 as it was 41 for mouse.
    Also my report array is now 8byts rather than 4 for mouse....

    Thanks for any help!!!

    Rob.

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    /*-----------------------------------------------------------------------------+
    | Device Descriptor |
    |-----------------------------------------------------------------------------*/

    BYTE

    const

    abromDeviceDescriptor[SIZEOF_DEVICE_DESCRIPTOR] = {
      SIZEOF_DEVICE_DESCRIPTOR,   
    // 0x12 Length of this descriptor
      DESC_TYPE_DEVICE,            // 0x01 Type code of this descriptor
     
    0x00, 0x02,                  //      Release of USB spec
     
    0x00,                        //      Device's base class code
     
    0x00,                        //      Device's sub class code
     
    0x00,                        //      Device's protocol type code
      
    EP0_PACKET_SIZE,             // 0x08 End point 0's packet size
     
    USB_VID&0xFF, USB_VID>>8,    // 0x0471 Vendor ID for device, TI=0x2047
     
    USB_PID&0xFF, USB_PID>>8,    // 0x0206 Product ID for device,
     
    VER_FW_L, VER_FW_H,          // 0x00, 0x02 Revision level of device
     
    1,                           // Index of manufacturer name string desc
     
    2,                           // Index of product name string desc
     
    USB_STR_INDEX_SERNUM,        // 0x03 Index of serial number string desc
     
    1                            // Number of configurations supported
    };

    /*-----------------------------------------------------------------------------+
    | Configuration Descriptor |
    |-----------------------------------------------------------------------------*/

    const

     

     

    /******************************************************* start of HID*************************************/
     
    {
     
    /*start HID[0] Here */
       
    {
         
    //-------- Descriptor for HID class device -------------------------------------
         
         
    // INTERFACE DESCRIPTOR (9 bytes)
         
    SIZEOF_INTERFACE_DESCRIPTOR,    // 0x09 bLength
         
    DESC_TYPE_INTERFACE,            // 0x04 bDescriptorType: 4
         
    HID0_REPORT_INTERFACE,          // 0x00 bInterfaceNumber
         
    0x00,                           // bAlternateSetting
         
    2,                              // bNumEndpoints
         
    0x03,                           // bInterfaceClass: 3 = HID Device
         
    0,                              // bInterfaceSubClass:
         
    0,                              // bInterfaceProtocol:
         
    INTF_STRING_INDEX + 0,          // 0x05 iInterface:1

         
    // HID DESCRIPTOR (9 bytes)
         
    0x09,                           // bLength of HID descriptor
         
    0x21,                           // HID Descriptor Type: 0x21
         
    0x01,0x01,                      // HID Revision number 1.01
         
    0x00,                           // Target country, nothing specified (00h)
         
    0x01,                           // Number of HID classes to follow
         
    0x22,                           // Report descriptor type
         
    (SIZEOF_REPORT_DESCRIPTOR& 0x0ff),   // 63 Total length of report descriptor
         
    (SIZEOF_REPORT_DESCRIPTOR >>8),
         
         
    SIZEOF_ENDPOINT_DESCRIPTOR,     // 0x07 bLength
         
    DESC_TYPE_ENDPOINT,             // 0x05 bDescriptorType
         
    HID0_INEP_ADDR,                 // 0x81 bEndpointAddress; bit7=1 for IN, bits 3-0=1 for ep1
         
    EP_DESC_ATTR_TYPE_INT,          // 0x03 bmAttributes, interrupt transfers
         
    0x40, 0x00,                     // wMaxPacketSize, 64 bytes
         
    1,                              // bInterval, ms

          SIZEOF_ENDPOINT_DESCRIPTOR,    

    // 0x07 bLength
         
    DESC_TYPE_ENDPOINT,             // 0x05 bDescriptorType
         
    HID0_OUTEP_ADDR,                // 0x01 bEndpointAddress; bit7=1 for IN, bits 3-0=1 for ep1
         
    EP_DESC_ATTR_TYPE_INT,          // 0x03 bmAttributes, interrupt transfers
         
    0x40, 0x00,                     // wMaxPacketSize, 64 bytes
         
    1,                              // bInterval, ms

     

    struct abromConfigurationDescriptorGroup abromConfigurationDescriptorGroup=
    {
      
    /* Generic part */
     
    {
       
    // CONFIGURATION DESCRIPTOR (9 bytes)
       
    SIZEOF_CONFIG_DESCRIPTOR,         // 0x09 bLength
        DESC_TYPE_CONFIG,                 // 0x02 bDescriptorType
       
    DESCRIPTOR_TOTAL_LENGTH, 0x00,    // 59   wTotalLength
       
    USB_NUM_INTERFACES,               // 0x01 bNumInterfaces
       
    USB_CONFIG_VALUE,                 // 0x01 bConfigurationvalue
       
    CONFIG_STRING_INDEX,              // 0x04 iConfiguration Description offset
       
    USB_SUPPORT_SELF_POWERED | USB_SUPPORT_REM_WAKE,    // 0x80 bmAttributes, bus power, remote wakeup
       
    USB_MAX_POWER                                       // 0x32 Max. Power Consumption
      },

          /* end of HID[0]*/
       
    }
     
    },
    /******************************************************* end of HID**************************************/
    };

    BYTE

    const abromReportDescriptor[SIZEOF_REPORT_DESCRIPTOR]= // For KEYBOARD
    {
      0x05, 0x01,
    // Usage Pg (Generic Desktop)
     
    0x09, 0x06, // Usage (Keyboard)
     
    0xA1, 0x01, // Collection: (Application)
     
    0x05, 0x07, // Usage Page (Key Codes)
     
    0x19, 0xE0, // Usage Minimum (224)
     
    0x29, 0xE7, // Usage Maximum (231)
     
    0x15, 0x00, // Logical Minimum (0)
     
    0x25, 0x01, // Logical Maximum (1)
     
    0x75, 0x01, // Report Size (1)
     
    0x95, 0x08, // Report Count (8)
     
    0x81, 0x02, // Input (Data, Variable, Absolute) ;Modifier byte
     
    0x95, 0x01, // Report Count (1)
     
    0x75, 0x08, // Report Size (8)
     
    0x81, 0x01, // Input (Constant) ;Reserved byte
     
    0x95, 0x05, // Report Count (5)
     
    0x75, 0x01, // Resport Size (1)
     
    0x05, 0x08, // Usage Page (Page# for LEDs)
     
    0x19, 0x01, // Usage Minimum (1)
     
    0x29, 0x05, // Usage Maximum (5)
     
    0x91, 0x02, // Output (Data, Variable, Absolute) ;LED report
     
    0x95, 0x01, // Report Count (1)
     
    0x75, 0x03, // Report Size (3)
     
    0x91, 0x01, // Output (Constant) ;LED report padding
     
    0x95, 0x06, // Report Count (6)
     
    0x75, 0x08, // Report Size (8)
     
    0x15, 0x00, // Logical Minimum (0)
     
    0x25, 0x65, // Logical Maximum (101)
     
    0x05, 0x07, // Usage Page (Key Codes)
     
    0x19, 0x00, // Usage Minimum (0)
     
    0x29, 0x65, // Usage Maximum (101)
     
    0x81, 0x00, // Input (Data, Array) ;Key arrays (6 bytes)
     
    0xC0 // End Collection
    };

     

  • Quick update...

    I change wTotalLength back to 41, and now the device enumerates...  It's clear I don't understand the point of wTotalLenght.
    However I still do not get any keyboard events.  So please if anyone can take a look at my descriptors aboave and confirm that this should be good for a HID Keyboard?

    Many thanks!
    Rob.

  • Hi Rob,

    1) wTotalLength is no of bytes of configuration descriptor.

    2) In interface descriptor we should give information of bInterfaceprotocol and bInterfaceSubClass.

    bInterfaceSubClass:  1 // 1- for boot interface 0- Report interface

     

    bInterfaceProtocol: 1 // 1: for keyboard

     

    3) In Endpoint descriptors, wMaxPacketSize value  need to change to 8 bytes for Keyboard transaction.

     

    With these changes try once. Hope it will work. 

     

    Regards

    SuryaG

     


     

     


  • Surya Narayana said:
    1) wTotalLength is no of bytes of configuration descriptor.  

    Yep figured that out.  Thanks!

    Surya Narayana said:
     2) In interface descriptor we should give information of bInterfaceprotocol and bInterfaceSubClass.

    bInterfaceSubClass:  1 // 1- for boot interface 0- Report interface

    bInterfaceProtocol: 1 // 1: for keyboard  

    Thanks.  I don't need boot mode, so as Tsueno mentioned the keyboard can be identified by the report descriptor, but I will try this on Monday and see if it helps.

    Surya Narayana said:
     3) In Endpoint descriptors, wMaxPacketSize value  need to change to 8 bytes for Keyboard transaction.

    I was wondering about this.  The 64 was set in the Mouse example, but the Mouse transaction is only 4 bytes.!  Then I saw in the TI MSP430 USB API document that the API has a fixed transaction size of 64, so I just left it.  Although in the code I am only sending 8 bytes to sendReport().

    A little confusing.  Does anyone else know anymore about this?

     

    I'm playing around in the code at the moment, but debugging is tough as it's hard to see if any data is actually going across the bus.

    Are there any host side tools that can "sniff" the USB to look at the report data.

    Thanks again for all you continued help.

    Rob.

  • > I was wondering about this.  The 64 was set in the Mouse example, but the Mouse transaction is only 4 bytes.!

    wMaxPacketSize of endpoint descriptor gives division unit, to divide lengthy transfer into transactions.

    USB is a time-shared bus. Many devices may share single bus using hub. If an endpoint of a device would occupy the bus so long by lengthy transfer, other endpoints of devices should wait for the end of the transfer. To ensure concurrency, lengthy transfer is divided into transactions on the bus. And the endpoints get chance to put a transaction in turn. In this way, USB runs many endpoints of devices concurrently on single bus.

    If you would like to know about transfer and transaction more, read this post.
    http://www.cygnal.org/ubb/Forum9/HTML/001627.html

    For the HID keyboard case,
    If you would set wMaxPacketSize to 1 on the interrupt IN endpoint, the firmware should split the 8-bytes input report into 8 transaction of 1 byte. It's a wasteful implementation. wMaxPacketSize of less than 8 bytes result in similar bad implementation. 8 or more wMaxPacketSize gives single transaction for the 8 bytes report - easy implementation.

    Does wMaxPacketSize of greater than 8 bytes cause any trouble?
    For interrupt and isoc endpoints, host reserves bus bandwidth for these endpoints at enumeration, according to the calculation of wMaxPacketSize / bInterval. In this way, host ensures the periodicity of transactions over these endpoints. On the other hand, host assigns the rest of bandwidth to bulk endpoints. If the interrupt endpoint would claim more than required, bulk endpoints of other devices could get less chance to communicate with.

    In these reasons, just the report size is recommended for the wMaxPacketSize


    > Are there any host side tools that can "sniff" the USB to look at the report data

    These open source sniffers captures traffic after enumeration finishes.
    SnoopyPro http://sourceforge.net/projects/usbsnoop/
    SniffUsb  http://www.pcausa.com/Utilities/UsbSnoop/default.htm

    A couple of commercial software sniffers can capture enumeration sequence, too.
    USBlyzer (33 days trial)  http://www.usblyzer.com/
    USBTrace (15 days trial)  http://www.sysnucleus.com/
    I hope your project finishes before evaluation expires :-)


    Using a sniffer, confirm whether 8 bytes report is sent from the device or not.

    Tsuneo

  • Thanks Tsuneo.

    You are the USB Ninja! :)

    I got it all working yesterday.  My report format was wrong as well as I aws trying to send ASCII chars as the keypress data, rather than the USB usage table data for keyboard.
    On my dev board (MSP-TS430RGC64USB) Switch S1 acts as CAPS LOCK, and S2 acts as NUM LOCK.  LED1 and LED2 act as keyboard LED's for these keys.

    The project is included below for those interested.  TI you are welcome to use this as a generic keyboard HID project for the MSP430 dev kit.

    5736.API Stack_HIDKeyBoard_MSP430F5510.zip

    Thanks & Regards

    Rob.

    PS.  The sniffer tool USBlyzer is very good.  Probably well worth the $200 should I need it post the demo period.

**Attention** This is a public forum