Cypress CYUSB3KIT-003 USB3 device crash

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

cross mob
Anonymous
Not applicable

Hello,

Maybe one of you has encountered similar problems or can give some advice on this topic. Please see the problem description below:

Preliminary System Setup:

We use the Cypress CYUSB3KIT-003 USB3 device to stream a bigger amount of data from an FPGA capture card to a PC via USB3. The data streamed is composed within the FPGA to a BGR video pixel stream in HD resolution. On the PC side we have a Windows application which uses the Cypress API to access the USB device.

The PC application uses the CCyUSBEndPoint and the CCyUSBDevice API classes to ‘open’ a USB end point.

Our Problem:

During a session it possible that the USB device does not retrieve any new data from the FPGA capturer going to a time out. This could happen several times in a short time period. This causes either the application waiting for a transfer to be done or the USB driver crashes. After such a crash the device has to be reseted by pulling the USB connector to the PC.

The following approach for the communication with the USB device via the driver is used:

1. USB initialize:

   1.1 Open usb device and checks it, if it does not satisfy the conditions, then disconnects it and try to connect again. If a video stream disconnect signal appears, stop trying to connect.

   1.2 Create an array of empty buffers and a pointer to the OVERLAPPED structure and reset them, start the transfer.

2. Data transfer cycle:

   2.1 Wait for the end of the transfer of the i-th element.

   2.2 Finish the transfer of the element and save its status.

   2.3 Status handling:

      2.3.1 If an error is received at the end of the transfer or the overflow counter is greater than 8:

         2.3.1.1 Clear all information and delete the buffer pointers.

         2.3.1.2 USB initialize[1]

      2.3.2 Process the received data, save it and restart the transfer[2].

      2.3.3 Increment the transfer counter, to go to the next pointer in the OVERLAPPED structur

0 Likes
1 Solution

Hi,

--> During a session it possible that the USB device does not retrieve any new data from the FPGA capturer going to a time out. This could happen several times in a short time period. This causes either the application waiting for a transfer to be done or the USB driver crashes.

If you go through the implementation of "Streamer" Application source code that is available with the FX3 SDK, you will find that whether there is any data streaming from the device or not it will never crash, timeout will happen but not crash.

I suggest you to implement your application in the such a way that it will not crash even with no data.

I am attaching the code snippet of the Streamer application for your reference:

for (;bStreaming;)                                                                                 

            {

                long rLen = len; // Reset this each time through because

                // FinishDataXfer may modify it

                if (!EndPt->WaitForXfer(&inOvLap, TimeOut))    

                {

                    EndPt->Abort();

                    if (EndPt->LastError == ERROR_IO_PENDING)

                        WaitForSingleObject(inOvLap.hEvent,2000);

                }

For complete code you may refer to Streamer.h file on "C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\application\cpp\streamer"

Thanks & Regards

Abhinav

View solution in original post

0 Likes
5 Replies
abhinavg_21
Moderator
Moderator
Moderator
50 likes received 25 likes received 10 likes received

Hi,

You can set the timeout value in Xferdata API greater than the waiting time so that it will never time out. Cypress strongly recommend to use UVC class application to stream video. Could you please tell me why you are using a custom application to stream video.

Thanks & regards

Abhinav

0 Likes
Anonymous
Not applicable

Thank you for your input. We are going to investigate if the video streaming class is feasible for our use case and “special” video signal. Also we are going to try out the idea with an increased timeout setting.

We also request a little bit of help with our current solution. What are we doing wrong? Is there an “obvious” mistake we oversee?

What we have noticed is that the “WaitForXfer“ method was finished but always return false. This causes the program to hang in an endless loop or crashing.

Further help is much appreciated.

0 Likes

Hi,

Please mention what kind of transfer (synchronous or asynch) you are performing? If possible please share your application code.

Thanks & Regards

Abhinav

0 Likes
Anonymous
Not applicable

Hi,

thanks for your replay. Yes we can provide the important parts of the code here and explain how it is glued together.

This part of the application is “glued” together via a Qt queue with which the data is transferred to another thread. The USB code is running in its own thread which’s run method we see below:

void StreamProducer::run()

{

m_pClient = std::make_unique<RW::VGR::FG_USB::FX3VideoStreamer>(m_Logger);

if (m_pClient->iAppUsbInit() != FG_USB::AppReturnCode::APP_SUCCESS)

{

m_Logger->error("StreamProducer::run: Initialise failed!");

return;

}

m_bBreak = false;

FG_USB::FramebufferConfig_t fbConfig;

fbConfig.pingMat = std::make_shared<cv::Mat>(ROWS, COLS, CV_8UC3);

fbConfig.pongMat = std::make_shared<cv::Mat>(ROWS, COLS, CV_8UC3);

while (!m_bBreak)

{

if (m_pClient->bAppUsbStreamRx(&fbConfig))

{

std::shared_ptr<cv::Mat> pgMat = fbConfig.ping_pong ? fbConfig.pingMat : fbConfig.pongMat;

m_qMutex->lock();

m_qQueue->enqueue(pgMat);

m_qMutex->unlock();

}

}

}

Please note how the USB device is initialized (iAppUsbInit()) and then bAppUsbStreamRx() is called in a loop until the user of the software decides to stop (m_bBreak == true)

The class which handles the USB interaction and saves the sate is the following:

FX3VideoStreamer::FX3VideoStreamer(std::shared_ptr<spdlog::logger> Logger)

: m_Logger(Logger), m_pUSBDevice(nullptr)

{

m_iXferCount = 0;

m_lFbByteOffset = 0;

m_bBreak = false;

}

FX3VideoStreamer::~FX3VideoStreamer()

{

vAbortXferLoop();

}

/*****************************************************************

*  Looking for FX3 device with VID and PID (SS mode) and get EP  *

*****************************************************************/

int FX3VideoStreamer::iOpenDevice(int i)

{

SAFE_DELETE(m_pUSBDevice);

// Creating new pointer to USB device.

if (!m_pUSBDevice)

{

GUID guid = { 0xEE9E7C37, 0x4714, 0x4B31, 0x8A, 0xE1, 0x41, 0xE1, 0xE7, 0x8B, 0xB0, 0xF9 };

m_pUSBDevice = new CCyUSBDevice(NULL, guid);

}

// Opening USB device.

for (int j = 0; j < m_pUSBDevice->DeviceCount(); ++j)

{

if (m_pUSBDevice->IsOpen() || m_pUSBDevice->Open(j))

break;

m_pUSBDevice->Close();

}

// Verifying the USB device connection.

if (!m_pUSBDevice->IsOpen())

{

m_Logger->error("FX3VideoStreamer::iAppUsbInit: Couldn't open the Frammgrabber USB device");

return APP_ERROR_DEVICE_NOT_FOUND;

}

// Verifying the VendorID and ProductID.

if (m_pUSBDevice->VendorID != DEVICE_VID || m_pUSBDevice->ProductID != DEVICE_PID)

{

if (i == 0)

m_Logger->error("FX3VideoStreamer::iAppUsbInit: Wrong VedorID or ProductID");

m_pUSBDevice->Close();

return APP_ERROR_DEVICE_NOT_FOUND;

}

if (!m_pUSBDevice->bSuperSpeed)

{

if (i == 0)

m_Logger->error("FX3VideoStreamer::iAppUsbInit: Device not in SuperSpeed mode");

m_pUSBDevice->Close();

return APP_ERROR_DEVICE_NOT_IN_SS_MODE;

}

// Get a first bulk IN endpoint.

m_pEndPt = m_pUSBDevice->BulkInEndPt;

// Get buffer length and the endpoint's transfers size.

m_lRequestedXferSize = m_pEndPt->MaxPktSize * PACKETS_PER_XFER;

return APP_SUCCESS;

}

/*****************************************************************

*      USB initializing and preparing buffers and queue them     *

*****************************************************************/

int FX3VideoStreamer::iAppUsbInit()

{

// Opening USB device.

int iCounter = 0;

while (iOpenDevice(iCounter++) != APP_SUCCESS && !m_bBreak)

{

Sleep(10);

};

// Verifying break signal.

if (m_bBreak)

return APP_ERROR_UNKNOWEN;

m_iOverflowCounter = 0;

m_vBuffers.resize(XFERS_TO_QUEUE);

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

{

// Prepare buffers.

m_vBuffers.reset(new UCHAR[m_lRequestedXferSize]);

m_inOvLap.hEvent = CreateEvent(NULL, false, false, NULL);

memset(m_vBuffers.get(), 0xEF, m_lRequestedXferSize);

// First batch of transfer requests.

iBeginDataXFer(i);

}

return APP_SUCCESS;

}

/*****************************************************************

*                       Data streaming phase                     *

*****************************************************************/

bool FX3VideoStreamer::bAppUsbStreamRx(FramebufferConfig_t *m_fbConfig)

{

try

{

bool isFullFrame = false;

// Preset readLength with requester lenght.

long lLastXferSize = m_lRequestedXferSize;

// Wait till the transfer completion.

bWaitForTransferCompletion(m_iXferCount);

// Read the transferred data from the device.

bool bRetVal = m_pEndPt->FinishDataXfer(m_vBuffers[m_iXferCount].get(), lLastXferSize, &m_inOvLap[m_iXferCount], m_pContexts[m_iXferCount]);

m_bIsFinishedXFer[m_iXferCount] = true;

if (!bRetVal || m_iOverflowCounter > PACKETS_PER_XFER)

{

if (!m_bBreak)

{

m_Logger->error("FinishDataXfer returned false. LastError: {}", m_pEndPt->LastError);

vAbortXferLoop();

iAppUsbInit();

}

}

else

{

// Test if framebuffer has enough space

if (m_lFbByteOffset + lLastXferSize > ROWS*COLS * 3)

{

// Reset write pointer and toggle framebuffer.

m_lFbByteOffset = 0;

m_fbConfig->ping_pong = !m_fbConfig->ping_pong;

m_Logger->debug("-> Framegrabber overflow \n");

m_iOverflowCounter++;

}

else

{

// Write frame data to framebuffer.

if (m_fbConfig->ping_pong)

{

m_fbConfig->pongMtx.lock();

memcpy(m_fbConfig->pongMat->data + m_lFbByteOffset, m_vBuffers[m_iXferCount].get(), lLastXferSize);

m_fbConfig->pongMtx.unlock();

}

else

{

m_fbConfig->pingMtx.lock();

memcpy(m_fbConfig->pingMat->data + m_lFbByteOffset, m_vBuffers[m_iXferCount].get(), lLastXferSize);

m_fbConfig->pingMtx.unlock();

}

// Test if last buffer was full

if (lLastXferSize % m_pEndPt->MaxPktSize)

{

// Reset write pointer and toggle framebuffer.

m_lFbByteOffset = 0;

m_fbConfig->ping_pong = !m_fbConfig->ping_pong;

isFullFrame = true;

}

else

{

// Shift write pointer.

m_lFbByteOffset = m_lFbByteOffset + lLastXferSize;

}

}

// Re-submit this queue element to keep the queue full.

iBeginDataXFer(m_iXferCount);

}

m_iXferCount++;

if (m_iXferCount == XFERS_TO_QUEUE)

m_iXferCount = 0;

return isFullFrame;

}

catch (...)

{

return false;

}

}

void FX3VideoStreamer::vAbortXferLoop()

{

if (!m_vBuffers.empty())

{

m_pEndPt->Abort();

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

{

if (!m_bIsFinishedXFer)

{

m_pEndPt->FinishDataXfer(m_vBuffers.get(), m_lRequestedXferSize, &m_inOvLap, m_pContexts);

m_bIsFinishedXFer = true;

}

m_vBuffers = nullptr;

CloseHandle(m_inOvLap.hEvent);

}

}

SAFE_DELETE(m_pUSBDevice);

}

bool FX3VideoStreamer::bWaitForTransferCompletion(int i)

{

bool bRet = false;

while (!bRet)

{

Ret = m_pEndPt->WaitForXfer(&m_inOvLap, XFER_TIMEOUT);

if (!bRet)

{

m_Logger->debug("FramegrabberUsbConf::vWaitForTransferCompletion: WaitForXfer returned false. LastError = {}, Count = {}, packet = {} \n", m_pEndPt->LastError, m_iXferCount, i);

if (m_bBreak)

bRet = true;

}

}

return bRet;

}

int FX3VideoStreamer::iBeginDataXFer(int i)

{

int bRet = APP_ERROR_UNKNOWEN;

while (bRet != APP_SUCCESS)

{

m_pContexts = m_pEndPt->BeginDataXfer(m_vBuffers.get(), m_lRequestedXferSize, &m_inOvLap);

if (m_pEndPt->NtStatus || m_pEndPt->UsbdStatus)

{

if (m_bBreak)

{

bRet = APP_SUCCESS;

}

else

{

m_Logger->error("FramegrabberUsbConf::iBeginDataXFer: Xfer request rejected. NtStatus = {}, UsbdStatus = {}, Count = {}, packet = {} \n", m_pEndPt->NtStatus, m_pEndPt->UsbdStatus, m_iXferCount, i);

bReconnectDevice();

}

}

else

{

m_bIsFinishedXFer = false;

bRet = APP_SUCCESS;

}

}

return bRet;

}

bool FX3VideoStreamer::bReconnectDevice()

{

if (m_pUSBDevice != NULL)

return m_pUSBDevice->ReConnect();

return 0;

}

/* ############################## Header ##################################### */

#pragma once

#include <opencv2/core.hpp>

#include "AbstractModule.hpp"

#include <opencv2/core.hpp>

#include "AbstractModule.hpp"

#include <atomic>

#include <CyAPI.h>

#include "util.h"

#pragma warning (disable : 4996)

#define XFERS_TO_QUEUE 64

#define ROWS 720

#define COLS 1920

#include <atomic>

struct FramebufferConfig_t

{

std::atomic<bool> ping_pong;

std::mutex pingMtx;

std::mutex pongMtx;

std::shared_ptr<cv::Mat> pingMat;

std::shared_ptr<cv::Mat> pongMat;

};

enum AppReturnCode

{

APP_SUCCESS,

APP_ERROR_UNKNOWEN,

APP_ERROR_DEVICE_NOT_FOUND,

APP_ERROR_DEVICE_NOT_IN_SS_MODE,

APP_ERROR_BEGIN_XFER_FAILED,

APP_ERROR_XFER_TIMEOUT

};

class FX3VideoStreamer : public QObject

{

Q_OBJECT

int m_iXferCount;

long m_lFbByteOffset;

long m_lRequestedXferSize;

std::shared_ptr<spdlog::logger> m_Logger;

CCyUSBDevice *m_pUSBDevice;

CCyUSBEndPoint *m_pEndPt;

std::vector<std::unique_ptr<UCHAR[]>> m_vBuffers;

PUCHAR m_pContexts[XFERS_TO_QUEUE];

OVERLAPPED m_inOvLap[XFERS_TO_QUEUE];

bool m_bIsFinishedXFer[XFERS_TO_QUEUE];

FramebufferConfig_t m_fbConfig;

void vAbortXferLoop();

bool bWaitForTransferCompletion(int i);

int iBeginDataXFer(int i);

int iOpenDevice(int i);

bool m_bBreak;

int m_iOverflowCounter;

public:

explicit FX3VideoStreamer(std::shared_ptr<spdlog::logger> Logger);

~FX3VideoStreamer();

int iAppUsbInit();

bool bAppUsbStreamRx(FramebufferConfig_t *fbConfig);

bool bAbortEndpoint();

bool bResetEndpoint();

bool bResetDevice();

bool bReconnectDevice();

bool bResetFpga();

void SetBreak(bool bBreak)

{

m_bBreak = bBreak;

}

};

0 Likes

Hi,

--> During a session it possible that the USB device does not retrieve any new data from the FPGA capturer going to a time out. This could happen several times in a short time period. This causes either the application waiting for a transfer to be done or the USB driver crashes.

If you go through the implementation of "Streamer" Application source code that is available with the FX3 SDK, you will find that whether there is any data streaming from the device or not it will never crash, timeout will happen but not crash.

I suggest you to implement your application in the such a way that it will not crash even with no data.

I am attaching the code snippet of the Streamer application for your reference:

for (;bStreaming;)                                                                                 

            {

                long rLen = len; // Reset this each time through because

                // FinishDataXfer may modify it

                if (!EndPt->WaitForXfer(&inOvLap, TimeOut))    

                {

                    EndPt->Abort();

                    if (EndPt->LastError == ERROR_IO_PENDING)

                        WaitForSingleObject(inOvLap.hEvent,2000);

                }

For complete code you may refer to Streamer.h file on "C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\application\cpp\streamer"

Thanks & Regards

Abhinav

0 Likes