USB HID mouse

Published: February 2011

After reading the book USB complete: everything you need to develop custom USB peripherals I started to develop USB peripherials. The first test, a simple HID mouse.

USB Stack & HID Class Stack

The generic USB code just manages the interrupts generated by the USB SIE and processes the common USB requests like Set_Address and Get_Descriptor. Whenever a class-specific request is sent the generic stack asks the specific class for an answer.

How HID works

A HID device has one IN interruption endpoint and optionally and after 1.1 version can have an OUT interrupt endpoint. Those endpoints are used to send and receive HID reports periodically. I'm not going to go deep in that aspect as many websites tell the same, I'll explain things that aren't found so easily.

A report can be sent and received by using the interrupt endpoints and the control endpoint 0 by making use of the Get_Report/Set_Report class specific request (look at bmRequestType for request type and bRequest for the request number). Usually hosts use the interrupt endpoints instead of using the control endpoint for all report transfer because it's better (speed and bandwidth!) so I don't implement the report feeding at EP0. But there's also the feature reports which are less used (hadn't seen any) and can only be transferred using the EP0.

Usually devices don't use report IDs. Those IDs allow the device to only transfer pieces of the data instead of transferring the entire block of data. The IDs are defined at the report descriptor and the Set/Get Report requests use the wValue0 value in the Setup Packet for specifying the desired report. And here comes the not-widely-known thing: if using the interrupt endpoint the report ID is the first byte of the data received or sent (in case we actually use the IDs, in other case the report ID byte is missing). I quote from the book: "In an interrupt transfer, if the interface supports more than one report ID, the report ID precedes the report data on the bus. If the interface supports only the default report ID of zero, the report ID isn’t sent with the report when using interrupt transfers."

Demo code & circuit

Here it is some demo code which emulates a HID mouse with 8 buttons and 2 axis. At the time of writing I use 5 buttons to emulate the UP/DOWN/LEFT/RIGHT movement and the remaining one to emulate the first button of the eight buttons (right mouse button for friends).



Circuit picture

(As you can see I started playing with wireless!)

Download sources