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:

  1. USB_CFG_HAVE_INTRIN_ENDPOINT needs to be set to have an additional endpoint
  2. USB_CFG_INTR_POLL_INTERVAL set to 100 ms instead of 10 in template
  3. USB_CFG_IMPLEMENT_FN_WRITE is not needed, nor is …FN_READ (define both to 0)
  4. Device ID and name need to be changed. I’ll just use the same ID as they did
  5. USB_CFG_DEVICE_CLASS is set to 0, not 0xff
  6. USB_CFG_INTERFACE_CLASS set to 3 instead of 0
  7. USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH defined 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:

  1. Report descriptor is defined for our HID device, outlining a simple mouse status report
  2. The described struct for the report is implemented
  3. Make the device to respond to a few required request
  4. 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/