USB-HID on a USBASP Board

Implementing USB-HID on a reprogrammed USBASP AVR Programmer Board

The USBASP programmer for AVR microcontrollers (https://www.fischl.de/usbasp/) is a simple circuit board containing an ATMega8 microcontroller, some USP support components, a couple of LEDs and a 10 pin connector. They can be found on ebay for less than $2 but the best part is that they are easily re-programmed (so buy two or more). Link to excellent user’s guide : https://protostack.com.au/download/Users%20Guide%20(AC-PG-USBASP-UG-V2.0).pdf

I recently investigated using the HID (Human Interface Device) USP protocol to communicate between this device and my PC.

Now it’s time to share and hopefully make life easier for others trying to do the same.

The USP specification is hugely complicated and I’ll admit to understanding only a very small bit of it.
But through examples I found online I am able to get the basics working and put together this demo project.
What you’ll need is a couple of these devices (you can also use an Arduino as a programmer if you like)
You’ll also want to download and install the WinAVR compiler (https://sourceforge.net/projects/winavr/) and CodeBlocks (http://www.codeblocks.org/downloads) the GCC compiler for the PC.

Choose one of your USBASP boards to be the target device and jumper J2 (the Self Program jumper)

One of the trickier parts I encountered with this project were defining the proper HID Report Descriptor.

Here’s an example:

PROGMEM char usbHidReportDescriptor[43] = {

0x06, 0x00, 0xFF, // USAGE_PAGE (Generic Desktop)

0x09, 0x01, // USAGE (Vendor Usage 1)

0xA1, 0x01, // COLLECTION (Application)

0x15, 0x00, // LOGICAL_MINIMUM (0)

0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255)

0x75, 0x08, // REPORT_SIZE (8 bits)

// 14 bytes Feature report#1 ( 8 bytes sent to/from host)

0x85, 0x01, // Global Report ID (cannot be 0) Command Report 8 bytes + ID

0x95, 0x08, // Global Report Count 8 (number of Report Size fields)

0x09, 0x00, // Usage Undefined

0x15, 0x00, // Local Usage Minimum (each Report Count must be associated with a Usage)

0x26, 0xFF, 0x00, // Local Usage Maximum

0xB2, 0x02, 0x01, // Main Feature (Data,Var,Abs,Buf)

// 28 bytes Feature report#2 ( 16 bytes sent to/from host)

0x85, 0x02, // Global Report ID (cannot be 0) Data Report 16bytes + ID

0x95, 0x10, // Global Report Count 16 (number of Report Size fields)

0x09, 0x00, // Usage Undefined

0x15, 0x00, // Local Usage Minimum (each Report Count must be associated with a Usage)

0x26, 0xFF, 0x00, // Local Usage Maximum

0xB2, 0x02, 0x01, // Main Feature (Data,Var,Abs,Buf)

// 42 buytes

0xC0 // END_COLLECTION

};

This defines 2 feature reports, #1 is 8 bytes and #2 is 16 bytes. The details can be found (if you’re brave)

here http://www.usb.org/developers/docs/

The total size of the descriptor is 43 bytes and if you change it (by adding another report for instance) you need to also update this line in usbconfig.h

#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 43

Another thing that I discovered was critical was the length of the data request for both send and receive.
In this example we’re using report IDs (1 or 2) so the MUST be the first byte in any batch of date we send.
We also need to adjust the size of the message to accommodate this ID so the length MUST be increased by 1 byte, 9 for Report ID#1 and 17 for Report ID#2. Any other value will simply cause the request to fail.

What this demo does is simply send the hex bytes you enter from the PC to the device (SET). When you request data from the device (GET) it should send back what you last sent it. If you have a serial terminal attached to the UART on the device, you’ll see messages confirming the communications.
You can try the Terminal Mode option to send keystrokes between the PC and a serial terminal.

So what’s all this mean?

What I imagined (and later used in another project) was using the 8 byte report to send commands to the device. If a reply was involved and it was small, it could get returned in the 8 byte report otherwise one or more 16 byte reports could be requested.

Let’s say you had a button connected to one of the I/O pins and the device was measuring the time between each press of the button. We could send an 8 byte report from the host with the second byte (remember the first byte holds the report ID) set to a code (let’s use 5) that tells the device to load the most recent 16 readings into the 16 byte report buffer on the device. Then the host sends a request for the 16 byte report and get the contents of the recently loaded values.

The schematic attached bellow shows that, in the version 2.0 build, you should have access to six I/O pins plus VCC and GND.

Here's what they are:

Sadly none of these are analog (ADC) pins. However JP3 gives you access to PC2 / (ADC2) and with careful soldering you should be able to make connections to any of the other (9 more) unused I/O pins on the ATMega8.

The code for this project is available for download via a link posted below.

USBASP v2.0 Schematic

USBASP V2.0 Connector Pins

Host (PC) Session example

Terminal Session Example

Download Links:

HIDData16.zip The .zip archive contains the files to re-program the USBASP board.

The HID_Host16 subfolder contains the CodeBlocks project to build the PC demo application.

The HID_Host16 subfolder also contains the HID_Host16.exe executable. (keep this structure)