USB I2C HID device?

Technical questions regarding the xTIMEcomposer, xSOFTip Explorer and Programming with XMOS.
T-5
Member
Posts: 15
Joined: Wed Jun 26, 2019 3:59 pm

USB I2C HID device?

Post by T-5 »

Hi,

Sorry if this topic has already been discussed but i was not able to find anything, partly due to the fact that "usb i2c hid" all are words that will not produce any search results in this forum.

I have a XUF512 (Exact designation: XS2-UnA-512-FB236) running with UAC2 (12 channel i2s out, 6 channel i2s in).

What I'd like to add is a USB HID device with functionality similar to the CP2112 (https://www.silabs.com/interface/usb-br ... ice.cp2112) that allows the XMOS chip to act as an USB to I2C bridge.

Has this done before, are there any examples around?

Thanks in advance and best regards,
Jürgen


User avatar
mon2
XCore Legend
Posts: 1910
Joined: Thu Jun 10, 2010 11:43 am

Post by mon2 »

You can study the following appnote on HID use and review the I2C example inside this document:

https://www.xmos.ai/download/AN00182:-U ... .2rc1).pdf
Precisely
New User
Posts: 2
Joined: Fri Nov 03, 2017 6:39 pm

Post by Precisely »

Jürgen,

Have you made any progress with this, either finding existing example code or modifying existing sample code to make it work?

I'm looking to do the same thing (USB HID <==> I2C), although I need it to run alongside UAC2 (6 channel I2S in, 2 channel I2S out) and a virtual serial port (both of which I already have working simultaneously on the same device).

Thanks,

Ben
Precisely
New User
Posts: 2
Joined: Fri Nov 03, 2017 6:39 pm

Post by Precisely »

I've made progress on this, but I'm stuck and would appreciate any guidance or help to get it working.

I've updated the module_usb_audio code to include an HID interface with output and input endpoints.
I'm communicating with the device using the hid Python library running on macOS Catalina. I can successfully write multiple bytes of data to the device through the HID output endpoint. However, the (multi-byte) data that I try to send back to the host (Mac) apparently isn't being sent.
I have only successfully been able to read 1 byte from the device, and only when that byte happens to be 0x08 (strangely, only the first byte is sent and if I change it to anything other than 0x08, no data is transferred and the Python script waits indefinitely for data to arrive). That's probably a clue, but I haven't figured out what it really means.

descriptors.h:

Code: Select all

unsigned char hidReportDescriptor[] =
{
	0x06, 0x00, 0xff,	/* Usage Page (Vendor defined 0) */
	0x09, 0x01,     	/* Usage (Consumer Control) */
	0xa1, 0x01,     	/* Collection (Application) */
	0x75, 0x08, 		/* Report Size (8) */
	0x26, 0xff, 0x00,	/* Logical Maximum (255) */
    0x15, 0x00,     	/* Logical Minimum (0) */
    0x85, 0x08,			/* Report ID (8) */
    0x95, 0x3f,     	/* Report Count (63) */
    0x09, 0x01,     	/* Usage 1 */
    0x91, 0x02,			/* Output (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Nonvolatile, Bitfield) */
    0x85, 0x09,			/* Report ID (9) */
    0x95, 0x3f,     	/* Report Count (63) */
	0x09, 0x02,     	/* Usage 2 */
	0x81, 0x02,			/* Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null Position, Bitfield) */
	0xc0            	/* End collection */
};

Code: Select all

.HID_Interface =
	{
		9,                                /* 0  bLength : Size of descriptor in Bytes */
		4,                                /* 1  bDescriptorType (Interface: 0x04)*/
		INTERFACE_NUMBER_HID,             /* 2  bInterfaceNumber : Number of interface */
		0,                                /* 3  bAlternateSetting : Value used  alternate interfaces using SetInterface Request */
		2,                                /* 4: bNumEndpoints : Number of endpoints for this interface (excluding 0) */
		3,                                /* 5: bInterfaceClass */
		0,                                /* 6: bInterfaceSubClass - no boot device */
		0,                                /* 7: bInterfaceProtocol*/
		0,                                /* 8  iInterface */
	},

	{
		9,                                /* 0  bLength : Size of descriptor in Bytes */
		0x21,                             /* 1  bDescriptorType (HID) */
		0x10,                             /* 2  bcdHID */
		0x01,                             /* 3  bcdHID */
		0,                                /* 4  bCountryCode */
		1,                                /* 5  bNumDescriptors */
		0x22,                             /* 6  bDescriptorType[0] (Report) */
		sizeof(hidReportDescriptor) & 0xff,/* 7  wDescriptorLength[0] */
		sizeof(hidReportDescriptor) >> 8,  /* 8  wDescriptorLength[0] */
	},

	.HID_Out_Endpoint =
	{
		/* Endpoint descriptor (OUT) */
		0x7,                              /* 0  bLength */
		USB_DESCTYPE_ENDPOINT,            /* 1  bDescriptorType */
		ENDPOINT_ADDRESS_OUT_HID,         /* 2  bEndpointAddress  */
		3,                                /* 3  bmAttributes (INTERRUPT) */
		64,                               /* 4  wMaxPacketSize */
		8,                                /* 6  bInterval */
	},

	.HID_In_Endpoint =
	{
		/* Endpoint descriptor (IN) */
		0x7,                              /* 0  bLength */
		USB_DESCTYPE_ENDPOINT,            /* 1  bDescriptorType */
		ENDPOINT_ADDRESS_IN_HID,          /* 2  bEndpointAddress  */
		3,                                /* 3  bmAttributes (INTERRUPT) */
		64,                               /* 4  wMaxPacketSize */
		8,                                /* 6  bInterval */
	}
usb_buffer.xc

Code: Select all

/* HID Report Data */
buffer(...)
{
	...
	while(1)
	{
		...
		select
		{
			...
            		case XUD_GetData_Select(c_hid_out, ep_hid_out, length, result):
			{
				if((result == XUD_RES_OKAY) && (length > 0))
				{	// Send the data out
					WriteHID_I2C(g_hidData_out, length);
				}
				// Indicate that we're ready for another data packet from the host.
				XUD_SetReady_Out(ep_hid_out, g_hidData_out);
			}
			break;

			case XUD_SetData_Select(c_hid_in, ep_hid_in, result):
			{
				if(result == XUD_RES_OKAY)
				{	// Read the desired data
					ReadHID_I2C(g_hidData_in);
					// Indicate that we have data ready to send to the host.
					XUD_SetReady_In(ep_hid_in, g_hidData_in, 63);
				}
			}
			break;
			...
		}
		...
	}
	...
}
At this point, my ReadHID_I2C() function just puts static values in the g_hidData_in array and my WriteHID_I2C() function does nothing.

XUD_SetReady_In() doesn't appear to be doing its job. Where might the problem lie?

Thanks for any tips!