Maximum transfer size for BeginDataXfer() / FinishDataXfer() with bulk endpoint

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

cross mob
siwrc_2591756
Level 1
Level 1

Hi

I'm using the CyAPI API for performing asychronous bulk transfers between the host (running Windows 10) and a Cypress FX3.

The FX3 is sending data to the host. The host application is only receiving on the bulk endpoint. The FX3 is sending relatively large chunks of data per transfer. I am successfully able to perform such large transfers up to approximately 4 MB.

Now I have new use case where the FX3 is sending more than 4 MB in a single transfer. I am calling BeginDataXfer() and FinishDataXfer() with the bufLen parameter set to 5 MB (5*1024*1024). The FX3 is performing transfers that are larger than 4 MB but smaller than 5 MB.

In this situation, the CyAPI API is behaving very strange. Firstly neither BeginDataXfer() or FinishDataXfer() are returning any errors, i.e. it looks like they are completing successfully from the point of view of my application. Typically, FinishDataXfer() will return with bufLen set to the maximum buffer size after completion. Sometimes it will also be less. I have found in the CyAPI documentation some hint that CyUSB3.sys driver is limited to 4 MB bulk transfer size.

I have the following questions.

1. Is it true that CyUSB3.sys driver is limited to 4 MB per bulk transfer?

2. If yes, is this a limitation of the driver or the operating system?

3. Is it possible to detect (via error checking) that I'm passing a bufLen parameter that is too large for CyAPI? I expect the API to know any size limitation and would therefore expect these functions to return an error if I'm trying to receive too much data.

4. How to get around this problem? Do I have to perform multiple calls to BeginDataXfer() / FinishDataXfer() per transfer?

5. How can I differentiate between the case when a transfer is exactly the size of bufLen and the case where the transfer is not finished yet and I need to call BeginDataXfer() / FinishDataXfer() again?

Thank you

0 Likes
1 Solution

Hi,

Please test with the attached driver.

This is only for Windows 10 and not MS certified but has Cypress digital signature.

Password for attachment: cypress

Regards,

Hemanth

Hemanth

View solution in original post

0 Likes
16 Replies
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi,

- Firstly, an URB is created when BeginDataXfer() is called.

- Regarding the limit: It comes from the Host Controller Driver and also specific to Operating System(and we have to rely on Microsoft Documentation for the info).

Below are the latest known links to us regarding the above info:

USB Transfer and Packet Sizes (Windows Drivers)​ and

USB Bandwidth Allocation - Windows drivers | Microsoft Docs

The above link does not cover Windows 10.

- I think if the transfer size exceeds than the operating system and the Host controller supports then BeginDataXfer() may fail. Please check for the same.

- Since you are implementing Asynchronous Transfers (i.e. BeginDataXfer(), WaitForXfer(), FinishDataXfer()), you can queue up few transfer and we do in Streamer Application. Please check for the same.

- You might already know the following. But just for discussion:

One URB created for certain size (i.e using BeginDataXfer()) returns under the following conditions:

a. When the requested data is sent by the device. OR

b. When a short packet (a USB packet less than max endpoint size) is received by the Host in the middle of the transfer. OR

c. When a zero length packet is received(by Host) in the middle of the transfer.

Regards,

Hemanth

Hemanth
0 Likes

Hi Hemanth

thanks for the reply.

-  I have seen this table, I think it is linked to from one of the Cypress answers. It says 32 MB for SuperSpeed on Windows 8, so I would assume (at least) the same for Windows 10 but this does not seem to be the case. I'm seeing this weird behavior start if I pass a buffer larger than 4 MB. Is there no further information from Cypress regarding this?

- I am performing the following error checks after each call to BeginDataXfer():

  - If the returned PUCHAR is NULL

  - If the UsbdStatus field of the endpoint is different from USB_STATUS_SUCCESS

  - If the NtStatus field of the endpoint is different from STATUS_SUCCESS

  Am I missing something here? The CyAPI reference documentation is not particularly clear on the error checking. All examples do not perform any error checking at all.

- I am queuing up multiple transfers already. But my design currently relies on the behavior that I have a completed transfer each time FinishDataXfer() has completed.

- I know about the conditions when a URB returns. I am concerned about the following case. Assume I am passing bufLen = 4*1024*1024 to BeingDataXfer(). Also assume that the driver connected to the FX3 actually performs a transfer of the exact same size, i.e. the last flag is asserted with the 1024*1024 32-bit word of the transfer. In my application FinishDataXfer() will return with the len parameter set to 4*1024*1024. How can my application tell that the current transfer has completed (i.e. the FX3 has received exactly 4*1024*1024 bytes for a single transfer) or that the transfer is still ongoing (i.e. the FX3 has received more than 4*1024*1024 bytes for a single transfer)?

Thank you

Update: I also had a look through the cyusb driver source code regarding this problem. Unfortunately I have no experience regarding (Windows) driver development. However, I found some pointers in the code that the cyusb driver should actually be able to handle this 4 MB limit. For example, in cyioctl.h there is a #define for BULK_STAGESIZE which is set to 0x400000 (equal to 4 Megabytes). Furthermore, the REQUEST_CONTEXT struct contains multiple fields under the comment "Adding paramter to send sub request to cary out large transfer.". These things are used in the corresponding IOCTL function in cyioctl.h but I do not understand the code. I'm assuming it should somehow be possible to pass bufLen > 4MB to CyAPI functions - but how?

0 Likes

Hi,

Regarding your last post:

"Also assume that the driver connected to the FX3 actually performs a transfer of the exact same size, i.e. the last flag is asserted with the 1024*1024 32-bit word of the transfer. In my application FinishDataXfer() will return with the len parameter set to 4*1024*1024. How can my application tell that the current transfer has completed (i.e. the FX3 has received exactly 4*1024*1024 bytes for a single transfer) or that the transfer is still ongoing (i.e. the FX3 has received more than 4*1024*1024 bytes for a single transfer)?"

From your first post, I understand that FX3 is sending data to the Host. But the above description tells other way round. Please clarify.

My comments:

- After a transfer has ended (which corresponds to 4MB or any size), the Host application has no way to know how much data FX3 has further. This is not a limitation and Host application should just ask for more data and the device can send how much it has. In case the device can't send the requested amount and if already sent data is a multiple of endpoint size, then the device has to send a zerolength packet.

If your Host application has to know howmuch data FX3 can send, before it makes the request (i.e URBs) is: you can implement a custom vendor command to get to know how much device can send.

Regards,

Hemanth

Hemanth
0 Likes

Hi Hemanth

yes, bulk transfers are going from the FX3 to the host.

Regarding zero-length packet: in my case an FPGA is driving the FX3 GPIF interface. Does this mean the FPGA firmware needs to know about the endpoint packet size so that PKTEND can be asserted in case the FPGA transmits an integer multiple of the endpoint packet size?

Regarding the 4MB limit, I have made some further tests.

I wrote a small FX3 firmware example project based on one of the Cypress examples. No GPIF interface is used, only the FX3. It can be used to perform the following test.

1) Host sends a control request to the FX3; this control request specifies the size of the following bulk transfer

2) The FX3 issues a single bulk transfer with the specified size using a MANUAL_OUT type DMA channel (I'm using a loop with CyU3PDmaChannelGetBuffer() and CyU3PDmaChannelCommitBuffer())

3) The host receives the bulk transfer using a buffer that is twice the size of the expected transfer size

4) The host verifies that the actual number of transferred data matches the initially expected transfer size

The goal is to experimentally determine the maximum bulk transfer size.

I have performed this test using CyAPI with cyusb3.sys driver and using libusb with WinUSB driver.

I am seeing different results depending on if I am using the Cypress stack or the libusb/WinUSB stack.

* With libusb/WinUSB I am able to perform bulk transfers that exceed 4MB successfully

* With the Cypress stack, the bulk transfer will fail as soon as the "bufLen" parameter of the XferData() function exceeds 4MB; everything works fine as long as the "bufLen" parameter is <= 4MB; note this seems to be independent of the actual transfer size: in this test I am performing a bulk transfer of 2MB on the FX3 and providing bufLen = 4MB + 1 byte to XferData() on the host application which results in a failure

Based on these tests my conclusion is that there is an issue passing bufLen > 4MB to XferData() (even if the actual transfer size is smaller than 4MB). Is this expected behavior according to Cypress? Or is this a known bug?

0 Likes

Hi,

yes, the FPGA firmware needs to know that a PKT_END/ZERO_LEN_PKT assertion is necessary when required. Please see the state machine  of AN65974 application note.

Regarding transfers larger than 4MB:

- You cannot request 4MB+1 bytes. The request should always be a multiple of endpoint max packet size. Please consider this in your test and check.

Meanwhile I will also experiment.

Regards,

Hemanth

Hemanth
0 Likes

Hi Hemanth

I have tried the same but using 4MB + 1024 to ensure that no matter the USB speed the request size will always be a multiple of the packet size (e.g. 512 for HighSpeed and 1024 for SuperSpeed).

Digging a bit more into what is actually failing in this case. XferData() internally uses BeginDataXfer(), WaitForIO() and FinishDataXfer(). When I request more than 4MB (even if the actual bulk transfer is less than 4MB in size), FinishDataXfer() will return an error.

Interestingly I am getting two different behaviors which seem to alternate randomly.

1. XferData() fails immediately (USBD_STATUS = 0x80000300 (USBD_STATUS_INVALID_PARAMETER) and NTSTATUS = 0xC000000D (STATUS_INVALID_PARAMETER) after FinishDataXfer())

2. XferData() hangs a couple of seconds then fails (USBD_STATUS = 0xC0010000 (USBD_STATUS_CANCELED) and NTSTATUS = 0xC0000120 (STATUS_CANCELLED) after FinishDataXfer())

Best

Simon

0 Likes

Hello Simon,

I have done the following tests:

-Setup: FX3 Explorer kit loaded with default USBBulkSrcSink firmware.

In the source code of C++ streamer app, in function - EnforceValidPPX(), max limit is imposed using the variable maxLen. Please note that this limit does not come from the cyusb3 driver as I have mentioned earlier. I have changed the limit from 0x400000 to 0x800000 and ran the streamer app by choosing Packets per Xfer as 512 and Xfers to Queue as 1. Reason for choosing 512: I have loaded FX3 with USBBulkSrcSink firmware which by default has burst set to maximum (16) for In Endpoint. So each URB that is created by streamer would be of size 512*16*1024 =  8MB. I was able to successfully stream the data.

- Setup: FX3 Explorer kit loaded with default USBBulkSrcSink firmware.

Run C# control center application. Choose In endpoint of streamer app. In the 'Data Transfers' tab on the right, in the section 'Bytes to transfer' I have entered 8388608 - 8MB. I was able to successfully stream the data.

Please test the above in a Windows 10 PC.

Regards,

Hemanth

Hemanth
0 Likes

Hi Hemanth

I was not yet able to reproduce the first test because I'm currently not able to recompile the C++ streamer application. Let me know if you still need this information (currently Visual Studio is not setup properly).

I was able to perform the your second test. I loaded the "USBBulkSrcSink" firmware and did some 8 MB transfers on the bulk IN endpoint 0x81. I am getting mixed results.

cycontrol_usbbulksrcsink_8mb.jpg

Sometimes the transfer will apparently complete successfully ("BULK IN transfer completed").

Sometimes the transfer will fail with error code 997. If I click on "URB Stat" in this case, it will show last error 0x80000300 which is the same error I also sometimes get with my example.

Are you running Windows 10? If yes, which cyusb3 driver are you using?

Edit #1: what version of Visual Studio are you using for compiling the C++ streamer application? I'm currently trying with Visual Studio 2017 but I'm getting many compiler errors.

Edit #2: I have also tried 8 MB transfers with my test application (using bufLen = 8 MB exactly). It will sometimes work successfully, sometimes it XferData() will report success but bufLen is set to 4 MB after the call, sometimes the same error as above occurs (0x80000300).

0 Likes

Hi Hemanth

is there any update on this? Is this being investigated further?

Kind regards

Simon

0 Likes

Hi Simon,

Please find the attached C++ Streamer for you to test(as mentioned in my previous post).

I am testing on Windows 10 and the cyusb3 driver version is 1.2.3.20

Password for the attachment is: cypress

Regards,

Hemanth

Hemanth
0 Likes

Hi Hemanth

thanks for this. I'm trying to use the same configuration you mentioned, i.e. "Packets per Xfer = 512" and "Xfers to Queue = 1", but I get the following error:

streamer_error.png

Regards

Simon

Edit: can you confirm that you never get errors when using the "Transfer Data-IN" feature of the USB Control Center application with the "USBBulkSourceSink" firmware? I will eventually get the error mentioned above ("Error Code:997"). Also the USB Control Center application will hang for a long time before showing success or error after clicking "Transfer Data-IN" with "Bytes to transfer: 8388608". Do you see the same behavior?

0 Likes

Hi Simon,

Please test with the attached utility. The change regarding the maximum limit was not updated in the utility that I had shared before.

Password for the attachment: cypress

It takes some time for control center to display the read data only after which I check Transfer-In once more. By doing the same, I don't see any errors.

Regards,

Hemanth

Hemanth
0 Likes

Hi Hemanth

thanks, this one works with the mentioned configuration. I am getting sporadic failures, typically a sequence of successes followed by a short "burst" of failures.

streamer.png

You are not seeing any failures at all?

I have checked that I'm using the same driver as you

driver.png

I am testing with the FX3 eval-kit.

Regards

Simon

0 Likes

Hi Simon,

- I have tried both the transfer types (Synchronous - using XferData() API and Asynchronous - using BeginDataXfer,WaitDataXfer, FinishDataXfer) for a data transfer larger than 4MB.

In both the cases the len parameter returned from the XferData() API and FinshDataXfer() are the same as the amount of data requested(since in my case FX3 is programmed with BulkSrcSink firmware - FX3 gives out data always).

- In the image showing Synchronous transfer, you can see that I have requested for 31MB and the transfer is success with the len parameter also reflecting the same.

In the image showing Asynchronous transfer, I have requested 8MB and you can see that the FinishDataXfer is reflecting the same.

So, I don't see any problem.

For your application, I suggest you to queue up more transfers instead of requesting huge URBs in one transfer.

FYI:

The Sync transfer tried by me was in a custom application. The Aync transfer was tried in streamer with little modifications.

Regards,

Hemanth

Hemanth
0 Likes

Hi Hemanth

please let us focus on the test case with the streamer application you sent me for now. This allows us both testing the exact same setup. Note that there is nothing in this setup that I have written myself, everything I use is provided by Cypress.

Now I'm getting failures in this streamer application so obviously there is a problem. I cannot simply reduce the transfer size in my application as this requires a major design change.

Again my questions

* Are you also testing with this exact setup, i.e. Windows 10 64-bit, FX3 eval-kit, USBBulkSourceSink FX3 firmware, Cypress driver 1.2.3.20 and the C++ streamer application you sent me?

* Are you not seeing any failures in the streamer application as I do?

If you are not seeing any errors we must find the difference between our setups. Please advise.

Regards

Simon

0 Likes

Hi,

Please test with the attached driver.

This is only for Windows 10 and not MS certified but has Cypress digital signature.

Password for attachment: cypress

Regards,

Hemanth

Hemanth
0 Likes