Flush stale data after error conditions

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

cross mob
mgiacomelli
Level 3
Level 3
25 replies posted 10 questions asked 25 sign-ins

I am struggling with getting stale GPIF data on the FX3 following host-side glitches or program crashes.  Presently, I configure 2 DMA channels from the GPIF and ping-pong back and forth from them to stream image data, which works.  However, if the host-side program crashes, and then is restarted, I get random data from the previous acquisition.

 

For example, if I configure a CY_U3P_DMA_TYPE_MANUAL_MANY_TO_ONE transfer, I can tag each buffer with a sequentially increasing number in the call back.  if I start a transfer with Begin/Wait/FinishDataXfer and then print the number sent on the host I get:

1 2 3 4 5 .... 4096  (each buffer I sent shows up in order at the host)

If instead I do Begin/Wait/FinishDataXfer and then close the program mid transfer, then launch it again, I get:

3387  3388  3389 3390 3391 3392  1 2 3 ...  (I get 6 buffers from the previous aborted transfer and then the new data)

This is shifting my image data and causing all kinds of data problems in the host application.  

I tried flushing the USB/DMA on start:

 

 

 

 

/* Place the EP in NAK mode before cleaning up the pipe. */
CyU3PUsbSetEpNak (CY_FX_EP_CONSUMER, CyTrue);
CyU3PBusyWait (125);

apiRetStatus = CyU3PDmaMultiChannelReset (&glDmaChHandleMulti);
if (apiRetStatus != CY_U3P_SUCCESS)
{
	CyU3PDebugPrint (4, "CyU3PDmaMultiChannelReset failed, Error code = 0x%x\n", apiRetStatus);
	CyFxAppErrorHandler(apiRetStatus);
}

//flush any stale data in the USB endpoint
CyU3PUsbFlushEp (CY_FX_EP_CONSUMER);
CyU3PUsbResetEp (CY_FX_EP_CONSUMER);	//not sure if required?


//Completely reset the entire GPIF state to be safe
apiRetStatus = CyU3PGpifLoad (&CyFxGpifConfig);
if (apiRetStatus != CY_U3P_SUCCESS)
{
	CyU3PDebugPrint (4, "CyU3PGpifLoad failed, error code = %d\n", apiRetStatus);
	CyFxAppErrorHandler (apiRetStatus);
}

//reconfigure the DMA
apiRetStatus = CyU3PDmaMultiChannelSetXfer (&glDmaChHandleMulti, CY_FX_GPIFTOUSB_DMA_TX_SIZE, 0);
if (apiRetStatus != CY_U3P_SUCCESS)
{
	CyU3PDebugPrint (4, "CyU3PDmaChannelSetXfer failed, Error code = %d\n", apiRetStatus);
	CyFxAppErrorHandler(apiRetStatus);
}

//remove NAK, not sure if I needed to do this?
CyU3PUsbSetEpNak (CY_FX_EP_CONSUMER, CyFalse);
CyU3PBusyWait (125);

//begin the GPIF state machine and start streaming data
apiRetStatus = CyU3PGpifSMStart(START, ALPHA_START);

 

 

 

 

 

However, I still get ~6 stale buffers if a transfer doesn't complete.  Is there something else I need to reset on the FX3?  Does the host side save USB data even after the receiving process terminates? 

0 Likes
1 Solution
18 Replies
JayakrishnaT_76
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hello,

Please let us know the how many buffers are allocated for the MANUAL Many to One channel. Have you allocated 6 buffers?

Also, when the host application is closed or stopped, does it send any command to the USB device?

Best Regards,
Jayakrishna
0 Likes

There are 2 sockets each with 3 buffers, so yes 6 total.  I tested a few times and always got 6, which is why I was trying to flush the DMA buffers, although I wasn't sure if maybe the data is stuck on host side somehow. 

In this case I am simulating a hard program crash, so I am terminating the process with no further device communication.  My goal is to be able to recover from this situation automatically.  

0 Likes

Hello,

Thank you for the clarification. I checked the code snippet that was shared earlier in your problem description. Can you please modify this part of the code as follows:

CyU3PGpifDisable (CyFalse);                   //Disable GPIF II interface

/* Place the EP in NAK mode before cleaning up the pipe. */
CyU3PUsbSetEpNak (CY_FX_EP_CONSUMER, CyTrue);
CyU3PBusyWait (125);

/* Reset and flush the endpoint pipe. */
CyU3PDmaMultiChannelReset (&glDmaChHandleMulti);

apiRetStatus = CyU3PDmaMultiChannelSetXfer (&glDmaChHandleMulti, CY_FX_GPIFTOUSB_DMA_TX_SIZE, 0);
if (apiRetStatus != CY_U3P_SUCCESS)
{
CyU3PDebugPrint (4, "CyU3PDmaChannelSetXfer failed, Error code = %d\n", apiRetStatus);
CyFxAppErrorHandler(apiRetStatus);
}
CyU3PUsbFlushEp (CY_FX_EP_CONSUMER);
CyU3PUsbSetEpNak (CY_FX_EP_CONSUMER, CyFalse);
CyU3PBusyWait (125);

Finally use the API CyU3PGpifSMSwitch () to switch to the start state. 

Please try the above and let me know if you find any improvement. 

Best Regards,
Jayakrishna
0 Likes

I tested that out and there was no change.  I still get 6 old buffers at the start of the new acquisition.  

One thing I have in my notes from a while back is that calling "CyU3PUsbStall" in my end acquisition function would prevent left over data from persisting into a future instance (for example, if the program chooses to end the acquisition early).  I am not sure if that is safe here however.

0 Likes

Hello,

It looks like the data is stuck at the host side. Can you please try calling Abort() for the endpoint from the host side when the application is started? Please let me know if there is a difference after trying this out.

Best Regards,
Jayakrishna
0 Likes

I added:

USBDevices[devices]->Open(fx3List[j]);
USBDevices[devices]->BulkInEndPt->Abort();

 

To the beginning of my program but I still see 6 extra buffers on the next run.   I will try further variations of this tomorrow, need to get some sleep for now.

0 Likes

Hello,

Can you please share the source code of the firmware project? We want to know when USB/DMA flush is done.

Best Regards,
Jayakrishna
0 Likes

Here is my firmware: https://imstore.circ.rochester.edu/GpifToUsb.zip


Thanks for looking at this!

0 Likes

Hello,

Please let me know if you receive a CLEAR FEATURE request on the firmware side the host application is closed.

The clear feature request can be handled in the following way

 switch (bmReqType)
    {       
case CY_U3P_USB_TARGET_ENDPT:
            if (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE)
            {
                if (wIndex == CY_FX_EP_BULK_VIDEO)
                {
                    /* Windows OS sends Clear Feature Request after it stops streaming,
                    
                    CyU3PDebugPrint (4, "Clear feature request detected...\r\n");

                    /* Clear the stall condition and sequence numbers. */
                    CyU3PUsbStall (CY_FX_EP_BULK_VIDEO, CyFalse, CyTrue);
                    CyFxApplnStop ();
                    uvcHandleReq = CyTrue;
                    /* Complete Control request handshake */
                    CyU3PUsbAckSetup ();
                }

 

You can refer to AN75779 firmware for the handling of clear feature request

Regards,
Rashi
0 Likes

I added:

 

	if(bRequest == CY_U3P_USB_SC_CLEAR_FEATURE)
		CyU3PDebugPrint (4, "Received a clear feature request! \r\n\r\n");

 

 

To CyFxApplnUSBSetupCB but the message never prints when the app is closed.  Stale data is then returned on the next run anyway.  

In further testing, the clear feature request is transmitted if the program calls "exit()" in Windows, but not if it crashes or is manually closed by the user.

 

 

0 Likes

After some more experimentation, I can generate the clear request using:   BulkInEndPt->Reset() (instead of Abort).  On the FX3 this calls a similar sequence of commands as recommended above:

 

CyU3PDmaMultiChannelReset (&glDmaChHandleMulti);
CyU3PUsbFlushEp(CY_FX_EP_CONSUMER);
CyU3PUsbResetEp (CY_FX_EP_CONSUMER);
CyU3PDmaMultiChannelSetXfer (&glDmaChHandleMulti, CY_FX_GPIFTOUSB_DMA_TX_SIZE, 0);
CyU3PUsbStall (wIndex, CyFalse, CyTrue);

 

Nonetheless this seems to very reliably flush all stale data, whereas calling it before I start the GPIF does not, so there must be some subtle difference.  Therefore I think my solution is to call  BulkInEndPt->Reset() anytime I am not sure about the FX3 state. 

0 Likes

Hello,

Thank you for confirming that the handling clear feature helped in clearing the DMA channel.

To call BulkInEndPt->Reset() independently , following sequence can be followed

CyU3PUsbStall (wIndex, CyFalse, CyTrue);
CyU3PGpifDisable (CyFalse);
CyU3PUsbSetEpNak (CY_FX_EP_BULK_VIDEO, CyTrue);
CyU3PBusyWait (125);
CyU3PDmaMultiChannelReset (&glDmaChHandleMulti);
CyU3PUsbFlushEp (CY_FX_EP_BULK_VIDEO);
CyU3PUsbSetEpNak (CY_FX_EP_BULK_VIDEO, CyFalse);
CyU3PBusyWait (125);


Please let me know if this works.

If the host app is closed/stopped completely, then maybe we can disable the GPIF state machine and put the DMA channel in the reset state. CyU3PDmachannelSetXfer puts the DMA channel in active state

Regards,
Rashi
0 Likes

No, that does not work.  The call to BulkInEndPt->Reset() must still happen or the stale data is not actually flushed.

Edit:  No I am wrong.  I copied the code as is, but wIndex was set to 0 instead of the actual endpoint I was trying to remove the stall from. 

CyU3PUsbStall (CY_FX_EP_CONSUMER, CyFalse, CyTrue);

Returns API success, but then the next transfer times out when i restart the DMA channel.

 

0 Likes

I recorded some wireshark traces with the above, and it really does seem that the FX3 sends the wrong data (not just that the Windows USB stack holds onto old data):fx3_no_flush.png

As you can see the DMA transfer number in wireshark also read 3551 on the first USB packet sent over the wire (should read 1 if data is new).  

I'm still not sure why  CyU3PUsbStall (CY_FX_EP_CONSUMER, CyFalse, CyTrue) causes bulk transfers to fail.  If I comment it out, stale data is sent.  If I leave it in, no data is ever sent.  Here is my code, maybe I am missing something?   https://pastebin.com/8P663wjW

0 Likes

Hello,

Thank you for the update.

The firmware link is not accessible. Please share the .zip file with the post.

Can you also share the snippet of the host application where BulkInEndPt->Reset() is called 

Regards,
Rashi
0 Likes
lock attach
Attachments are accessible only for community members.

 

I'm attaching an updated zip (the one used for the wireshark capture above).


To workaround this problem I call reset() like this on program start:

 

USBDevices[0] = new CCyUSBDevice(NULL);
USBDevices[0]->Open(fx3IndexList[0]);
USBDevices[0]->BulkInEndPt->Reset();

 

That is enough to flush out any old data from the device.

0 Likes

Hello,

To understand the flow of the application, please share the UART debug prints when the issue is seen. Also, please share the associated USB traces using Wireshark

Regards,
Rashi
0 Likes
0 Likes