cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F469 HID - add a keyboard to a custom HID

Jerry Hancock
Associate II

I have my custom HID device running and working fine. I would like it to also emulate a standard PC keyboard at the same time. So when my board enumerates, I would like the attached PC to find my custom device as well as a keyboard.

I think I can just add another device config descriptor, interface and end points to the existing custom HID descriptors and then add another report descriptor for the keyboard. Please confirm.

I then tried of setting up two complete sets of descriptors and calling USBD_init, USBD_RegisterClass and USBD_Start for each set of descriptors. I tried this and was never able to get the keyboard to enumerate, could be any of many reasons. Also, it looked like it was killing the first device, my custom HID.

Not being sure how to do this, I would appreciate advice. If both ways would work, then I guess I would use the first as it would require fewer lines of code.

I hesitate to try to the first way I described above as adding all the device descriptors, etc, are a lot of work to get them all aligned.

Thank you.

Jerry

28 REPLIES 28
Pavel A.
Evangelist III

You can do it in two ways:

A. The simplest way: one HID device with multiple top level collections.

This takes only creating a HID report descriptor with two (or more if you want) top level collections, one of these will be the keyboard. Add the report ID to your reports to differentiate keyboard reports from others. All reports go thru one endpoint.

B. Composite (multi-function) device. This is preferred with old or dumb hosts that do not understand HID collections.

Find a example project named "USB Composite device" or so.

This requires one endpoint per function. Each function will be a separate USB interface, so you need to create two or more interface descriptors per USB configuration. Each interface will have class HID and its own HID report descriptor. The keyboard should be defined as legacy-compatible, unless you need otherwise.

in this case, each function has its own endpoint to send reports so no report IDs are needed.

-- pa

Jerry Hancock
Associate II

Pavel, thanks for the quick reply.

I am leaning and looking at your example A. The issue I see is that when the device enumerates, there is a function called USBD_HID_Setup. In this function, depending on the request, the code returns the Custom Report descriptor. Do I need to modify this code to then return the second report descriptor for the keyboard device? or do I just lump them together and depending on the length of the report descriptor as defined in the relevant HID descriptor, the PC would figure out which one is which?

So my Config descriptor would have:

Custom type 02 with 2 interfaces

Custom type 04 for interface 1

Custom type 21 for HID descriptor with length of custom report descriptor for the 04 report

Custom type 05 endpoint input 0x81

custom type 05 endpoint output 0x01

keyboard type 04 for interface 2

Keyboard type 21 for HID descriptor with length of keyboard report descriptor for the 06 report

keyboard type 05 endpoint input 0x81

My custom report descriptor uses a type 0x04. A keyboard descriptor is a type 06. I've seen examples of Mouse + keyboard that just lumps the two together and I don't see how the USBD_Init_setup returns them correctly.

Or am I confused?

thanks,

Jerry

Jerry Hancock
Associate II

OK, I think I have the descriptors setup, at least the PC is reading them. It isn't recognizing the keyboard as a keyboard though. I am using tdd.exe to dump the descriptor and it looks ok with the exception of the text strings.

when I trace the keyboard device I get what looks like correct data on the trace but I must be sending it using the wrong interface because the characters seem to be being read as if they are coming from my custom device.

I am closer than I've been. I still think it has something to do with the wrong report descriptor being sent? any pointers?

Thanks!

Jerry Hancock
Associate II

OK, pulling my hair out. no errors and the descriptors look fine, at least I think they do. The PC isn't recognizing the second device as a keyboard for some reason. And when I send a report with the ReportID = 0x01 for the keyboard, the 0x01 isn't being stripped off.

I had a problem where the keyboard report id was specified correctly in the descriptor so I had an error during enumeration to that effect. So I think I fixed that problem. Now I just end up with mutiple HID devices opposed to an HID and a Keyboard.

Any ideas?

Thanks for reading.

Jerry

Jerry Hancock
Associate II

sorry for rambling on, but I think the last problem which might be a show stopper is that my custom device uses a unique VID/PID and is picked up by the application. So don't I have to have a separate VID/PID for my keyboard device? If that is the case, then I need another device descriptor, correct?

What's the best way to handle this then? Can I just have two completely separate sets of files, codes, etc and initialize them sequentially?

I hope there is a way around this. I see when the second device is enumerated that it picks up the same VID/PID from the common class structure. My application shows the custom HID and the keyboard HID as two custom HIds instead of one custom plus a keyboard.

Darn, so close...I have another way to handle the buttons but not nearly as elegant as this solution. When I get this working, the 8 buttons on my custom device will act as the keyboard function keys F1 to F8 making an external keyboard redundant for certain key functions.

Thanks,

Jerry

Ben K
Senior III

The VID and PID are part of the device descriptor, which is unique per physical device. A device can have multiple configurations, and each configuration can have multiple interfaces (including HID). Each HID interface can define multiple top-level collections.

In more practical terms, if you want your HID keyboard to be always recognized properly by the OS, you have to go for the composite device option (1 configuration with 2 HID interfaces). This is the way most modern keyboards operate, they have a standard 102 key keyboard interface, and they also have another interface which sends consumer controls such as volume +/-, media play/pause, sleep, etc.

The only problem is, composite devices aren't supported by the ST firmware package. You could use this library: https://github.com/IntergatedCircuits/USBDevice , but it needs some porting to work in HAL context.

Jerry Hancock
Associate II

Ben, thanks, I saw that library mentioned in a prior thread​. I was also thinking of modifying the cubex code that returns the descriptors to sequentially return the correct vid, pid, etc. So when my custom hid is enumerated I return one address and the keyboard another. So worst case is that the user would have to replug or reset the board if the application is restarted. Also, the SDR this plugs into isn't that picky.

I'll look at the other library to see if I can use it with HAL. I'm learning more every day about USB.

Thanks

Jerry​

Ben K
Senior III

If you don't want to use both HID interfaces at the same time, then you can have two entirely different device definitions with separate VID:PID, and switch between the two with soft disconnect (disabling and enabling the DP line pull-up). Then each device uses only one interface, and I guess the Cube code can solve this.

Jerry Hancock
Associate II

technically, the HID interfaces are not used concurrently. I have an encoder and keyboard. The user can turn the encoder or press the keyboard. As long as the delay isn't significant (go thru enumeration, for instance) and I can activate the HID encoder interface or keyboard interface in lets say 10ms, then that would be fine.

As per my message to you, I need two devices enumerated as the custom HID (encoder) has a unique VID/PID compared to a keyboard. My composite device doesn't work for some reason. It seems to enumerate correctly but in my application I get two copies of the encoder (one for the encoder and the second for the keyboard on the same address). I can live with this two address issue but the HIDCTRL.DLL being used by the application doesn't recognize the keyboard, only the encoder but since it is the same address as the encoder, the application grabs it instead of letting windows treat it as a keyboard device, I assume.

I downloaded the library you mentioned and don't see how it would be any different. In my message I also mentioned I have F7 boards that have both HS and FS ports and I think they can be used at the same time and would present different addresses for VID/PID depending on the code, of course.

Does this make sense or am I missing something? I am new to USB coding. By the way, the encoder I am emulating has three buttons that work fine but If I send it another button using the same endpoint number but different report ID in outbuffer[0], the SDR goes into transmit for some reason. Can't have that!

Thanks

Jerry