Sending USB HID Gamepad Reports with the SAMD11

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

 

Hi Atmel forums *wave*, I'm trying to develop a USB HID gamepad with the SAMD11 and have hit a wall trying to send HID reports. I'm ultimately trying to press a button and send a button press/axis movement on the gamepad. I've got a descriptor that at least appears to be a gamepad, but have failed to send any reports yet.

 

For some context, I'm using the SAMD11 XPlained Pro, Atmel START, and Microchip Studio 7 to prototype with. I'm used to the simple, 8-bit world and this is an early venture into 32-bit architectures and into USB. I've successfully built and sent reports using the USB HID mouse and keyboard examples with no modification what so ever (thanks to whoever wrote those examples!). After studying those projects, I was able to modify the mouse example to appear like a gamepad to Windows 10... sort of. Below is the descriptor I'm using and Windows 10 thinks the XPlained Pro is both a "USB Input Device" and a "HID-compliant game controller." Is this a problem?

        0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
	0x09, 0x04,                    // USAGE (Joystick)
	0xa1, 0x01,                    // COLLECTION (Application)
	0x05, 0x01,                    //   USAGE_PAGE (Generic)
	0x09, 0x01,                    //   USAGE (Pointer)
	0xa1, 0x00,                    //   COLLECTION (Physical)
	0x09, 0x30,                    //     USAGE (X)
	0x09, 0x31,                    //     USAGE (Y)
	0x09, 0x32,                    //     USAGE (Z)
	0x09, 0x33,                    //     USAGE (Rx)
	0x09, 0x34,                    //     USAGE (Ry)
	0x09, 0x35,                    //     USAGE (Rz)
	0x95, 0x06,                    //     REPORT_COUNT (6)
	0x81, 0x02,                    //     INPUT (Data,Var,Abs)
	0xc0,                          //   END_COLLECTION
	0x05, 0x01,                    //   USAGE_PAGE (generic)
	0x09, 0x39,                    //   USAGE (Hat switch)
	0x15, 0,                       //   LOGICAL_MINIMUM (0)
	0x25, 7,                       //   LOGICAL_MAXIMUM (7)
	0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
	0x46, 0x0e, 0x01,              //   PHYSICAL_MAXIMUM (270)
	0x65, 0x14,                    //   UNIT (Eng Rot:Angular Pos)
	0x75, 0x04,                    //   REPORT_SIZE (4)
	0x95, 0x01,                    //   REPORT_COUNT (1)
	0x81, 0x02,                    //   INPUT (Data,Var,Abs)
	0x05, 0x09,                    //   USAGE_PAGE (Button)
	0x19, 0x01,                    //   USAGE_MINIMUM (Button 1)
	0x29, 12,                      //   USAGE_MAXIMUM (Button 12)
	0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
	0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
	0x75, 0x01,                    //   REPORT_SIZE (1)
	0x95, 12,                      //   REPORT_COUNT (12)
	0x55, 0x00,                    //   UNIT_EXPONENT (0)
	0x65, 0x00,                    //   UNIT (None)
	0x81, 0x02,                    //   INPUT (Data,Var,Abs)
	0xc0                           // END_COLLECTION

 

From studying the mouse and keyboard examples, both projects are almost identical except for three core files in ./usb/class/hid/device/. In the solution I attached, the files in this folder are called hiddf_gamepad.c, hiddf_gamepad.h, and hiddf_gamepad_desc.h. The descriptor above is defined in ./usb/class/hid/device/hiddf_gamepad.c. Virtually all of the modifications from the mouse example happened in this file. Specifically, I tried to modify the hidddf_mouse_move() function in the original example to manipulate the hid report and send it using usbdc_xfer(), which I believe is a public function from Atmel. I also renamed and simplified a struct called hiddf_mouse_funct_data and renamed it appropiately. I'm certain there's something I don't understand because nothing I'm doing shows any sign of life from the board.

 

// ./usb/class/hid/device/hiddf_gamepad.c
...
/* Original code from mouse example
struct hiddf_mouse_func_data {
	// HID descriptor
	uint8_t *hid_desc;
	// HID Device Mouse Report
	union { // why is this report structured like this?
		// Interpreted by bytes.
		struct {
			// Button Status.
			uint8_t button_state;
			// X Axis Variant.
			uint8_t x_axis_var;
			// Y Axis Variant.
			uint8_t y_axis_var;
			// Scroll Variant.
			uint8_t scroll_var;
		} bytes;
		uint32_t u32;
	} mouse_report;
	// HID Device Mouse Interface information
	uint8_t func_iface;
	// HID Device Mouse IN Endpoint
	uint8_t func_ep_in;
	// HID Device Mouse protocol
	uint8_t protocol;
	// HID Device Mouse Enable Flag
	bool enabled;
};
*/

// Gamepad struct
struct hiddf_gamepad_func_data {
	/* HID descriptor */
	uint8_t *hid_desc;
	/* HID Device Gamepad Report */
	uint8_t gamepad_report[8]; // Is this report structure wrong?
	/** HID Device Gamepad Interface information */
	uint8_t func_iface;
	/** HID Device Gamepad IN Endpoint */
	uint8_t func_ep_in;
	/** HID Device Gamepad OUT Endpoint */
	uint8_t func_ep_out;
	/** HID Device Gamepad protocol */
	uint8_t protocol;
	/** HID Device Gamepad Enable Flag */
	bool enabled;
};

...
/* Original HID report manipulation from 
int32_t hiddf_mouse_move(int8_t pos, enum hiddf_mouse_move_type type)
{

	_hiddf_mouse_funcd.mouse_report.u32 = 0;  // what is this doing?

	if (type == HID_MOUSE_X_AXIS_MV) {
		_hiddf_mouse_funcd.mouse_report.bytes.x_axis_var = pos;
	} else if (type == HID_MOUSE_Y_AXIS_MV) {
		_hiddf_mouse_funcd.mouse_report.bytes.y_axis_var = pos;
	} else if (type == HID_MOUSE_SCROLL_MV) {
		_hiddf_mouse_funcd.mouse_report.bytes.scroll_var = pos;
	} else {
		return ERR_INVALID_ARG;
	}

	return usbdc_xfer(_hiddf_mouse_funcd.func_ep_in, &_hiddf_mouse_funcd.mouse_report.bytes.button_state, 4, false);
}
*/

int32_t hiddf_gamepad_move(int8_t pos, enum hiddf_gamepad_move_type type)
{

	if (type == HID_GAMEPAD_X_AXIS_MV) {
		_hiddf_gamepad_funcd.gamepad_report[0] = pos;
		} else if (type == HID_GAMEPAD_Y_AXIS_MV) {
		_hiddf_gamepad_funcd.gamepad_report[1] = pos;
		} else {
		return ERR_INVALID_ARG;
	}

	return usbdc_xfer(_hiddf_gamepad_funcd.func_ep_in, &_hiddf_gamepad_funcd.gamepad_report[0], 8, false);
}
...

Again, no signs of life from these modifications. Can anyone shed some light? Perhaps even share example code successfully sending hid gamepad reports? All the Atmel documentation I could find was for legacy APIs.

 

 

Attachment(s): 

Last Edited: Mon. Aug 29, 2022 - 12:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please?

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

Can't you find out what the report data should be from working examples? Maybe from arduino like here
https://github.com/NicoHood/HID/...

/Lars