- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Our system is working well with FX3 - it is a C#.net application that we are migrating to USB3.
We have found that when USB cable is pulled bulkendpt XferData call never exits or throws an exception, even though timeout is set.
...
try{
BulkOutEndPt.TimeOut = 500;
bResult = BulkOutEndPt.XferData(ref outData, ref numberOfBytesToWrite_CommandRead); // this line never exits !!
}
catch(Exception ex) {....
...
Adding support for .DeviceRemoved event, allows to at least know this has happened but the thread executing the Xfer remains blocked.
Has anyone had a similar experience ? any known workarounds ? - I presume we could move to asynchronous transfer but that seems a lot of work to deal with a rare fault condition, and I certainly wouldn't want to do that if I didn't know it would work.
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As a workaround to the problem I have now put the usb communications in a separate thread. This prevents a hung XferData call blocking the entire application. It also allows for independent timeouts from the controlling thread.
While testing it became clear that timeouts work as expected during normal operation, if for example more data is requested than is available.
The problem only occurs when the cable is disconnected
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
Can you please post your application code here.
This is not expected and we have not seen this issue so far.
The control center application is based on C# and uses XferData call to transfer data.
Thanks,
Yatheesh
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for your response - This is fully repeatable the system works fine while USB connected but hangs when the cable is pulled
- the full application is a large application that uses USB to communicate between PC and our servo-controller DSP product, - code below is full file at the bottom of the chain for FX3 USB comms.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using System.Threading;
using Servotest.D2R.CoreTypes;
using Servotest.Foundation.Exceptions;
using Servotest.Foundation.IO;
using Servotest.Foundation.Logging;
using Servotest.Foundation.Utils;
using Servotest.Foundation.Ui.Controls;
using Servotest.Foundation.Localization;
using CyUSB;
using System.Windows.Forms;
namespace Servotest.D2R.DspUsb.Hub {
// This makes use of the CyUSB.DLL to transfer data to and from the FX3
// Uses XferData which points to and In/Out endpoint depending on the direction of the data transfer
// The functions should be called from USBFPGA when in USB 3.0 mode
using FPGAWord = UInt32;
using FPGAWord_16 = UInt16;
using FPGAWord_3 = UInt32;
public class FX3_USB : IUSB {
bool bResult = false;
byte[] outData = new byte[1024*16], inData = new byte[1024 * 16];
int numberOfBytesReadIn = 16383;
int numberOfBytesReadIn_ReadData;
int numberOfBytesToWrite_CommandRead;
string HUB_Serial;
UInt32[] inData_uint = new UInt32[1024*4];
byte[] inData_clear = new byte[1024*16];
CyUSBDevice myFX3Device = null; // Create a USB device for our application called myFX3Device
CyUSBDevice myDevice = null; // myDevice represents the bulkloop device in this example
USBDeviceList usbDevices = null; // Dynamic list of USBdevcies bound to CyUSB.sys
CyBulkEndPoint BulkInEndPt = null; // We need one Bulk IN endpoint
CyBulkEndPoint BulkOutEndPt = null; // We need one Bulk OUT endpoint
CyControlEndPoint CtrlEndPt = null;
static int file_bytes;
byte[] file_buffer;
bool success;
const int VID_Boot = 0x04B4, PID_Boot = 0x00F3;
const int VID_FIFO = 0x04B4, PID_FIFO = 0x00F1;
internal const int MAX_BLOCK_SIZE_FOR_BOOTLOADER = 256;
internal const int FX3_EXTRA_READ_WORDS = 2;
private const string RBF_FILE_NAME_FOR_PROFINETFX3HUB = "ProfinetFX3Hub.rbf";
private const string RBF_FILE_NAME_FOR_FX3HUB = "FX3Hub.rbf";
private const string FX3_DOWNLOAD_IMAGE_FILE = "USB3_FPGA.img";
internal FX3_USB(out bool isColdBoot,ServotestFile fpgaExplicitFile)
{
isColdBoot = true;
if (usbDevices != null) usbDevices.Dispose();
usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);
myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice; // Represents a hub that already has a configured FPGA
myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device; // Represents a hub that without a configured FPGA
int iTryCount =0;
while ((myFX3Device == null) && (myDevice == null))
{
if (iTryCount++ > 50) {
throw new Exception ("Timeout looking for FX3 USB device #2");
}
Thread.Sleep(10);
TraceHelper.WriteLine(TraceCategory.Info, "Looking for the FX3 as either Device #1 ...");
usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);
Thread.Sleep(100);
myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device;
myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;
}
if ((myFX3Device == null) && (myDevice != null)) { // this is a warm boot as the FX3 is already running the FPGA/FIFO code
int len = 0;
byte[] buf = new byte[16];
CtrlEndPt = myDevice.ControlEndPt;
CtrlEndPt.Target = CyConst.TGT_DEVICE;
CtrlEndPt.ReqType = CyConst.REQ_VENDOR;
CtrlEndPt.Direction = CyConst.DIR_FROM_DEVICE;
CtrlEndPt.ReqCode = 0xB4; // reset FX3 from bootloader state
CtrlEndPt.Value = 0;
CtrlEndPt.Index = 1;
len = 16;
buf[0] = 0;
CtrlEndPt.XferData(ref buf, ref len);
TraceHelper.WriteLine(TraceCategory.Info, "Warm Boot. Rebooting FX3 to bootloader");
System.Threading.Thread.Sleep(1000);
isColdBoot = false;
TraceHelper.WriteLine(TraceCategory.Info, "Renumerating FX3.");
if (usbDevices != null) usbDevices.Dispose();
usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);
myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device;
myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;
iTryCount = 0;
while ((myFX3Device == null) && (myDevice == null)) {
if (iTryCount++ > 50) {
throw new Exception ("Timeout looking for FX3 USB device #2");
}
Thread.Sleep(500);
TraceHelper.WriteLine(TraceCategory.Info,"Looking for the FX3 as either Device #2 ...");
usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);
Thread.Sleep(100);
myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device;
myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;
}
}
if ((myFX3Device != null) && (myDevice == null))
{ // If myFX3Device != null, then hub FPGA is not configured and FX3 is a Bootloader
// This is a cold boot, FX3 bootloader code is running and FPGA is unconfigured.
HUB_Serial = myFX3Device.SerialNumber;
TraceHelper.WriteLine(TraceCategory.Info, "Serial Number: " + myFX3Device.SerialNumber);
CyFX3Device fx = myFX3Device as CyFX3Device;
FX3_FWDWNLOAD_ERROR_CODE enmResult = FX3_FWDWNLOAD_ERROR_CODE.FAILED;//SUCCESS;
string download_image_file = FX3_DOWNLOAD_IMAGE_FILE;
string filename = Path.Combine(ApplicationData.ApplicationFileLibrary.FullName, download_image_file);
int retry = 0;
while ((enmResult != FX3_FWDWNLOAD_ERROR_CODE.SUCCESS) && (retry < 5))
{
enmResult = fx.DownloadFw(filename, FX3_FWDWNLOAD_MEDIA_TYPE.RAM);
TraceHelper.WriteLine(TraceCategory.Info, "Programming of FX3 " + fx.GetFwErrorString(enmResult));
retry++;
if (retry > 0)
{
System.Threading.Thread.Sleep(100);
}
}
System.Threading.Thread.Sleep(1000);
//Getting rbf for FPGA and setting FX3 to serial out
long flen;
// there is only one type of Hub FPGA at the moment for USB3, combined function for 16port, demo and master slave
// in the future may have a way to select different types, possibly on Serial Number
//HubType = WorkOutUSBBaseBoardCombination(out var is300MHz, out var hasScramnet, out var hasProfinet, out var isdownloadable);
//if (HasProfinet) string rbf_name = RBF_FILE_NAME_FOR_PROFINETFX3HUB;
//else
string rbf_name = RBF_FILE_NAME_FOR_FX3HUB;
if (SerialNumber.Contains("P")) {
rbf_name = RBF_FILE_NAME_FOR_PROFINETFX3HUB;
}
string fname = Path.Combine(ApplicationData.ApplicationFileLibrary.FullName, rbf_name);
if (fpgaExplicitFile != null) { fname = fpgaExplicitFile.FullName;}
FileStream file = new FileStream(fname, FileMode.Open, FileAccess.Read);
flen = file.Length;
file_bytes = (int)flen;
file_buffer = new byte[file_bytes];
file.Read(file_buffer, 0, file_bytes);
file.Close();
//Getting rbf for FPGA and setting FX3 to serial out
int len = 0;
byte[] buf = new byte[16];
for (int iRetry = 0; iRetry < 4; iRetry++) {
usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);
if (usbDevices.Count > 0) break; // success
System.Threading.Thread.Sleep(5000);
TraceHelper.WriteLine(TraceCategory.Info, "retrying to get devices");
}
if (usbDevices.Count == 0) { throw new Exception ("FX3 USB Device Not found"); }
myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;
BulkOutEndPt = myDevice.EndPointOf(0x01) as CyBulkEndPoint;
buf[0] = (Byte)(file_bytes & 0x000000FF);
buf[1] = (Byte)((file_bytes & 0x0000FF00) >> 8);
buf[2] = (Byte)((file_bytes & 0x00FF0000) >> 16);
buf[3] = (Byte)((file_bytes & 0xFF000000) >> 24);
if (myDevice != null)
{
TraceHelper.WriteLine(TraceCategory.Info, "Writing configuration data to FPGA...");
CtrlEndPt = myDevice.ControlEndPt;
CtrlEndPt.Target = CyConst.TGT_DEVICE;
CtrlEndPt.ReqType = CyConst.REQ_VENDOR;
CtrlEndPt.Direction = CyConst.DIR_TO_DEVICE;
CtrlEndPt.ReqCode = 0xB2; // move to FPGA config mode
CtrlEndPt.Value = 0;
CtrlEndPt.Index = 1;
len = 16;
CtrlEndPt.XferData(ref buf, ref len);//Send vendor command to start configuration of the FPGA
myDevice.BulkOutEndPt.XferSize = 4096;//Set the endpoint sizes to 4096 for Slave FIFO
success = myDevice.BulkOutEndPt.XferData(ref file_buffer, ref file_bytes); //Check if the FPGA has been successfully configured
if (success == true)
{
TraceHelper.WriteLine(TraceCategory.Info, "Success");
}
else
{
TraceHelper.WriteLine(TraceCategory.Info, "Failure");
}
if (success == true)
{
TraceHelper.WriteLine(TraceCategory.Info, "FPGA configuration data has been sent to FPGA :"+ fname);
System.Threading.Thread.Sleep(1000);
CtrlEndPt.Target = CyConst.TGT_DEVICE;
CtrlEndPt.ReqType = CyConst.REQ_VENDOR;
CtrlEndPt.Direction = CyConst.DIR_FROM_DEVICE;
CtrlEndPt.ReqCode = 0xB1; // move from FPGA config mode to FIFO operating mode
CtrlEndPt.Value = 0;
CtrlEndPt.Index = 1;
len = 16;
buf[0] = 0;
CtrlEndPt.XferData(ref buf, ref len); //Send vendor command to change the FX3 to Slave FIFO
if (buf[0] == 1)
{
TraceHelper.WriteLine(TraceCategory.Info, "FX3 Slave FIFO interface is activated");
}
else
{
TraceHelper.WriteLine(TraceCategory.Info, "Configuration Failed");
}
}
}
System.Threading.Thread.Sleep(1000);
BulkOutEndPt = myDevice.EndPointOf(0x01) as CyBulkEndPoint; // Instantiating the endpoints
BulkInEndPt = myDevice.EndPointOf(0x81) as CyBulkEndPoint;
BulkOutEndPt.TimeOut = 500; // 5 seconds
BulkInEndPt.TimeOut = 500;
numberOfBytesReadIn = 16383;
//numberOfBytesReadIn = 64;
bResult = BulkOutEndPt.XferData(ref outData, ref numberOfBytesReadIn);
BulkInEndPt.XferData(ref inData, ref numberOfBytesReadIn); // This DUMMY Read is needed to clear the endpoints after initialisation
numberOfBytesReadIn = 16383;
bResult = BulkInEndPt.XferData(ref inData, ref numberOfBytesReadIn);
}
else
{
// not detected FX3 running FIFO/FPGA
TraceHelper.WriteLine(TraceCategory.Info, "FX3 Problem. Not in correct state.");
}
bool bIsFast = myDevice.bSuperSpeed;
if (bIsFast) {
TraceHelper.WriteLine(TraceCategory.Info, "Super Speed USB");
}
else {
TraceHelper.WriteLine(TraceCategory.Info, "Not Super Speed USB");
}
// TraceHelper.WriteLine(TraceCategory.Info, "Press enter to send write block to FPGA");
usbDevices.DeviceRemoved += new EventHandler(usbDeviceRemoved);
}
public FPGAWord[] ReadData(FPGAWord numberOfFPGAWords) {
numberOfBytesReadIn_ReadData = (int) (numberOfFPGAWords + FX3_EXTRA_READ_WORDS + 1) * 4;
try {
BulkInEndPt.TimeOut = 500;
bResult = BulkInEndPt.XferData(ref inData, ref numberOfBytesReadIn_ReadData);
}
catch (Exception ex) {
TraceHelper.WriteException(ex,"FX3 ReadData");
throw (ex);
}
Buffer.BlockCopy(inData, FX3_EXTRA_READ_WORDS * 4, inData_uint, 0, inData.Length - FX3_EXTRA_READ_WORDS * 4);
return inData_uint;
}
public bool CommandRead(FPGAWord[] outData_uint) {
Buffer.BlockCopy(outData_uint, 0, outData, 0, outData_uint.Length * 4);
numberOfBytesToWrite_CommandRead = 40;
try{
BulkOutEndPt.TimeOut = 500;
bResult = BulkOutEndPt.XferData(ref outData, ref numberOfBytesToWrite_CommandRead);
}
catch(Exception ex) {
TraceHelper.WriteException(ex,"FX3 CommandRead");
throw (ex);
}
return bResult;
}
public void CommandWriteAndData(FPGAWord[] Command, FPGAWord[] outData_uint) {
int numberOfBytesReadIn_clear = 16383; //RT // does not actually read these words GD
int CommandLength = Command.Length;
Array.Resize(ref Command, CommandLength + outData_uint.Length);
Array.Copy(outData_uint, 0,Command, CommandLength, outData_uint.Length);
byte[] outData_write = new byte[(Command.Length * 4)];
Buffer.BlockCopy(Command, 0, outData_write, 0, (Command.Length * 4));
int numberOfBytesToWrite = outData_write.Length+32;
try {
BulkOutEndPt.TimeOut = 500;
bResult = BulkOutEndPt.XferData(ref outData_write, ref numberOfBytesToWrite);
}
catch(Exception ex) {
TraceHelper.WriteException(ex,"FX3 CommandWriteAndData");
throw (ex);
}
BulkInEndPt.TimeOut = 500;
bResult = BulkInEndPt.XferData(ref inData_clear, ref numberOfBytesReadIn_clear); //RT //GD dummy read to clear the endpoint, returns 0 length array
}
public void WriteCommand(FPGAWord[] outData_uint) {
int numberOfBytesReadIn_clear = 16383; // does not actually read these words GD
Buffer.BlockCopy(outData_uint, 0, outData, 0, outData_uint.Length * 4);
Array.Resize(ref outData, outData_uint.Length * 4);
numberOfBytesToWrite_CommandRead = outData.Length + 32;
try {
BulkOutEndPt.TimeOut = 500;
bResult = BulkOutEndPt.XferData(ref outData, ref numberOfBytesToWrite_CommandRead);
} catch(Exception ex) {
TraceHelper.WriteException(ex,"FX3 WriteCommand");
throw (ex);
}
BulkInEndPt.TimeOut = 500;
bResult = BulkInEndPt.XferData(ref inData_clear, ref numberOfBytesReadIn_clear); //RT //GD dummy read to clear the endpoint, returns 0 length array
}
public string SerialNumber{
get{
return HUB_Serial;
}
}
public FPGAWord_16 FPGAWordRead(FPGAWord[] outData_uint) {
CommandRead(outData_uint);
uint numberOfWordsToRead = 7;
FPGAWord_3[] allData = ReadData(numberOfWordsToRead);
FPGAWord_3[] result = new FPGAWord_3[numberOfWordsToRead];
Array.Copy(allData, 0, result, 0, numberOfWordsToRead);
FPGAWord_16 out_word;
out_word = (FPGAWord_16) (allData[3] & 0x0000FFFF);
return out_word;
}
private void usbDeviceRemoved(object sender, EventArgs ea) {
USBEventArgs args = (USBEventArgs) ea;
TraceHelper.WriteLine (TraceCategory.Error , " -----------------------------------" );
TraceHelper.WriteLine (TraceCategory.Error , " FX3 DEVICE REMOVED :" + args.FriendlyName );
TraceHelper.WriteLine (TraceCategory.Error , " -----------------------------------" );
// TODO - improve handling to abort transactions in progress
// Need to find a way to terminate FX3 trasnaction in progres
if (usbDevices != null) {
usbDevices.Dispose();
}
// Even system exception doesn't work well
throw new Exception (" FX3 device removed");
}
internal static bool ModulePresent {
get {
bool device = false;
int i = 0;
while((i < 3) && (device == false)) {
CyUSBDevice myFX3Device = null; // Create a USB device for our application called myFX3Device
CyUSBDevice myDevice = null; // myDevice represents the bulkloop device in this example
USBDeviceList usbDevices = null;
Thread.Sleep(100);
usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);
myFX3Device = usbDevices[VID_Boot, PID_Boot] as CyFX3Device;
myDevice = usbDevices[VID_FIFO, PID_FIFO] as CyUSBDevice;
if ((myFX3Device != null)||(myDevice != null)){
device = true;
}
else {
device = false;
}
i++;
}
if (!device) {
TraceHelper.WriteLine(TraceCategory.Info, "(" + i.ToString() + ") FX3 device not found"); // debug only
}
return device;
}
}
}
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
Thank you for the code.
Can you try reproducing the same using the control center application?
The control center also uses the a similar method.
Thanks,
Yatheesh
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Many thanks - I have Cypress control center but I am not very familiar with it. Our DSP only send blocks of data on request from the PC - is there a way within control centre to setup a continuous loop of Write (BulkOut end point) followed by Read (BulkIn end point) ? - e.g. scripts
Best regards
Glen Wardrop
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Glen,
You will have to do it manually from the control center.
Also, can you try increasing the timeout in your application from 500 to 5000?
Thanks,
Yatheesh
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the rapid response - yes we have tested increasing the timeout settings. The timeout never expires. The DeviceRemoved event fires when the device is removed, but the XferData call never exits .
My colleagues are continuing to work with Control center to try to reproduce as you suggest.
Best regards
Glen
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As a workaround to the problem I have now put the usb communications in a separate thread. This prevents a hung XferData call blocking the entire application. It also allows for independent timeouts from the controlling thread.
While testing it became clear that timeouts work as expected during normal operation, if for example more data is requested than is available.
The problem only occurs when the cable is disconnected