Custom Generic USB-HID-Device not reconized

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

//EDIT: See last post #9 for working Program!

 

Hey,

i want to create a Joystick on a xMega32A4U.

i am using the generic HID-Example from ASF  V3.20.1

 

I followed the Quickstart guide and implemented that stuff incl. Clock-Configuration.

Besides that i changed following stuff to fit my needs:

 

Descriptor:

udi_hid_generic.c:

//! HID report descriptor for standard HID generic
UDC_DESC_STORAGE udi_hid_generic_report_desc_t udi_hid_generic_report_desc = { {
			   0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
			   0x09, 0x04,                    // USAGE (Joystick)
			   0xa1, 0x01,                    // COLLECTION (Application)
			   0xa1, 0x00,                    //   COLLECTION (Physical)
			   0x05, 0x09,                    //     USAGE_PAGE (Button)
			   0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
			   0x29, 0x1e,                    //     USAGE_MAXIMUM (Button 30)
			   0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
			   0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
			   0x95, 0x1e,                    //     REPORT_COUNT (30)
			   0x75, 0x01,                    //     REPORT_SIZE (1)
			   0x81, 0x02,                    //     INPUT (Data,Var,Abs)

			   0x75, 0x02,                    //     REPORT_SIZE (2) //dummys to fill byte
			   0x95, 0x01,                    //     REPORT_COUNT (1)
			   0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)

			   0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop) min. 2 Axis for Joystick required
			   0x09, 0x30,                    //     USAGE (X)
			   0x09, 0x31,                    //     USAGE (Y)
			   0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
			   0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
			   0x75, 0x08,                    //     REPORT_SIZE (8)
			   0x85, 0x02,                    //     REPORT_ID (2)
			   0x81, 0x02,                    //     INPUT (Data,Var,Abs)
			   0xc0,                          //     END_COLLECTION
			   0xc0                           // END_COLLECTION
			
		}
};

 

So i have 30 Bits for Buttons, 2 DummyBits to fill and 2x8Byte for two axis, which makes a total of 6 Bytes.

Since i have only in-Reports i deleted references to the out-ep.

 

Set .iface.bNumEndpoints to 1 in UDI_HID_GENERIC_DESC and delete ep.out-stuff:

   .ep_out.bLength             = sizeof(usb_ep_desc_t),\
   .ep_out.bDescriptorType     = USB_DT_ENDPOINT,\
   .ep_out.bEndpointAddress    = UDI_HID_GENERIC_EP_IN,\
   .ep_out.bmAttributes        = USB_EP_TYPE_INTERRUPT,\
   .ep_out.wMaxPacketSize      = LE16(UDI_HID_GENERIC_EP_SIZE),\
   .ep_out.bInterval           = 4,\

Editing the structs and this is the result:

//! Interface descriptor structure for HID generic
typedef struct {
    usb_iface_desc_t iface;
    usb_hid_descriptor_t hid;
    usb_ep_desc_t ep_in;
} udi_hid_generic_desc_t;

//! Report descriptor for HID generic
typedef struct {
    uint8_t buttons_A;
    uint8_t buttons_B;
    uint8_t buttons_C;
    uint8_t buttons_D;
    int8_t x;
    int8_t y;
} udi_hid_generic_report_desc_t;




//! Content of HID generic interface descriptor for all speed
#define UDI_HID_GENERIC_DESC    {\
   .iface.bLength             = sizeof(usb_iface_desc_t),\
   .iface.bDescriptorType     = USB_DT_INTERFACE,\
   .iface.bInterfaceNumber    = UDI_HID_GENERIC_IFACE_NUMBER,\
   .iface.bAlternateSetting   = 0,\
   .iface.bNumEndpoints       = 1,\
   .iface.bInterfaceClass     = HID_CLASS,\
   .iface.bInterfaceSubClass  = HID_SUB_CLASS_NOBOOT,\
   .iface.bInterfaceProtocol  = HID_PROTOCOL_GENERIC,\
   .iface.iInterface          = UDI_HID_GENERIC_STRING_ID,\
   .hid.bLength               = sizeof(usb_hid_descriptor_t),\
   .hid.bDescriptorType       = USB_DT_HID,\
   .hid.bcdHID                = LE16(USB_HID_BDC_V1_11),\
   .hid.bCountryCode          = USB_HID_NO_COUNTRY_CODE,\
   .hid.bNumDescriptors       = USB_HID_NUM_DESC,\
   .hid.bRDescriptorType      = USB_DT_HID_REPORT,\
   .hid.wDescriptorLength     = LE16(sizeof(udi_hid_generic_report_desc_t)),\
   .ep_in.bLength            = sizeof(usb_ep_desc_t),\
   .ep_in.bDescriptorType    = USB_DT_ENDPOINT,\
   .ep_in.bEndpointAddress   = UDI_HID_GENERIC_EP_OUT,\
   .ep_in.bmAttributes       = USB_EP_TYPE_INTERRUPT,\
   .ep_in.wMaxPacketSize     = LE16(UDI_HID_GENERIC_EP_SIZE),\
   .ep_in.bInterval          = 4,\
   }

 

and in usb_conf.h:

//! Device definition (mandatory)
#define  USB_DEVICE_VENDOR_ID             USB_VID_ATMEL
#define  USB_DEVICE_PRODUCT_ID            0x1111
#define  USB_DEVICE_MAJOR_VERSION         1
#define  USB_DEVICE_MINOR_VERSION         0
#define  USB_DEVICE_POWER                 100 // Consumption on Vbus line (mA)
#define  USB_DEVICE_ATTR                  USB_CONFIG_ATTR_BUS_POWERED


//! Sizes of I/O reports
#define  UDI_HID_REPORT_IN_SIZE             6
#define  UDI_HID_REPORT_OUT_SIZE            0
#define  UDI_HID_REPORT_FEATURE_SIZE        4

 

and my main.c looks like this:

http://pastebin.com/fy2KPHeB

 

If i run the software, windows 7 detects and tries to install HID-Input drivers, but fails with Code10.

It's listed under Devices and Printers, but according to state it has a problem, device failed to start.

 

i installed USBlyzer to check the data, it gives following output:

It is may noticeable that "Current configuration" is zero.

 

i would be happy if you could help me to find the error.

i think i need to change more configs, but i'm not sure what and where.

 

Last Edited: Mon. Aug 3, 2015 - 01:23 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Disclaimer: I've never used ASF or XMega.

 

But I have used USB HID Report Descriptors a bit.  So, if you'll allow me to speculate, based on a comparsion of your Report Descriptor to one of mine, I'm wondering why there is no 'REPORT_COUNT' field for the X/Y axes.

 

Also, I've never used 'REPORT_ID', but from a search on my drive for it, I've never seen a 'REPORT_ID' setting of 2 without previously having another 'REPORT_ID' setting of 1.  Is that intentional or an oversight?  Maybe it matters not, but it caught my eye.

 

Of course, the problem may not be the Report Descriptor, but I thought I'd mention those "peculiarities", for whatever it's worth.

 

Regards,

Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, that was indeed a mistake. is should be _COUNT(2) and not _ID(2).

But that was not the main error. 

Still getting "device failed to start"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BurrrY wrote:
Still getting "device failed to start"
Be aware that Windows (Win98 and WinXP for sure, and probably Vista, Win7, and Win8 -- never used those) annoyingly caches the USB HID Report Descriptors in the registry.  So if you ever send it a bad descriptor and then fix it, you need to do one of two things to keep it from using the older, erroneous, cached descriptor:

  1. Delete the cached descriptor from Windows' registry -- a big pain!
  2. Change the Vendor and/or Product ID in your HID Report Descriptor to something that Windows has never seen before (e.g. simply incrementing the Product ID will usually suffice) -- a lesser pain.

HTH...

 

If you get it working, please post the solution here so that future thread searchers can benefit too.

 

Regards,

Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, i already figured this out and tested with different PIDs.

 

If somebody could provide me something like an appNote on how to create own devices, that would be very helpful. Because as far as i can see, there is nothing like this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Upon further examination, I see that you appear to be confusing the USB HID Report Descriptor with the actual USB HID Report.  Your Report Descriptor is 48 bytes, but you're telling the system that it's only 6 bytes.

 

Stated differently, your setup of the 'udi_hid_generic_report_desc_t' is done as if it were a Report (6 bytes) but this is supposed to be the Report Descriptor (48 bytes).  Check the ASF generic HID example code a bit more carefully and I think you'll understand.

 

On a more positive note, your actual USB HID Report Descriptor (with the error fixes we discussed above) does correctly enumerate under Windows and Linux, at least when programmed into my PCB which runs an ATMega168 and V-USB.  So I think you can safely assume that the HID Report Descriptor is no longer the issue.  So if you fix up that other problem, you might have this issue solved.  Good or bad, please let us know the results.

 

HTH....  Good luck!

 

Regards,

Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh, yes, i think i got it.

 

So i changed to this:

//! Report descriptor for HID generic
typedef struct {
    uint8_t array[48];
} udi_hid_generic_report_desc_t;

Because there are 48 bytes in the Descriptor ( UDC_DESC_STORAGE udi_hid_generic_report_desc_t udi_hid_generic_report_desc = { { ... }} ).

 

Now i have to do something like this in the main file:


typedef struct {
	uint8_t buttons_A;
	uint8_t buttons_B;
	uint8_t buttons_C;
	uint8_t buttons_D;
	int8_t x;
	int8_t y;
} hid_generic_reportData_t;

hid_generic_reportData_t *report;

void my_button_press_event(void)
{	
	//set some data according to buttons
	report->buttons_A = 0xAF;

        //send Data
 	udi_hid_generic_send_report_in(report);
}

 

Thanks for your help again. I will test it on sunday, since i'm not at home earlier.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Never having used ASF or XMega, I cannot be 100% sure, but (assuming that you properly allocate storage for the 6-byte report somewhere) that looks much better to my eye.  Looking forward to hearing your results in about a week.  Good luck!

 

Regards,

Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey,

now it seems to work, the device is recognized!

In addition to your advice, i reverted the udi_hid_generic.h to ASF-Standard, in which the Interface-Descripton is given.

This reverted my deleted endpoints. Now i also have the OUT-Endpoint, but i think i just don't use it.

Also the reports are send! You made me Happy :D thanks a lot for you time and work!

 

btw. i've tried that with LUFA-Libs. got that running in 1-2hours, very simple ;) but i'll prefer ASF.

 

Ok, so for anybody who comes here fore help, this is my summary:

(Search by Names in your Project)

 

First, import the USB-Device-service (generic) from ASF-Lib.

 

Then, follow the Quickstart-Guide from Atmel: http://asf.atmel.com/docs/3.5.1/...

 

Then, this are my changes to the code:

Clock_conf:


#ifndef CONF_CLOCK_H_INCLUDED
#define CONF_CLOCK_H_INCLUDED
// USB from the 32MHz RC oscillator, up-scaled to 48MHz
#define CONFIG_USBCLK_SOURCE                USBCLK_SRC_RCOSC
#define CONFIG_OSC_RC32_CAL                 48000000UL

// Enable DFLLs to stabalize RC oscillators
#define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC  OSC_ID_USBSOF
#define CONFIG_OSC_AUTOCAL_RC2MHZ_REF_OSC   OSC_ID_RC32KHZ

// Enable PLL to multiply 2MHz RC oscillator to 32MHz
#define CONFIG_PLL0_SOURCE                  PLL_SRC_RC2MHZ
#define CONFIG_PLL0_MUL                     (32 / 2)
#define CONFIG_PLL0_DIV                     1

// Switch system clock to the internal 2MHz RC oscillator
#define CONFIG_SYSCLK_SOURCE                SYSCLK_SRC_PLL
#define CONFIG_SYSCLK_PSADIV                SYSCLK_PSADIV_1
#define CONFIG_SYSCLK_PSBCDIV               SYSCLK_PSBCDIV_1_1

#endif /* CONF_CLOCK_H_INCLUDED */

 

 

Change the Report Descriptor:


//! HID report descriptor for standard HID generic
UDC_DESC_STORAGE udi_hid_generic_report_desc_t udi_hid_generic_report_desc = { {
			   0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
			   0x09, 0x04,                    // USAGE (Joystick)
			   0xa1, 0x01,                    // COLLECTION (Application)
			   0xa1, 0x00,                    //   COLLECTION (Physical)
			   0x05, 0x09,                    //     USAGE_PAGE (Button)
			   0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
			   0x29, 0x1e,                    //     USAGE_MAXIMUM (Button 30)
			   0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
			   0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
			   0x95, 0x1e,                    //     REPORT_COUNT (30)
			   0x75, 0x01,                    //     REPORT_SIZE (1)
			   0x81, 0x02,                    //     INPUT (Data,Var,Abs)

			   0x75, 0x02,                    //     REPORT_SIZE (2) //dummys to fill byte
			   0x95, 0x01,                    //     REPORT_COUNT (1)
			   0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)

			   0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop) min. 2 Axis for Joystick required
			   0x09, 0x30,                    //     USAGE (X)
			   0x09, 0x31,                    //     USAGE (Y)
			   0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
			   0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
			   0x75, 0x08,                    //     REPORT_SIZE (8)
			   0x95, 0x02,                    //     REPORT_COUNT (2)
			   0x81, 0x02,                    //     INPUT (Data,Var,Abs)
			   0xc0,                          //     END_COLLECTION
			   0xc0                           // END_COLLECTION
			
		}
};

 

Change the Report Descriptor Typedef. Array-Length = Number of Bytes in Report Descriptor

//! Report descriptor for HID generic
typedef struct {
    uint8_t array[48];
} udi_hid_generic_report_desc_t;

Change Sizes of Reports. I've got 32 Bits for Buttons and 2 Bytes for Axis which sums up in 6 Bytes. I don't use the OUT_Report so i set it to zero.


//! Sizes of I/O reports
#define  UDI_HID_REPORT_IN_SIZE             6
#define  UDI_HID_REPORT_OUT_SIZE            0
#define  UDI_HID_REPORT_FEATURE_SIZE        4

//! Sizes of I/O endpoints
#define  UDI_HID_GENERIC_EP_SIZE            64
//@}

Now, my Main is like

int main (void)
{
	// Insert system clock initialization code here (sysclk_init()).

	sysclk_init();
	irq_initialize_vectors();
	cpu_irq_enable();
	board_init();

	udc_start();
	vbus_event(true);

	while(42) {
			my_button_press_event();
			delay_ms(1000);	
			my_button_unpress_event();
			delay_ms(1000);
	}
	// Insert application code here, after the board has been initialized.
}

where the button-press-events are for testing-purposes:


void my_button_press_event(void)
{
	if (!my_flag_autorize_generic_events) {
		return;
	}
	uint8_t report[] = {0x00,0x01,0x02,0x02,0x02,0x02};
	udi_hid_generic_send_report_in(report);
}

void my_button_unpress_event(void)
{
	if (!my_flag_autorize_generic_events) {
		return;
	}
	uint8_t report[] = {0x00,0x10,0x00,0x20,0x50,0x30};
	udi_hid_generic_send_report_in(report);
}

Now, in Devices And Printers, there is something like that, where the light-red-buttons are pressed.

Last Edited: Wed. Dec 3, 2014 - 08:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BurrrY wrote:
now it seems to work, the device is recognized!
Excellent!  Nice work!

 

Thank you for posting the details of your solution.  Future folks who conscientiously take the time to search the forums will appreciate it as well!

 

Regards,

Bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, thanks for this. Can I ask, when I set UDI_HID_REPORT_OUT_SIZE to zero as you did my device can't start in Device Manager.

 

Another odd thing is that the device appears under "Human Interface Devices" in Device Manager, rather than under "Sound, video and game controllers".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

Thank You very much for a great description how-to make own joystick.

 

Previously I used http://www.imaginaryindustries.c...

 

Well, it is also strange for me, that it appears as not under "Sound, video and game controllers", but what is more when I run joy.cpl Controller name is not value of  #define  USB_DEVICE_PRODUCT_NAME

 

Can anybody tell me why? Using ASF 3.25.0.