Hi there! I'm still trying to get around USB HID communication. To that end I've added Keil's HIB example to my project (some LPC2478). Since it's lacking the buttons and LEDs that the example is expecting, I've slightly modified the user interface: the data provided by my device is the RTC's seconds, while the data sent to the device gets output to the LCD. Now everything is fine, data gets transferred to the PC every 32ms (as specified by the descriptor).
My general questions are: 1. In terms of the example project, do I work in usbuser.c or hiduser.c? I've commented out HID_GetReport and HID_SetReport, and still my device works. So obviously what's being called is USB_EndPoint1. Why is it that I have to declare my device an HID, and in the end the HID stuff doesn't even execute? 2. The USB Set Configuration Request is issued once, during enumeration, isn't it? 3. After reading a lot of Tsuneo's posts, I think there's two different ways that I can transfer data to/from the device: either via the control endpoint, or via the endpoints specified in my descriptor. So why do I even go through the trouble of defining my own endpoints? 5. How does "one interrupt-type data transfer" proceed? I think, it's something like: - the PC sends an InReport to the device, causing a USB_EVT_OUT there which leads to the execution of USB_EndPoint1. - Now by some magic, USB_EndPoint1 is called again with an argument of USB_EVT_IN. Is this somehow similar to reality?
Any answers would be greatly appreciated. I'm struggling with Axelson's USB Complete, with lots of forum threads (thanks, Tsuneo), but can't yet get a grip on this whole USB business.
Kind regards, Peter
> 1. In terms of the example project, do I work in usbuser.c or hiduser.c? I've commented out HID_GetReport and HID_SetReport, and still my device works. So obviously what's being called is USB_EndPoint1.
HID device has two ways to exchange reports - over interrupt IN / OUT endpoints - using GetReport / SetReport request over the default endpoint (EP0)
You've disabled GetReport / SetReport request handlers. You may examine these requests using SimpleHIDWrite.
SimpleHIDWrite (by Robert Marquardt) on Jan Axelson's site www.lvr.com/.../SimpleHIDWrite3.zip
The source code (Delphi) of SimpleHIDWrite is included in Human Interface Device controller suite www.soft-gems.net/index.php
Before running the device on SimpleHIDWrite, comment the USB_EVT_IN case in USB_EndPoint1(). Otherwise, the report pane of the application dialog is filled with repeated input reports from the interrupt IN endpoint. > 2. The USB Set Configuration Request is issued once, during enumeration, isn't it?
SetConfiguration(1) is required at least once on enumeration. Usually, it's just once. But you may put SetConfiguration(0) to reset the configuration. > So why do I even go through the trouble of defining my own endpoints?
The interrupt IN endpoint is mandatory by the HID spec. Interrupt OUT endpoint is optional.
These two ways (interrupt IN endpoints and Requests) are assigned to the different tasks.
Host puts GetReport request to know the status of the device immediately. Device has to respond to GetReport within given timeout (500ms). As HID interrupt IN endpoint is always polled by host, device may put an input report at any timing when the device likes.
In the same way, host expects that the device processes SetReport request within timeout. Device may delay process of the output report over the interrupt OUT endpoint, as long as it likes. > the PC sends an InReport to the device, causing a USB_EVT_OUT there which leads to the execution of USB_EndPoint1. - Now by some magic, USB_EndPoint1 is called again with an argument of USB_EVT_IN.
You don't need to wait for USB_EVT_IN. Rather, comment all lines of USB_EVT_IN case of USB_EndPoint1(). Call USB_WriteEP(HID_EP_IN) in the USB_EVT_OUT case.
Tsuneo
I'm starting to doubt that interrupt mode is the best choice for me. My use case goes roughly like this: 1. When connected to the PC, the device doesn't send any data 2. The user starts the software on the PC 3. The user plugs in the USB connector and tells the device to connect to the PC 4. The PC software realizes the device's presence and starts communicating with it
My main concern is how to stop the device from sending data in (1). Is this even possible without causing the timeout you mentioned after 500ms? Is something possible like "the device should only answer the PC if the PC sends certain commands"? Should I comment the EP1 bit? Because I think on EP1 I can't identify the PC's request, while on EP0 I can (because I can tell one reportID from another)? So I could implement something like "if the GetReport is from the OS, answer it with some meaningless data. But if the GetReport is from my PC software, answer it with real data". Does this make any sense?
Thanks for your help! Peter
Maybe, you didn't yet read the posts I told to you on your another post. Here is excerpts from the posts. http://www.keil.com/forum/15613/ 24-Sep-2009 17:48 GMT
Even if your PC application doesn't read any input report, HID device driver (*1) repeats IN transactions at the specified interval without break.
I'll show you how HID example handles the interrupt IN endpoint.
This is an excerpt from KEIL HID implementation. LPC2368 / LPC2378 USB HID (Human Interface Device) Example http://www.keil.com/download/docs/335.asp
usbuser.c #if USB_CONFIGURE_EVENT void USB_Configure_Event (void) { if (USB_Configuration) { /* Check if USB is configured */ GetInReport(); USB_WriteEP(0x81, &InReport, sizeof(InReport)); } } #endif void USB_EndPoint1 (DWORD event) { switch (event) { case USB_EVT_IN: GetInReport(); USB_WriteEP(0x81, &InReport, sizeof(InReport)); break; } }
USB_Configure_Event() is called when Set_Configuration request comes from host on enumeration. In this routine, an input report is loaded to the EP1 IN buffer using USB_WriteEP(). This report is the first one. When host starts to repeat IN transactions just after enumeration, this report is sent to the host. And then, USB interrupt occurs at the IN EP1.
On this interrupt, USB_EndPoint1() is called. This routine fills the endpoint buffer with a report using USB_WriteEP(). This report is sent to host at the next IN transaction after the specified interval (bInterval). Another endpoint interrupt occurs, and USB_EndPoint1() is called again.
In this way, USB_EndPoint1() is called repeatedly, at bInterval.
If you put nothing to the endpoint buffer in USB_EndPoint1(), what happens? No report is sent to the host, and no endpoint interrupt occurs. The sequence stops, USB_EndPoint1() is never called any more, until you fill the endpoint buffer with USB_WriteEP().
(*1) Actually, it is the host controller which repeats IN transactions periodically. HID device driver keeps IN transfer, putting one after another. 26-Sep-2009 03:46 GMT The evil of this HID example is that it gives a fixed idea - read/write of endpoint buffer should be done just in the endpoint ISR. It's wrong. Rather, read/write in the endpoint ISR is a rare case in the real world code.
You may call USB_WriteEP(), at any where, at any timing as you like (unless the EP buffer is still occupied by the last write). For example, you may call USB_WriteEP() in a timer ISR, which scans ports for keypads. You may call in ADC ISR, just when a sensor input shows change.
These ISRs should have the same priority (FAST/SLOW) as USB ISR, so that USB_WriteEP() calls from both ISRs don't interrupt each other. When you call USB_WriteEP() on main line code, disable USB interrupt temporarily around USB_WriteEP() call. Or make a SWI which calls USB_WriteEP().