Challenges with USB transfer

I have a custom piece of hardware that uses the XEM-3005 as its brains. My application code on the mac tells my FPGA code how many packets of data to acquire and over what time period. This varies from a minimum of 4 packets over one second to a maximum of 400 packets over approximately 25 ms. Each packet consists of 2048 bytes and I can’t afford to miss a single byte.

I had developed a fairly workable approach. I would write the key parameters to the FPGA using SetWireInValue. Then I would ActivateTriggerIn to start the acquisition sequence on the FPGA. Immediately after that I would use ReadFromBlockPipeOut to acquire the number of bytes that were expected. I did all these steps in a real-time thread, which is of course a soft concept on the mac.

This approach worked, with some careful tuning of the real-time thread parameters. Lucky me though, I got a new macbook pro and the old code no longer works. I drop data, which is fatal in this application.

I can try to hand tune the real-time thread parameters and hopefully get it right, but it seems to me that there must be a better way. I’m open to any and all suggestions, although I’d rather avoid placing all the acquired data in RAM and doing a bulk transfer, just because I want to minimize my changes.

Thanks in advance for any insights.

@bwalker- Unfortunately, I’m afraid you’ve already alluded to the most reliable solution here. The best way to avoid data underrun or overrun in a non-real-time system is with adequate buffering.

Without the hard guarantees of a real-time system, it’s the only sure way to protect against system changes like this.

I am wondering if there is a way to make sure that the OS doesn’t leave the current thread while waiting for the remainder of the data block. Setting the thread as realtime seems one possibility, but I wonder if there is a way to alter the driver to hold a larger buffer or perhaps to set a higher priority for data transfer?

Not through the API, certainly. There may be specific methods through the Apple internals, but we’re not aware of them. Your best bet would be to cut back on services running if you can.

The suggestion of cutting back on services seems reasonable, but, I’ve just migrated to a much faster computer and that is what broke my code. On my old macbook pro with an intel core duo it worked. On my new macbook pro with an i5 it stopped working. Speed it seems is my enemy, not my friend!

Is it possible to share any more information about the driver or how BTpipe transfers work so that I can try to tune the call to work more reliably?

Unfortunately, no. There really isn’t any information (proprietary or not) that would help your communication be more reliable. The truth is, in a non-realtime system, you are always going to be chasing this sort of issue.

The solution is to make your system more robust to such delays. That involves adding buffering. We even provide the RAMTester sample as an example of transferring data to/from the SDRAM with a basic controller. With a few tweaks on this sample, you can run data from a different source into the SDRAM and then read it out with the PC.

I’m performing BTpipe transfers and they work often. But, sometimes not. I’ve tried to get error codes to figure out what is happening and all I see is that the returned code is -1, Failed. Is there a way to get more insight into the failure?

Hm. A simple Failed code represents a failure of one of the underlying calls to USB fails. There isn’t any further information available.

What are the conditions under which this happens?

Not sure what info you would like.

The FPGA runs a state machine which collects data from an A/D converter in blocks at set intervals. I decide before an acquisition how many times the block should be filled. I set up counters in the FPGA and I tell the application code to do a throttled block pipe transfer from the fpga to the application. If I am doing 400 blocks of acquisition then the pipe transfer call from the application code has a transfer size of 400*N where N is the block size. This whole thing always used to work on my old macbook pro with a realtime thread. On my new one it works about 90-95% of the time, but when it fails I just get Failed (error code -1).

Does the RAMTester sample work?

I’ve got an old libFrontPanelMac.a which doesn’t contain the 64 bit versions I need. Compile error:

warning: in …/…/libFrontPanelMac.a, missing required architecture x86_64 in file

You had previously sent me a dylib that had the x86_64 architecture

Why can’t you use the new dylib with RAMTester?

I go into the directory for version 3.0.11 and this is what happens:

pwd
/Users/wfw5h/Desktop/New SR System/FrontPanel-Mac-3.0.11/Samples/RAMTester/Cxx

usguest:Cxx wfw5h$ make
g++ -o RAMTester RAMTester.o -arch i386 -framework Carbon -framework IOKit …/…/libFrontPanelMac.a
Undefined symbols:
“_okFrontPanelDLL_GetVersion”, referenced from:
_main in RAMTester.o
“okCUsbFrontPanel::LoadDefaultPLLConfiguration()”, referenced from:
initializeFPGA() in RAMTester.o
“_okFrontPanelDLL_LoadLib”, referenced from:
_main in RAMTester.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [RAMTester] Error 1

Switch to 3.1.0

usguest:Cxx wfw5h$ pwd
/Users/wfw5h/Desktop/New SR System/FrontPanel-Mac-3.1.0/Samples/RAMTester/Cxx

usguest:Cxx wfw5h$ make
g++ -o RAMTester RAMTester.o -arch i386 -framework Carbon -framework IOKit …/…/libFrontPanelMac.a
Undefined symbols:
“_okFrontPanelDLL_GetVersion”, referenced from:
_main in RAMTester.o
“okCUsbFrontPanel::LoadDefaultPLLConfiguration()”, referenced from:
initializeFPGA() in RAMTester.o
“mt_init()”, referenced from:
_main in RAMTester.o
“mt_random()”, referenced from:
writeSDRAM(okCUsbFrontPanel*, int) in RAMTester.o
“_okFrontPanelDLL_LoadLib”, referenced from:
_main in RAMTester.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [RAMTester] Error 1

Hm. Looks like we have an updated Makefile for OS X that hasn’t been released yet. You should be using the dylib, not a static lib:

[CODE]PROGRAM = RAMTester
FRAMEWORKS = -framework Carbon -framework IOKit
CXX = g++
OBJECTS =
RAMTester.o
mt_random.o
okFrontPanelDLL.o

.SUFFIXES: .o .cpp

all: $(PROGRAM)

(OBJECTS): %.o:%.cpp (CXX) -DMACOSX -I…/… -c $<

(PROGRAM): (OBJECTS)
(CXX) -o (PROGRAM) (OBJECTS) (FRAMEWORKS)

clean:
rm -f *.o $(PROGRAM)

[/CODE]

Can you point me to these source files? They’re not on my mac install anywhere, and I have not had luck goolging for the correct version. Thanks.

Hm. That wasn’t in your distribution? It should be in the same directory as RAMTester.cpp

Here it is.


mt_random.zip (1061 Bytes)

Terrific, that compiled with just a warning and no errors.

Would you mind sending the bit file for this for the XEM3005? They’re not in my mac build either.

Thanks.

I pulled the bit file out of another distribution. Ran the code and everything worked great. So, that leaves me believing that the hardware is fine and the software / firmware combination is the problem. I’m stuck though as to how to troubleshoot that.

Passed: 99 Failed: 0
Generating random data…
Writing to memory(0)…
Reading from memory(0)…
Passed: 100 Failed: 0

Still hoping for some insights on how to debug this failure mode…