Wow, my AVR ATtiny USB tutorial here I got featured in Hack a Day! Motivated by the influx of readers, I decided to find out how to make a USB HID (human interface device) mouse.
V-USB examples already contain an example of this, so I digged in to see what is different in usbconfig.h compared to the one we finished in my tutorial. It seems only a few things need changing:
USB_CFG_HAVE_INTRIN_ENDPOINTneeds to be set to have an additional endpointUSB_CFG_INTR_POLL_INTERVALset to 100 ms instead of 10 in templateUSB_CFG_IMPLEMENT_FN_WRITEis not needed, nor is …FN_READ (define both to 0)- Device ID and name need to be changed. I’ll just use the same ID as they did
USB_CFG_DEVICE_CLASSis set to 0, not 0xffUSB_CFG_INTERFACE_CLASSset to 3 instead of 0USB_CFG_HID_REPORT_DESCRIPTOR_LENGTHdefined to match the structure’s length
That’s it! So here are the defines I changed:
#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 #define USB_CFG_INTR_POLL_INTERVAL 100 #define USB_CFG_IMPLEMENT_FN_WRITE 0 #define USB_CFG_IMPLEMENT_FN_READ 0 #define USB_CFG_DEVICE_ID 0xe8, 0x03 #define USB_CFG_DEVICE_NAME 'M', 'o', 'u', 's', 'e' #define USB_CFG_DEVICE_NAME_LEN 5 #define USB_CFG_DEVICE_CLASS 0 #define USB_CFG_INTERFACE_CLASS 3 #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 52
OK. So what about main.c? Turns out the changes are rather straightforward:
- Report descriptor is defined for our HID device, outlining a simple mouse status report
- The described struct for the report is implemented
- Make the device to respond to a few required request
- In the main loop, when ever USB interrupt is ready, send our report buffer
That’s actually it. The V-USB example uses a nice 10.6 fixed point sine and cosine to draw circles with the mouse, but I chose to have some erratic motion with a pseudo-random number generator. Note that with a bit of extra motion and erratic mouse clicks, you could really drive a user insane!
You can find the complete main.c (as well as usbconfig.h and the schematic) from this project zip file and study the usbHidReportDescriptor (just a string of numbers) and usbFunctionSetup() (really straightforward) on your own, but here’s the “meat” of the code – report structure and new main function inner loop:
typedef struct{
uchar buttonMask;
char dx;
char dy;
char dWheel;
} report_t;
// ...
int main() {
int rand = 1234; // initial value
// ...
while(1) {
wdt_reset(); // keep the watchdog happy
usbPoll();
if(usbInterruptIsReady()) { // if the interrupt is ready, feed data
// pseudo-random sequence generator, thanks to Dan Frederiksen @AVRfreaks
// http://en.wikipedia.org/wiki/Linear_congruential_generator
rand=(rand*109+89)%251;
// move to a random direction
reportBuffer.dx = (rand&0xf)-8;
reportBuffer.dy = ((rand&0xf0)>>4)-8;
usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
}
}
}
Thanks for reading! I might do a USB keyboard tomorrow, so I do recommend checking back soon or subscribing to the RSS feed. :)
Update: I didn’t make a USB keyboard tutorial after all, but opted instead to make a USB password generator. However, I recently stumbled upon this nice post that covers USB keyboards with V-USB and Arduino, so it might be worth to check it out:
http://petrockblog.wordpress.com/2012/05/19/usb-keyboard-with-arduino-and-v-usb-library-an-example/

Posted by
Tagged with:
Driving an LCD display directly with ATtiny

Xiangrui:
February 13, 2012 at 19:48
This is very nice series. Thanks. I wonder whether it is easy to program a generic HID device to do something like flashing an LED. The advantage of HID is host driver free. Some toolkit, like Psychtoolbox for Matlab, has OS-independent HID support.
jokkebk:
February 13, 2012 at 21:22
@Xiangrui
Thanks! And yes, I think there’s an example in V-USB bundle on how to use HID descriptors for driver-less data. It’s definitely less of a hassle without drivers. :)
utkarsh singhal:
March 15, 2012 at 0:48
great tutorial indeed!however,i have some doubts.is it possible for the mouse pointer to go to specified coordinates, like 255,10 ?and is it possible to read the coordinates of mouse pointer?also,is it possible to read the resolution of screen,like it’s width and height in pixels?please answer :-)
jokkebk:
March 15, 2012 at 0:55
@utkarsh: I actually do not know, you probably need to read the USB HID specification and see if it is possible to give absolute coordinates or read the coordinates – I would assume such a thing would be possible as Wacom-type tablets at least support absolute positioning.
But of course it’s also possible that such additional control over the cursor would require PC-side drivers, Wacom at least has some that you use to tweak the settings.
utkarsh singhal:
March 15, 2012 at 11:38
thanks for the reply!well,is there a way to store the id of host computer to permanent memory?if yes,then how?this is because it is possible,we can calibrate the device once and use the presets next time.
reportbuffer.dx must update some variable,to change the pointer position.if we can directly get that variable,we would know of the position.to get the screen size,we could use calibration technique.we could keep giving dx and dy negative values,which would eventually send the pointer to (0,0).at that particular movement,the user will push a calibration button on the device,which will take another variables x=0 and y=0,count the no. of steps taken in the process,and thus calculate no. of pixels moved ,thus calculating screen size.how’s that?but it will be a lot easier if we could just read the pointer position…….again,thanks!
jokkebk:
March 15, 2012 at 12:00
@utkarsh: The HID mouse implemented in this example is not able to receive any identification info from PC, so storing calibrated values is out of the question. It seems absolute positioning is possible (I just googled for “usb hid mouse absolute”), you might want to check out this thread, one of the guys even posted links to a project where he made a working device with absolute coordinates:
http://forums.obdev.at/viewtopic.php?f=8&t=2559
utkarsh singhal:
March 15, 2012 at 12:20
thanks for quick reply!i am actually working on touchscreen interface,so this might help!hey,how about co-developing the device?it is a new technology,sure is revolutionary.with the idea i have,we can turn any computer into a touchsrceen computer,in less than $10 !!!
utkarsh singhal:
March 15, 2012 at 12:43
just imagine the huge potential of this technology.touchscreen interfaces will become as common as mice!gone will be days of big clunky mice.the technology will require just a small setup,cheaper than $10!!!!everything,from laptops,to desktops computers,to phones,will have OUR technology.
jokkebk:
March 15, 2012 at 13:24
@utkarsh: Thanks for the offer, but I think I will pass this time. :) Good luck with the project in any case!
utkarsh singhal:
March 15, 2012 at 13:49
ok,no problem! :)
jobin:
April 2, 2012 at 7:04
Can you please help me with the way in which hid mouse conveys data with pc .. Like a sample of code for exchanging the change in x and y coordinates
jokkebk says:
April 3, 2012 at 0:08
The data is sent using the reportBuffer structure, which has members dx, dy, buttonMask and dWheel. dx and dy are differential coordinates, i.e. if you want to move the mouse 5 pixels up, you set reportBuffer.dy = -5 in one report. To keep the mouse still, you’d do this:
reportBuffer.dx = 0;
reportBuffer.dy = 0;
You should be able to locate the lines where the example code changes reportBuffer pretty easily. Good luck!
Florian:
May 29, 2012 at 20:26
Hi,
I enjoyed reading your tutorials a lot! I have just found your blog and I will definitely follow your posts.
Thank you for mentioning my article in your post above :-)
Andrew:
June 2, 2012 at 9:59
THE F I WANT IT!!!!!!!!!!!!!!!
but I don’t have the materials
- Eagle monster – 12 year old, high school student
Ghassi:
June 30, 2012 at 15:56
hi
i’m trying to make an touch mouse ,
i use a touch pad and with its output and using ADC . provide dx and dy
but it dosent work
windows dos not recognize my mouse,
can you help me ?
jokkebk says:
July 7, 2012 at 9:52
I’d recommend that you first try to make the “random mouse mover” circuit described in the tutorial, and after that works, combine it with the touch pad functionality. The USB hardware part is sometimes tricky, so having a 1:1 reference usually helps to spot small mistakes. Software side has the same thing, so it’s often easier to take something that works and gradually adapt it so you’ll see what change “breaks” the code.
One possible reason for the mouse not working is if usbPoll() is not called often enough – the communication drops if you have something that takes too long between the polls.
haitham:
August 3, 2012 at 0:37
when i activate end point 3 it shows error in device manager ?
How can i handle interrupt out using HID
Eng.Haitham Khairy
Egypt
haitham:
August 3, 2012 at 0:47
i found the answer
first you need to declare in usb configuration . follow these steps:
1- go to usbdrv.c
2- find this line: PROGMEM char usbDescriptorConfiguration[] = { /* USB configuration descriptor */
3- add seven bites to the length of descriptor as followed in this line:
18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + (USB_CFG_DESCR_PROPS_HID & 0xff) +7, 0, //I added las +7
4-now you need to add one ondpoint . find this line and add 1:
USB_CFG_HAVE_INTRIN_ENDPOINT + 1 , /* endpoints excl 0: number of endpoint descriptors to follow */ // I added last +1
5-now at the end of descriptor add these codes to make a new OUT endpoint:
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
(char)0×01, /* OUT endpoint number 1 */ //instead of 81
0×03, /* attrib: Interrupt endpoint */
8, 0, /* maximum packet size */
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
You need also to configure your driver to use this interrupt-OUT no-1
6- now go to usbconfig.h and set USB_CFG_IMPLEMENT_FN_WRITEOUT to 1
7- find this line:
#if USB_CFG_IMPLEMENT_FN_WRITEOUT
if(usbRxToken < 0×10){ /* endpoint number in usbRxToken */
and change it to this:
if(usbRxToken == USBPID_OUT){ /* endpoint number in usbRxToken *///*
8-every time device receives Interrupt-out, goes into usbFunctionWriteOut()
tell me if it works for you
John Jennings:
April 1, 2013 at 21:53
Nice series. Thanks a lot.