Hi, We make a custom board work the same as MCB2300 and try to run the USBHID example for LPC 2364 chip. I cannot read the endpoint 1 from libusb command usb_interrupt_read(device, 0x81, buffer, sizeof(buffer), 500). I can make another endpoint 2 and can write to the endpoint 2 OK but I cannot read any endpoint. It gives me a timeout error with error code -110.
Can anyone show me how to fix it?
To trace the bug in systematic way, monitor the USB traffic on a hardware bus analyzer or on a software sniffer
A hardware bus analyzer suggests the place where the problem lies, as follows a) Problem on PC side When usb_interrupt_read() is executed on step execution, no IN transaction to the endpoint of the device appear on the bus. If you see any IN transaction, check device and endpoint address of the IN transaction carefully. Does it match to the target device endpoint?
When the PC puts an IN transaction on correct device and endpoint address, b) Problem on the firmware side - IN - no response, three times Your firmware doesn't initialize (realized/configured) the endpoint
- Repeated IN - NAK, until cancelled by timeout Your firmware doesn't put any packet to the endpoint
For software sniffers, a) Problem on PC side When usb_interrupt_read() is executed on step execution, no BULK_OR_INTERRUPT_TRANSFER URB to the endpoint of the device appear on the bus. If you see any BULK_OR_INTERRUPT_TRANSFER URB, check device and endpoint address of the URB carefully. Does it match to the target device endpoint?
When the PC puts an IN transaction on correct device and endpoint address, b) Problem on the firmware side - BULK_OR_INTERRUPT_TRANSFER URB finishes immediately with error Your firmware doesn't initialize (realized/configured) the endpoint
- BULK_OR_INTERRUPT_TRANSFER URB goes pending, and cancelled afterward. Your firmware doesn't put any packet to the endpoint Most likely, "Your firmware doesn't put any packet to the endpoint" is the case. If it's the case, see this post
No HID interrupt IN transfers http://www.keil.com/forum/docs/thread15613.asp 24-Sep-2009 17:48 GMT, Author: Tsuneo Chinzei
Tsuneo
Thank Tsuneo. I check the usb with a bus analyser and see that they have Repeated IN - NAK but without data. So I go back to the old board MCB2140 and see the same thing with USBHID example.
When I connected to a window machine and it worked fine for this board. But it failed on linux so I check the sequence of commands before send the usb_interrupt_read().
I added another command usb_set_configuration(device, 1) and it works now. It also works on LPC2364 with this new added command.
I port the usb code from LPC2888 to LPC2364 and on LPC2888 I don't need this usb_set_configuration(device, 1) that is why I cannot figure out what is wrong with the firmware.
> I added another command usb_set_configuration(device, 1) and it works now.
Monitor the enumeration of the device using the hardware bus analyzer, just after the device is plugged into the host PC. Does the host PC puts Set_Configuration request before the extra usb_set_configuration(device, 1) is executed explicitly on the host app?
Set_Configuration( config 1 ) request is required once at the end of enumeration, but just once.
If extra Set_Configuration is needed to run the firmware, it suggests a firmware bug. The bug exists on the Set_Configuration handler on the firmware.
Hi Tsuneo,
There is a Set_Configuration request after the device is plugged into the host PC but I still need the extra usb_set_configuration(device, 1) to make it work to read the endpoint otherwise it will fail.
You can test this bug on USBHID on MCB2140 board at C:\Keil\ARM\Boards\Keil\MCB2140\USBHID example. I use it on my linux opensuse 10.3 linux kernel 2.6.22.5-31 to read and write to the endpoint.
In 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; } }
Does any Set_Interface request occur after the first Set_Configuration request? Please check it on the hardware analyzer.
Keil USBHID example arms the first input report to the interrupt IN endpoint in USB_Configure_Event(). This input report triggers following IN endpoint interrupt sequence. USB_Configure_Event() is called just from the Set_Configuration handler, but not from Set_Interface handler.
When Set_Interface is issued by host after Set_Configuration, the IN endpoint is reset again, and the input report armed by Set_Configuration handler is canceled.
In the standard enumeration sequence on Windows, Mac and Linux for HID, no Set_Interface appears. But when you run the device on libusb, you may accidentally summon up Set_Interface after Set_Configuration. Using libusb, PC application can configure the enumeration sequence freely.
If this is the case, a) Don't call Set_Interface after Set_Configuration in the libusb code. OR b) On the firmware, call USB_Configure_Event() from the Set_Interface handler, too
we use usb_claim_interface() in libusb so there is a Set_Interface request occur after the first Set_Configuration request. It worked fine on NOHAU LPC 2800 board.
So to make it compatible to my old libusb code, I change the firmware on LPC 2364 to call USB_Configure_Event() from the Set_Interface handler.
Thank you Tsuneo for all your help.
More detailed code modification along with above topic is requested by another thread
> Gudjon > Can anyone please show me the code changes needed for USBHID to work with lpc2148? http://www.keil.com/forum/docs/thread16347.asp
This modification is applied to this KEIL example.
LPC2148 USB HID (Human Interface Device) Example http://www.keil.com/download/docs/306.asp
usbcfg.c #define USB_POWER_EVENT 0 #define USB_RESET_EVENT 1 #define USB_SUSPEND_EVENT 0 #define USB_RESUME_EVENT 0 #define USB_WAKEUP_EVENT 0 #define USB_SOF_EVENT 0 #define USB_ERROR_EVENT 0 #define USB_EP_EVENT 0x0003 #define USB_CONFIGURE_EVENT 1 #define USB_INTERFACE_EVENT 1 // <----- enable USB_INTERFACE_EVENT #define USB_FEATURE_EVENT 0 usbuser.c /* * USB Set Configuration Event Callback * Called automatically on USB Set Configuration Request */ #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 /* * USB Set Interface Event Callback * Called automatically on USB Set Interface Request */ #if USB_INTERFACE_EVENT void USB_Interface_Event (void) { // <-------- copy the contents of USB_Configure_Event(), // or just call USB_Configure_Event() USB_Configure_Event(); } #endif
I have a question about the reset button. When I hit the reset button:
For NXP LPC23XX USB Bootloader example, I can see the usb reset message on the linux kernel log and have usb back.
For USBHID keil example, I don't see any message on linux kernel log and the usb never come back until I power off the board and turn on the power again to get the usb.
I check the files and see they have the same usbhw.c and usbcore.c, most of other files are the same except one use hid and another use msc.
> For NXP LPC23XX USB Bootloader example, I can see the usb reset message on the linux kernel log and have usb back. ... I check the files and see they have the same usbhw.c and usbcore.c, most of other files are the same except one use hid and another use msc.
Sound like the difference of the length of start up initialization of the firmware. When the reset button is pushed down longer, for 2-3 sec, what occurs ?
1) When the LPC23XX goes to reset, port pins turn to input. 2) The D+ pull-up resistor on the USB line, which is controlled by CONNECT pin, is detached. 3) Host PC (or hub) detects USB disconnection by the voltage change on D+ line, which is pulled down on the host side. 4) The firmware on the LPC23XX starts initialization 5) When the firmware initializes USB engine, it enables D+ pull-up, too. 6) Host detects connection by the D+ line voltage change. 7) Host starts enumeration again, which start with bus reset.
If the length of disconnected period is too short, host misses to detect the disconnection.