EP0 Read() takes 5 seconds to complete.

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

cross mob
lock attach
Attachments are accessible only for community members.
dilic_2635671
Level 4
Level 4

I had hard time to response to my original post with attachments. So I create this new discussion.

I added the source code and the screen shot. Set the breakpoint on Rea and next statement, you can see from VS IDE how much time it take to execute that statement.

I am using VS2017 free community version. Thx

   bResult = ept->Read(rxBuf, bytesToSend);

   printf("txBuf[0-3] \r\n");

0 Likes
1 Solution
Anonymous
Not applicable

Hi milkfish1227_2635671

The CY_FX_RQT_SPI_FLASH_READ is a control IN Transfer. It occurs in 3 phase:

1) Host sends the bRequest CY_FX_RQT_SPI_FLASH_READ

2) The Device responds by sending data (CyU3PSendEp0Data).

3) Device acknowledges that control transfer is successful as below

isHandled = CyTrue;

return isHandled;

This whole thing above is a single control IN Transfer.

Similarly CY_FX_RQT_SPI_FLASH_WRITE is a control Out Transfer. It occurs in 3phase:

1) Host sends the bRequest CY_FX_RQT_SPI_FLASH_WRITE

2) The Device receives the data (CyU3PGetEp0Data).

3) Device acknowledges that control transfer is successful as below

isHandled = CyTrue;

return isHandled;

The whole thing is a single control OUT Transfer. But You have added CyU3PSendEp0Data between steps 2 and 3 above.

There are two problems in this:

1) An ongoing control out transfer is not yet completed.

2) The Control transfer must always be initiated by host (Both Control OUT and IN). You are trying to send data to host even without the host;s request.

So it will fail.

Regards,

-Madhu Sudhan

View solution in original post

0 Likes
16 Replies
dilic_2635671
Level 4
Level 4

Forgot the FX3 firmware code. I am using UsbSpiGpioMode project. It's in CyFxUSBSetupCB() for WRITE case.

The only thing this vendor request doing is loopback the data read from EP1.

CyBool_t

CyFxUSBSetupCB (

        uint32_t setupdat0,

        uint32_t setupdat1)

{

...

            case CY_FX_RQT_SPI_FLASH_WRITE:

                status = CyU3PUsbGetEP0Data (wLength, glEp0Buffer, NULL);

//                if (status == CY_U3P_SUCCESS)

//                {

//                    status = CyFxSpiTransfer (wIndex, wLength, glEp0Buffer, CyFalse);

//                }

                // for testing

                status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);

0 Likes
Anonymous
Not applicable

Hi,

Can you please check in your FX3 firmware, which part of the code execution takes much time? Did you check any other writes on your SPI Flash  in general and how much time it takes? If you comment out the SPI Flash code and just looping back the EP0 data is it taking this much time?

Please let us know your observations.

Regards,

-Madhu Sudhan

0 Likes
dilic_2635671
Level 4
Level 4

The FX3 firmware only get EP0 data, then send EP0 data. The time was take from host VS IDE. I haven't tried on Eclipse to measure the time yet.

In my post, I do have have host side VS solution. Can you give it a try to see if it happened on your side? I have been tried on different PCs.

            case CY_FX_RQT_SPI_FLASH_WRITE:

                status = CyU3PUsbGetEP0Data (wLength, glEp0Buffer, NULL);

//                if (status == CY_U3P_SUCCESS)

//                {

//                    status = CyFxSpiTransfer (wIndex, wLength, glEp0Buffer, CyFalse);

//                }

                // for testing

                status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);

0 Likes

Following image is the "Figure 8-37. Control Read and Write Sequences" in the "Universal Serial Bus Specification Revision 2.0" document.

GS003206.png

There are three kinds of sequences WRITE, READ, and NO-DATA.  When the vendor request CY_FX_RQT_SPI_FLASH_WRITE is handled, the WRITE sequence is attempted because there is a CyU3PUsbGetEP0Data() function to get the "Data Stage" packets from the HOST.  After these packets, the HOST expects to receive a "Status Stage" packet from the DEVICE.  Please note that the "Status Stage" cannot have any data in the packet.  "Status Stage" is just used for an acknowledge.

In your code snippet, CyU3PUsbSendEP0Data() API function is invoked after the "Data Stage" to generate a "IN" packet with some data.  This packet does not follow the USB specification.

If you want to receive some data from the FX3 device with a Control Transfer, the HOST must issue another Control READ Transfer.

Regards,

Noriaki

0 Likes
dilic_2635671
Level 4
Level 4

Any suggestions? I am stuck. Thx

0 Likes
dilic_2635671
Level 4
Level 4

I did have the Read() function in host app right after the Write(). See below. I did attached the host app solution in my first post.

int main()

{

   CCyUSBDevice *USBDevice = new CCyUSBDevice(NULL);

   //  Attempt to open device #0

   if (USBDevice->DeviceCount() && !USBDevice->Open(0))

   {

      USBDevice->Reset();

      USBDevice->Open(0);

   }

   //  Just for typing efficiency

   CCyControlEndPoint  *ept = USBDevice->ControlEndPt;

   ept->Target = TGT_ENDPT;

   ept->ReqType = REQ_VENDOR;

   ept->ReqCode = 0xC2;

   ept->Value = 0;

   ept->Index = 0;

   unsigned char  txBuf[256], rxBuf[256];

   ZeroMemory(txBuf, 256);

   ZeroMemory(rxBuf, 256);

   LONG bytesToSend = 4;

   bool bResult = true;

     

   txBuf[0] = 1;

   txBuf[1] = 2;

   txBuf[2] = 3;

   txBuf[3] = 4;

   bResult = ept->Write(txBuf, bytesToSend);

   bResult = ept->Read(rxBuf, bytesToSend);

   printf("txBuf[0-3] \r\n");

   for (int i = 0; i < bytesToSend; i++)

      printf("%d ", txBuf);

   printf("\r\n\r\nrxBuf[0-3] \r\n");

   for (int i = 0; i < bytesToSend; i++)

      printf("%d ", rxBuf);

   return 0;

}

0 Likes

I am saying "the Read() function in host app right after the Write()" is out of the USB specification.  The behavior of the HOST and device driver for that sequence may not be specified.

Regards,

Noriaki

0 Likes
dilic_2635671
Level 4
Level 4

Here is the Write/Read function ins CyAPI. I believe it should be doing the whole sequence of what you mentioned in USB spec.

Write( ) sets the CyControlEndPoint Direction member to DIR_TO_DEVICE and then calls CCyUSBEndPoint::XferData( ). The buf parameter points to a memory buffer where the read bytes will be placed. The len parameter tells how many bytes are to be read. Returns true if the write operation was successful. Passes-back the actual number of bytes transferred in the len parameter.

Read( ) sets the CyControlEndPoint Direction member to DIR_FROM_DEVICE and then calls CCyUSBEndPoint::XferData( ). The buf parameter points to a memory buffer where the read bytes will be placed. The len parameter tells how many bytes are to be read. Returns true if the read operation was successful. Passes-back the actual number of bytes transferred in the len parameter

0 Likes

How about the "Status Stage" transaction?

At the end of a Control Transfer, the "Status Stage" transaction must be handled.

Did you check the return value from the Write() and Read() method?

Regards,

Noriaki

0 Likes
dilic_2635671
Level 4
Level 4

Both return are true. See below example from CyAPI programmer's reference.

Are you saying this document is wrong?

Example

CCyUSBDevice *USBDevice = new CCyUSBDevice(NULL);

// Just for typing efficiency

CCyControlEndPoint *ept = USBDevice->ControlEndPt;

ept->Target = TGT_DEVICE;

ept->ReqType = REQ_VENDOR;

ept->ReqCode = 0x07;

ept->Value = 1;

ept->Index = 0;

unsigned char buf[512];

ZeroMemory(buf,512);

LONG bytesToSend = 128;

ept->Write(buf, bytesToSend);

CCyUSBDevice *USBDevice = new CCyUSBDevice(NULL);

// Just for typing efficiency

CCyControlEndPoint *ept = USBDevice->ControlEndPt;

ept->Target = TGT_DEVICE;

ept->ReqType = REQ_VENDOR;

ept->ReqCode = 0x07;

ept->Value = 1;

ept->Index = 0;

unsigned char buf[512];

LONG bytesToRead = 64;

ept->Read(buf, bytesToRead);

0 Likes

I am saying the firmware does not follow the USB specification.  Please go back to the Control Transfer sequence.

GS003206.png

Following is the behavior of the PC application and the FX3 firmware assumed by me..

(1) PC initiates a Control WRITE Transfer by calling the Write() method.  PC sends a SETUP packet as the Setup Stage.

(2) FX3 receives the SETUP packet and call the SetupCB() function.

(3) PC sends an OUT packet as the Data Stage.

(4) In the callback function FX3 receives the OUT packet by calling the CyU3PUsbGetEP0Data() function.

(5) When all data of the OUT packet received, FX3 sends an IN packet as the Status Stage.  The Control WRITE transfer completed.

(6) FX3 calls the CyU3PUsbSendEP0Data() function to send a packet.  The data is stored in the EP0 buffer and FX3 exit from the SetupCB() function.

(7) PC calls the Read() method to initiate a Control READ Transfer.  PC sends a SETUP packet as the Setup Stage.

(8) FX3 receives the SETUP packet and call the SetupCB() function again.

(9) PC waits for an IN packet as the Data Stage.  PC may receive a DATA packet set at the step (6)

(10) PC returns an OUT packet (with NO DATA) as the Status Stage.

(11) In the callback function FX3 receives an OUT packet (with NO DATA) sent at step (10) by calling the CyU3PUsbGetEP0Data() function.

(12) After the OUT packet received, FX3 sends an IN packet as the Status Stage.  But PC does not receive the packet because PC does not initiate any packet.

(13) After timeout time flies, the connection will be reset.

(14) FX3 calls the CyU3PUsbSendEP0Data() function to send a packet but PC does not receive the packet.

This issue is caused by the insufficient procedure in the SetupCB() function.

As I said in a reply "I recommend to define Control WRITE and READ transfer sequence separately to follow the USB specification."

Regards,

Noriaki

0 Likes
dilic_2635671
Level 4
Level 4

All right. You think the issue is in firmware SetupCB() function.

Here is from Cypress UsbSpiRegMode sample code CyFxUSBSetupCB() function. Do you think Cypress is not doing their sample code correctly?

CyBool_t

CyFxUSBSetupCB (

        uint32_t setupdat0,

        uint32_t setupdat1)

{

    /* Handle supported vendor requests. */

    if (bType == CY_U3P_USB_VENDOR_RQT)

    {

        switch (bRequest)

        {

            case CY_FX_RQT_SPI_FLASH_WRITE:

                status = CyU3PUsbGetEP0Data (wLength, glEp0Buffer, NULL);

                if (status == CY_U3P_SUCCESS)

                {

                    status = CyFxSpiTransfer (wIndex, wLength,

                            glEp0Buffer, CyFalse);

                }

                break;

0 Likes

The Cypress's example code is correct.  It is working.

The problem is the following lines you added to the original example code.

                // for testing

                status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);

The control transfer does not have an ability to execute a loopback as I described with the control transfer sequence figure.

0 Likes
dilic_2635671
Level 4
Level 4

All right. Here is example code in the same function switch case. Do you think control transfer can't call CyU3PUsbSendEP0Data() ?

            case CY_FX_RQT_SPI_FLASH_READ:

                CyU3PMemSet (glEp0Buffer, 0, sizeof (glEp0Buffer));

                status = CyFxSpiTransfer (wIndex, wLength,

                        glEp0Buffer, CyTrue);

                if (status == CY_U3P_SUCCESS)

                {

                    status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);

                }

                break;

0 Likes
Anonymous
Not applicable

Hi milkfish1227_2635671

The CY_FX_RQT_SPI_FLASH_READ is a control IN Transfer. It occurs in 3 phase:

1) Host sends the bRequest CY_FX_RQT_SPI_FLASH_READ

2) The Device responds by sending data (CyU3PSendEp0Data).

3) Device acknowledges that control transfer is successful as below

isHandled = CyTrue;

return isHandled;

This whole thing above is a single control IN Transfer.

Similarly CY_FX_RQT_SPI_FLASH_WRITE is a control Out Transfer. It occurs in 3phase:

1) Host sends the bRequest CY_FX_RQT_SPI_FLASH_WRITE

2) The Device receives the data (CyU3PGetEp0Data).

3) Device acknowledges that control transfer is successful as below

isHandled = CyTrue;

return isHandled;

The whole thing is a single control OUT Transfer. But You have added CyU3PSendEp0Data between steps 2 and 3 above.

There are two problems in this:

1) An ongoing control out transfer is not yet completed.

2) The Control transfer must always be initiated by host (Both Control OUT and IN). You are trying to send data to host even without the host;s request.

So it will fail.

Regards,

-Madhu Sudhan

0 Likes
dilic_2635671
Level 4
Level 4

Hi,

Your explanation sounds reasonable but

- there is no error even an host OUT request with EP0 CyU3PSendEp0Data firmware response

- the Read() 5 seconds delay doesn't fixed even with IN request.

Thanks.

0 Likes