Hi everyone,
I'm working on a custom system monitoring device and have a requirement for a USB HID input report longer than 64 bytes. From what I've read, it's possible to send it as multiple transactions but I can't figure out how to make Keil's USBHID sample code do it.
Any ideas?
Thanks, Jason
Thanks for the response Tsuneo! I gave it a try but it still doesn't seem to be working. I think it may have something to do with USB_ConfigEP that deals with the Endpoint descriptor. The code is:
void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR *pEPD) { DWORD num; num = EPAdr(pEPD->bEndpointAddress); REALIZE_EP |= (1 << num); EP_INDEX = num; MAXPACKET_SIZE = pEPD->wMaxPacketSize; while ((DEV_INT_STAT & EP_RLZED_INT) == 0); DEV_INT_CLR = EP_RLZED_INT; }
It assumes that the max packet size a word. Should MAXPACKET_SIZE be the two bytes (my report is 100 bytes) added together?
The important bits of my code are:
Report Descriptor
HID_UsagePageVendor(0xFF), // ESA Config HID_Usage(0x03), // ESA Water Cooling HID_Collection(HID_Application), HID_ReportID(0x11), // Input Report 11 //HID_UsagePage(0xFF), HID_Usage(0x04), HID_LogicalMin(0), HID_LogicalMax(255), HID_ReportCount(99), HID_ReportSize(8), HID_Input(HID_Data | HID_Array | HID_Absolute), HID_EndCollection,
Endpoint Descriptor
/* Endpoint, HID Interrupt In */ USB_ENDPOINT_DESC_SIZE, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ USB_ENDPOINT_IN(1), /* bEndpointAddress */ USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */ 0x40,0x24, /* wMaxPacketSize */ 0x20, /* 32ms */ /* bInterval */
USB_EndPoint1
void USB_EndPoint1 (DWORD event) { DWORD byte_count = 0; set_chb_err_led(FALSE); switch (event) { case USB_EVT_IN: // Alternate which report we output so we don't stomp the buffer switch (report_block_number) { case 0: GetInReportMCC(); byte_count = USB_WriteEP(0x81, InReport, 64); report_block_number = 1; break; case 1: byte_count = USB_WriteEP(0x81, InReport, 36); report_block_number = 0; break; } if (byte_count > 0) set_usb_status(0); if (byte_count == 0) set_usb_status(1); break; } }
Does this look correct? Thanks again for all the help. I'm on a really tight timeline so it's appreciated.
Jason Lewis
"Should MAXPACKET_SIZE be the two bytes (my report is 100 bytes) added together?"
You don't need to touch MAXPACKET_SIZE of USB_ConfigEP. Please note, wMaxPacketSize means the division unit for transactions. It doesn't mean the transfer size itself. Transfer size is defined by the HID_ReportCount() on the report descriptor. And the wMaxPacketSize for full-speed interrupt and bulk transfer is limited to 64 bytes by the USB spec.
Recently, I wrote about the relation of "Transfer - transaction - packet" in this post. It describes how wMaxPacketSize works on the USB protocol. It is applied to bulk and interrupt (HID) transfer.
"C8051F340 USB_Bulk example question" on SiLabs Forum www.cygnal.org/.../001627.html "Report Descriptor"
HID_ReportID(0x11), // Input Report 11
As the report descriptor has just single definition of input report, you can do without the report ID. Of course, you can apply report ID as you wrote, too. If you have plan to add more input reports, the report ID will ease the extension. "Endpoint Descriptor"
0x40,0x24, /* wMaxPacketSize */
This is the problem. Set wMaxPacketSize to 64 (LSB first, as usual on USB).
0x40,0x00, /* wMaxPacketSize = 64 */
"USB_EndPoint1"
DWORD byte_count = 0;
Make byte_count to static, or global. USB_EndPoint1() is called by the USB ISR every time a transaction finishes. Anyway, I think this byte_count is not useful in your code, because you does it with report_block_number.
In this implementation, your device continuously puts the input report at the rate defined by the endpoint descriptor (bInterval). As it is 32 ms, the first transaction (64 bytes) and later one (32 bytes) are sent to the host alternately, in this rate. (The entire transfer takes 64 ms).
If you want to send the report just when the device detects a change on the target, rewrite it as described in above post.
Tsuneo
Awesome, that did it. Turns out that I had all the code right initially with the exception of USB_Endpoint1.
Thanks Tsuneo!
Okay, another related question. I also need to be able to send the controller long reports (140 bytes) via a control transfer. I've verified that the report is being sent and the controller is receiving them (64, 64, and 12). I can't figure out how to modify the HIDUSB code to parse the pieces together. Any help would be appreciated.
Sorry for my late response,
"I also need to be able to send the controller long reports (140 bytes) via a control transfer."
You can support OUT report over control transfer, but primarily OUT report is handled by an OUT endpoint. - For the firmware, handling of control transfer is heavy than interrupt endpoint - For Windows XP and Vista host app, WriteFile primarily goes to OUT endpoint.
In this topic, we discussed about the way to add OUT endpoint to HID. You can extend this method for the greater report size than 64, as you did it to the IN endpoint.
"LPC2148 usb controller" http://www.keil.com/forum/docs/thread11137.asp
Instead of OUT report, Feature report is primarily handled by control transfer. If you want to exercise the control write transfer implementation, I'll guide you.