Adding HID interface

Now I have a composite device in my STM32F4 Discovery board. It contains a USB Audio 1.0 interface (speaker) and a MIDI (in&out) interface. I need a convenient way to send the speed, direction from the Tascam unit, and other debug data for the mouse application to my laptop than MIDI. I can write my own Windows program for HID communication easier than one for MIDI. And on the other side, for the future, HID will be a better way of communication with DJ programs. So let’s move on to add HID in and out.

I need to initialize interrupt endpoints for HID. Need to append the HID descriptors to the current Audio+MIDI descriptor set. I also need to make an HID Report Descriptor for my desired data structure. I need to modify the Setup stage, because I need to return this Report Descriptor for the appropriate Get_Descriptor request. And don’t forget to allocate TX FIFO for the new endpoint. Mainly these are the steps. After the MIDI interface it is easy. I put everything into usbd_audio.c and header files as I did with the MIDI.

Report Descriptor:

I had the most problems with a correct report descriptor. Windows did not recognized my device for a while. I only want to send 4 bytes Input and receive 4 bytes Output (Report ID+3 byte data). No mouse or keyboard, just general custom HID reports. Finally I successfully made a working descriptor. I will polish it later. I might not need the report ID as I only have one data structure to send or receive.

0x06, 0xFF, 0x00,      /* USAGE_PAGE (Vendor Page: 0xFF00) */
0x09, 0x01,            /* USAGE              */
0xa1, 0x01,            /* COLLECTION (Application)       */

0x85, 0x01,  /*     REPORT_ID (1)             */
0x09, 0x01,            /*     USAGE                  */
0x15, 0x00,            /*     LOGICAL_MINIMUM (0)        */
0x26, 0xff, 0x00,      /*     LOGICAL_MAXIMUM (255)        */
0x75, 0x08,            /*     REPORT_SIZE (8)            */
0x95, 0x03,                         /*     REPORT_COUNT (3)           */
0x91, 0x00,            /*     OUTPUT   */

0x85, 0x02,   /*     REPORT_ID (2)              */
0x09, 0x02,            /*     USAGE            */
0x15, 0x00,            /*     LOGICAL_MINIMUM (0)        */
0x26, 0xff, 0x00,      /*     LOGICAL_MAXIMUM (255)      */
0x75, 0x08,            /*     REPORT_SIZE (8)            */
0x81, 0x00,            /*     INPUT */

0xc0                      /*     END_COLLECTION                 */

It is important, to count the Report ID into the total amount of data and buffer size. So in the code I use 4bytes, the first on is the ID. IT is also important to add USAGE local items to each report, because otherwise windows won’t recognize the device.

Issues and performance:

I was worried about the performance. I nearly in the limit of the processor’s USB Full Speed endpoints. And i have a lot of things to do in a 1ms rate. Receiving 384 bytes of audio. Sending and receiving 32byte bulk MIDI and now the HID with 1ms refresh rate with 4bytes in, 4 bytes out. I tested almost the worst case. I configured to receive the 384 bytes of audio and send a MIDI packet for button push, and a HID packet each SysTick (1ms).

And  I experienced some problems. After a while, the audio interface crashed.  I analyzed this issue, and captured the moment of crash with USBee. The reason is Data_Out interrupt is not generated anymore for my audio isochronous endpoint. However the my laptop still sends audio packet and acts like there’s no problem on the device side.


The cause of the problem:

In my theory, the probem is with the timing of the HID report (SysTick) compared to the Data_out (USB clock domain). A clock domain problem again. In the zoomed waveform I can see that each HID report is sent out after the Data_out interrupt completed. Because the USB core schedules them into the same USB frame I think. Thats OK. It works correctly in the beginning. I issue a HID write command with every SysTick, and it completes every USB frame. There is a constant time difference or phase between SysTick and USB Out interrupt. But then something happens. And the the code Issues a HID write in a completely different phase. It is very close to the end of the frame. The HID write completes, but the Data Out stage interrupt stops. The HID is still working.

It can be seen on the zoomed waveform here:


It is 15us before the end of the USB frame.

I have no solution yet. In the next step, I’m going to schedule the HID and MIDI packets. I won’t use the SysTick interrupt as a time reference for my code. I will use the USB Data Out interrupt instead. I hope this way, I’m going to have a fix time slot for MIDI and HID sending. The main complication is when i’m not playing any music on my laptop, there is no USB Data Out interrupt on the Audio interface, and thus I cannot schedule the HID and MIDI. I will figure out how to overcome this problem.

Happy New Year! 🙂


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s