USBFS: 64-Byte HID sometimes missing transmissions?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
KyTr_1955226
Level 6
Level 6
250 sign-ins 10 likes given 50 solutions authored

Hello!

I'm having a weird problem with USB HID application.

USBFS component (v3.2.0) running on a PSoC5LP device.

The USB Device is configured as a 64-Byte Generic HID. 

EP1 is 64 bytes IN, 20ms INT

EP2 is 64 bytes OUT, 20ms INT

Right now all I am trying to do is send a command from the PC to the PSoC via EP2, and get a response back from the PSoC on EP1.  The application I am sending from is built in C# .NET, using the CyUSB.dll (v3.4.7.0) library.  Right now I'm just trying to query a firmware version string from the PSoC off a button press.  "00" is the command being sent:

private void btn_getFWInfo_Click(object sender, EventArgs e)

        {

            bool status;

            string incoming;

            string[] fwstrings;

            int count = 0;

            byte[] inbuffer = new byte[64];

            byte[] outbuffer = new byte[65];

            if (ApplicationHIDDevice != null)

            {

                outbuffer[1] = Convert.ToByte('0');

                outbuffer[2] = Convert.ToByte('0');

                while ((inbuffer[1] == 0x00) && (count < 100))

                {

                    outbuffer.CopyTo(ApplicationHIDDevice.Outputs.DataBuf, 0);

                    ApplicationHIDDevice.WriteOutput();

                    status = ApplicationHIDDevice.ReadInput();

                    ApplicationHIDDevice.Inputs.DataBuf.CopyTo(inbuffer,0);

                    count++;

                }

                tb_Statuslog.Text += count.ToString()+ "\r\n";

               

                if (count < 100) {

                    incoming = Encoding.ASCII.GetString(inbuffer).Trim().Substring(1);

                    fwstrings = incoming.Split(',');

                    if (incoming.Contains("98-"))

                    {

                        tb_fwNum.Text = fwstrings[0];

                        tb_fwRev.Text = fwstrings[1];

                        tb_buildDate.Text = fwstrings[2];

                    }

                } else

                {

                    tb_Statuslog.Text += "USB Device "

                        + "0x" + ApplicationHIDDevice.VendorID.ToString("X4")

                        + "/0x" + ApplicationHIDDevice.ProductID.ToString("X4")

                        + " No Response.\r\n";

                }

            }

        }

When running this code, it only ever makes it to the message processing function on the PSoC about half the time when the command is sent, and even then only about half of those times does the response actually come back to the host correctly.  When I run this code, the count variable usually ends up around 20 to 30 before the code above manages to catch a response back from the PSoC.

The USB message handling code for the PSoC is below.  It is called every time through the main loop of the firmware, about once every 20-30us:

uint8_t USB_HIDInBuffer[64];

uint8_t USB_HIDOutBuffer[65];

/** Process_USB

*  - Handles USB connection and exchange of IN/OUT Endpoint data

*  - Calls processing function for Control messages

*/

void Process_USB (void){

    static bool is_connected = false;

    uint8_t cmd_in;

    is_connected = USB_UpdateConnection();

   

        if (is_connected){

           

            /*IN Buffer is data going IN to Host PC*/

            if (USBFS_bGetEPState(USBFS_EP1) == USBFS_IN_BUFFER_EMPTY){

                USBFS_LoadInEP(1, USB_HIDInBuffer, 64);

                memset(USB_HIDInBuffer,0x00,64);

                USBFS_EnableOutEP(2);

            }

           

            /*OUT Buffer is data coming OUT of Host PC*/

            if (USBFS_bGetEPState(USBFS_EP2) == USBFS_OUT_BUFFER_FULL){

                USBFS_ReadOutEP(2, USB_HIDOutBuffer, 64); 

               

                cmd_in = USB_HIDOutBuffer[0];

               

                    if (cmd_in != 0){

                        /*This processes the command and loads USB_HIDInBuffer with the response*/

                        Process_ControlMessage(INTERFACE_HID, (char *)USB_HIDOutBuffer, (char *)USB_HIDInBuffer);

                    }

                memset(USB_HIDOutBuffer,0x00,65);

                USBFS_EnableOutEP(2);

            }

           

        }

       

}

What I've found is that most of the time when I send the message from the PC, the EP2 Event Pending (USBFS_OUT_BUFFER_FULL) check fails, so no message processing ever happens.  Even when I drop into the EP2 Event Pending check and the message processing fires, only infrequently do I actually manage to receive the response back on the IN endpoint.  Generally it takes about 8-10 attempts of successfully processing the message for the response to be received by the PC using the above C# code.

I'd figure there might be something funky with the hardware, but using the USBFS HID Bootloader gives me absolutely no trouble, so the connection looks to be plenty stable.  it must be something how my code is written on either end.  I don't have my USB Analyzer at the moment, so I figure I could take a shot and see if anyone here might have any suggestions.

Thanks in advance!

0 Likes
1 Solution
Ekta_N
Moderator
Moderator
Moderator
750 replies posted First like given 250 solutions authored

Hello KyTr_1955226

Your understanding of the ReadInput() being a blocking all is correct. ApplicationHIDDevice.ReadInput is blocking call..so if the psoc is not ready with the data when requested, this will add to the delay.

Please refer to the following link for more details on the ReadInput function: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile​ . It is possible to read the return status of ReadInput call in the Host app. In the code you are storing the status of the readinput but it should be checked as well before incrementing the count variable

Also, I guess that you are using the old CyUSB.dll. The new one is available at:https://www.cypress.com/documentation/software-and-drivers/ez-usb-fx3-software-development-kit Note that in the newer version we do not provide WriteOutput and ReadInput APIs. It uses the use the standard hidsdi.lib (Hidsdi.h header - Windows drivers | Microsoft Docs )

Please note that CyUSB library HID/Mass Storage library support is “AS IS”. Cypress isn’t maintaining this legacy implementation for long time (Starting CyUSB3 applications).

Best Regards

Ekta

View solution in original post

4 Replies
Ekta_N
Moderator
Moderator
Moderator
750 replies posted First like given 250 solutions authored

Hi KyTr_1955226

Can you please let me know if you are continuously calling the Process USB function?

According to me we should continuously keep checking if the data has been received in a for loop.

Also, can you please let me know why are you calling USBFS_EnableOutEP2() in the line 20?

Can you please attach your project? I have a USB Analyzer so I can check the transactions happening. In that case please let me know how you are transferring data from Host to the PSoC.

Best Regards

Ekta

0 Likes

EktaN_26 wrote:

Hi KyTr_1955226

Can you please let me know if you are continuously calling the Process USB function?

According to me we should continuously keep checking if the data has been received in a for loop.

Also, can you please let me know why are you calling USBFS_EnableOutEP2() in the line 20?

Can you please attach your project? I have a USB Analyzer so I can check the transactions happening. In that case please let me know how you are transferring data from Host to the PSoC.

Best Regards

Ekta

Process_USB is being called from my main loop.  It's not on any sort of timer, but it fires roughly every 20-30us (measured by toggling an IO on each call).  I usually want to avoid a for() loop in this sort of situation to avoid spinning in place waiting for USB data.

I actually do not know why I put that call to USBFS_EnableOutEP(2) after servicing EP1.  Possibly added it when tracking down another issue a long while back.  In any case, removing that call has no effect.

I unfortunately can't post up the whole project, but do appreciate the offer though to have a look with a USB Analyzer.  I should hopefully be getting mine back soon.

I will note though that this same Process_USB() works perfectly well in a different firmware (the one I based this newer code off of) so maybe I'm looking in the wrong place.

I did just try something that seems to have solved half the issue.  I just raised the priority of the USBFS Interrupts:

USBFS_arb_int

USBFS_bus_reset

USBFS_dp_int

USBFS_ep_0

USBFS_ep_1

USBFS_ep_2

These were all at Priority Level 7.  Bringing the ISR Priority down (or I guess up, technically) and the PSoC is now receiving and processing all the incoming commands with none missing.  Now the problem looks to be entirely in receiving the response back on the PC.

I measured the time between command reception by the PSoC and the response being loaded into EP1 and it comes out to <20ms.  So the 20ms interval is being met by the PSoC to return the response back to the PC on the first available EP1 report.  This leads me to suspect something funny going on with the CyUSB library.  When I adjust the reception code to the following, sending only once and looping to receive the response:

outbuffer[1] = Convert.ToByte('0');

outbuffer[2] = Convert.ToByte('0');

outbuffer.CopyTo(ApplicationHIDDevice.Outputs.DataBuf, 0);

ApplicationHIDDevice.WriteOutput();

while ((inbuffer[1] == 0x00) && (count < 100))

{

    status = ApplicationHIDDevice.ReadInput();

    inbuffer = ApplicationHIDDevice.Inputs.DataBuf;

    ApplicationHIDDevice.Inputs.DataBuf.CopyTo(inbuffer,0);

    count++;

}

With this, I still see count at around 30 before a response is detected.

Looking at the documentation for ReadInput():

pastedImage_2.png

It sounds like ReadInput() should be blocking until an input report is received, so if the PSoC is loading up EP1 with the response well within the 20ms report interval, why is ReadInput() supposedly taking up to 30 input reports to see the response?  Am I misunderstanding and ReadInput() isn't actually a blocking function?

Thanks again for the input!

0 Likes
Ekta_N
Moderator
Moderator
Moderator
750 replies posted First like given 250 solutions authored

Hello KyTr_1955226

Your understanding of the ReadInput() being a blocking all is correct. ApplicationHIDDevice.ReadInput is blocking call..so if the psoc is not ready with the data when requested, this will add to the delay.

Please refer to the following link for more details on the ReadInput function: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile​ . It is possible to read the return status of ReadInput call in the Host app. In the code you are storing the status of the readinput but it should be checked as well before incrementing the count variable

Also, I guess that you are using the old CyUSB.dll. The new one is available at:https://www.cypress.com/documentation/software-and-drivers/ez-usb-fx3-software-development-kit Note that in the newer version we do not provide WriteOutput and ReadInput APIs. It uses the use the standard hidsdi.lib (Hidsdi.h header - Windows drivers | Microsoft Docs )

Please note that CyUSB library HID/Mass Storage library support is “AS IS”. Cypress isn’t maintaining this legacy implementation for long time (Starting CyUSB3 applications).

Best Regards

Ekta

Hi Ekta,

Yes, this is a bootloader application based off the AN73503​, which uses the legacy CyUSB.dll.

I can probably port it over to the newer library at some point in the future when I have the time to figure it out.

Does the new version of CyUSB include references to these windows HID functions, or will I need to get those installed on my own with the Windows Driver SDK?

I think I did get this specific issue sorted out, reading LastError after ReadInput:

uint status = 0;

/*snipped - load output buffer*/

ApplicationHIDDevice.WriteOutput();

while ((inbuffer[1] == 0x00) && (count < 100))

{

     ApplicationHIDDevice.ReadInput();

     status = ApplicationHIDDevice.LastError;

    if (status == 0)

    {

          inbuffer = ApplicationHIDDevice.Inputs.DataBuf;

          ApplicationHIDDevice.Inputs.DataBuf.CopyTo(inbuffer, 0);

    }

    else

    {

          count++;

    }

                

}

This reads out the information on the first attempt.

Thanks for the assist!

0 Likes