When using Intel hardware for your embedded platform, you
most likely will include the UHCI (1.1) and/or EHCI (2.0) USB drivers in your
Windows CE image. Already some time ago I noticed that when unplugging a USB
device (keyboard, mouse, memory stick …) and inserting it again, the UI stalled
for a moment while the USB device was inserted again. I also noticed on a
particular hardware platform where 2 CAN channels were used, that the CAN
communication failed with timeouts of a few 100milliseconds. This happens with the sample USB Windows CE 6/7/8 drivers shipped by Microsoft.
I already knew that the UHCI and EHCI USB driver code had
some bugs, but I patched them already long ago with the fixes you can obtain from BSquare or
Adeneo. Still no luck.
After investigation (together with my work colleague
Kevin) it turned out that the UHCI driver was responsible for that behaviour.
The problem is located in HCD\UHCD\chw.cpp, more precisely in the function CHW::ResumeHostController(). This
function implements a 20msec delay by running a for-loop 600000 times. Ugh! As
this code runs at a pretty high thread priority (around (driver) priority level
100), it blocks any lower thread priority code running at the same time. The
code intended to pause for 20msec, but in reality it did so for ±300msec. Killing
on a real-time OS!
The CAN driver IST thread ran at a lower priority, but it
buffers the CAN messages properly in a FIFO. No CAN messages were lost, but the
application (actually the thread) that processed these CAN message had a
timeout built in (between transmitting command and waiting for response) and as a result the application failed.
Windows CE UI threads run typically at the default thread priority
level 251, it is obvious that the UI stalled during this for-loop period.
Here is the code snippet with the problem
VOID CHW::ResumeHostController(){
… // I need 20 ms delay here 30(30ns)*1000*20
for (DWORD dwIndex =0; dwIndex<30*1000*20; dwIndex++)
Read_USBCMD();
…
}
And the obvious fix
VOID
CHW::ResumeHostController()
{
…
// I need
20 ms delay here 30(30ns)*1000*20
Sleep(20);
…
}