Hi All, I've been have a issue streaming data from an FPGA to a PC using the FX2LP and LibUSB. The FPGA is sending 8 bits to the FX2 at a rate of 20MHz (152 Mbps) using isochronous mode. The problem I'm having is that I cannot get data from the FX2's buffer to the PC fast enough and the buffer becomes full, causing me to miss some data. I'm not sure where the bottle neck is. The FX2 is set to iso mode, with 1024 bytes per packet, and 3 packets per microframe, so I should have enough bandwidth to empty the buffer. I'm attached my firmware (fpga.c), descriptor file, and libusb driver. The driver was written in Python using python-libusb1 wrappers. I have a LED on the FPGA board which will read the FULL flag on the FX2 and light an LED when full. By inspection, it looks like the LED is lit at about 50% duty cycle. I've been working on this for quite a while and would really appreciate any tips.
Thanks! Best Regards, Phil Behnke
import usb1
import time
import sys
import os
import threading
#this is a little messy since I dont clean up any of the threads, but its a quick and dirty prototype.
#claim and open the fx2
class IsoXfer():
def __init__(self):
#init stuff
self.context=usb1.LibUSBContext()
self.context.setDebug(3)
self.fx2=self.context.openByVendorIDAndProductID(0x04b4,0x1004)
self.fx2.claimInterface(0)
print "Transfer Object Done."
#submit URBs in its own thread.
class SubmitThread(threading.Thread):
def __init__(self, iso_xfer_object):
self.iso_xfer_object=iso_xfer_object
threading.Thread.__init__(self)
print "Armed."
def run(self):
while(1):
transfer_object1=self.iso_xfer_object.fx2.getTransfer(500)
transfer_object1.setIsochronous(endpoint=0x82,buffer_or_len=(1024*500),callback=self.createDataThread)
transfer_object2=self.iso_xfer_object.fx2.getTransfer(500)
transfer_object2.setIsochronous(endpoint=0x82,buffer_or_len=(1024*500),callback=self.createDataThread)
transfer_object3=self.iso_xfer_object.fx2.getTransfer(500)
transfer_object3.setIsochronous(endpoint=0x82,buffer_or_len=(1024*500),callback=self.createDataThread)
transfer_object4=self.iso_xfer_object.fx2.getTransfer(500)
transfer_object4.setIsochronous(endpoint=0x82,buffer_or_len=(1024*500),callback=self.createDataThread)
transfer_object5=self.iso_xfer_object.fx2.getTransfer(500)
transfer_object5.setIsochronous(endpoint=0x82,buffer_or_len=(1024*500),callback=self.createDataThread)
transfer_object1.submit()
transfer_object2.submit()
transfer_object3.submit()
transfer_object4.submit()
transfer_object5.submit()
#must sleep or LibUSB will start to fail
time.sleep(0.005)
#spawn a new thread to handle the data coming back
def createDataThread(self,newxfer):
newthread=HandleDataThread(newxfer)
newthread.start()
#this thread handles the incoming data.
class HandleDataThread(threading.Thread):
def __init__(self, iso_xfer):
threading.Thread.__init__(self)
self.my_xfer=iso_xfer
def run(self):
self.phoneHome()
def phoneHome(self):
print "We phoned home."
#print self.my_xfer.getBuffer()
#f=os.open('/home/phil/fx2lib-git/fx2lib/examples/fpga_iso/my_fifo',os.O_WRONLY)# | os.O_NONBLOCK)
#for i in usbxfer.getBuffer():
# os.write(f,i)
#os.close(f)
#this thread is dedicated to listening for events
class ListenThread(threading.Thread):
def __init__(self, iso_xfer_object):
self.iso_xfer_object=iso_xfer_object
threading.Thread.__init__(self)
def run(self):
while(1):
self.iso_xfer_object.context.handleEvents()
#main
if __name__=="__main__":
print "Test Harness"
test=IsoXfer()
print "Running Threads"
t2=ListenThread(test)
t1=SubmitThread(test)
t1.start()
t2.start()
dscr.a51
Description: Binary data
/**
* Copyright (C) 2009 Ubixum, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**/
#include <stdio.h>
#include <fx2regs.h>
#include <fx2macros.h>
#include <serial.h>
#include <delay.h>
#include <autovector.h>
#include <lights.h>
#include <setupdat.h>
#include <eputils.h>
#define SYNCDELAY() SYNCDELAY4
#define REARMVAL 0x80
#define REARM() EP2BCL=REARMVAL
volatile WORD bytes;
volatile bit gotbuf;
volatile BYTE icount;
volatile bit got_sud;
DWORD lcount;
bit on;
void main() {
REVCTL=0; // not using advanced endpoint controls
// d2off();
on=0;
lcount=0;
got_sud=FALSE;
icount=0;
gotbuf=FALSE;
bytes=0;
// renumerate
RENUMERATE_UNCOND();
SETCPUFREQ(CLK_48M);
//SETIF48MHZ();
sio0_init(57600);
USE_USB_INTS();
ENABLE_SUDAV();
ENABLE_SOF();
ENABLE_HISPEED();
ENABLE_USBRESET();
SYNCDELAY();
USBCS|=bmHSM;
SYNCDELAY();
//internal clk at startup to wait for ifclk from fpga, slave fifo mode
IFCONFIG=0x83;
SYNCDELAY();
//all wordwides must be zero to power on FPGA
EP2FIFOCFG = 0x0C; //, autoin, ZEROLENIN=1, wordwide=0
SYNCDELAY();
EP4FIFOCFG = 0x0; //wordwide=0
SYNCDELAY();
EP6FIFOCFG = 0x0; //wordwide=0
SYNCDELAY();
EP8FIFOCFG = 0x0; //wordwide=0
SYNCDELAY();
//This turns on the FPGA on my dev board (nexys2).
if(USBIE&bmHSGRANT){
OED |= bmBIT7;
IOD |= bmBIT7;
}
//wait for thet fpga to turn on
delay(5000);
//use the ifclk from the fpga, internally run at 48mhz, slave fifo mode
IFCONFIG=0x43;
SYNCDELAY();
REVCTL=0x03;
SYNCDELAY();
EP2ISOINPKTS=0x03;
SYNCDELAY();
EP2AUTOINLENH = 0x04; //1024 byte auto in length
SYNCDELAY();
EP2AUTOINLENL = 0x00;
SYNCDELAY();
EP2FIFOCFG = 0x4C;
SYNCDELAY();
EP4FIFOCFG = 0x0;
SYNCDELAY();
EP6FIFOCFG = 0x0;
SYNCDELAY();
EP8FIFOCFG = 0x0;
SYNCDELAY();
// only valid endpoint is 2
EP2CFG = 0xD8; //quad buffered here, IN, iso, 1024 bytes
SYNCDELAY();
EP6CFG &= ~bmVALID;
SYNCDELAY();
EP1INCFG &= ~bmVALID;
SYNCDELAY();
EP1OUTCFG &= ~bmVALID;
SYNCDELAY();
EP4CFG &= ~bmVALID;
SYNCDELAY();
EP8CFG &= ~bmVALID;
SYNCDELAY();
RESETFIFOS();
// make it so we enumberate
EA=1; // global interrupt enable
printf ( "Done initializing stuff\n" );
while(TRUE) {
if ( got_sud ) {
printf ( "Handle setupdata\n" );
handle_setupdata();
got_sud=FALSE;
}
}
}
// copied routines from setupdat.h
// value (low byte) = ep
#define VC_EPSTAT 0xB1
BOOL handle_vendorcommand(BYTE cmd) {
switch ( cmd ) {
case VC_EPSTAT:
{
xdata BYTE* pep= ep_addr(SETUPDAT[2]);
printf ( "ep %02x\n" , *pep );
if (pep) {
EP0BUF[0] = *pep;
EP0BCH=0;
EP0BCL=1;
return TRUE;
}
}
default:
printf ( "Need to implement vendor command: %02x\n", cmd );
}
return FALSE;
}
// this firmware only supports 0,0
BOOL handle_get_interface(BYTE ifc, BYTE* alt_ifc) {
printf ( "Get Interface\n" );
if (ifc==0) {*alt_ifc=0; return TRUE;} else { return FALSE;}
}
BOOL handle_set_interface(BYTE ifc, BYTE alt_ifc) {
printf ( "Set interface %d to alt: %d\n" , ifc, alt_ifc );
if (ifc==0&&alt_ifc==0) {
// SEE TRM 2.3.7
// reset toggles
RESETTOGGLE(0x02);
RESETTOGGLE(0x86);
// restore endpoints to default condition
RESETFIFO(0x02);
EP2BCL=0x80;
SYNCDELAY();
EP2BCL=0X80;
SYNCDELAY();
RESETFIFO(0x86);
return TRUE;
} else
return FALSE;
}
// get/set configuration
BYTE handle_get_configuration() {
return 1;
}
BOOL handle_set_configuration(BYTE cfg) {
return cfg==1 ? TRUE : FALSE; // we only handle cfg 1
}
// copied usb jt routines from usbjt.h
void sudav_isr() interrupt SUDAV_ISR {
got_sud=TRUE;
CLEAR_SUDAV();
}
bit on5;
xdata WORD sofct=0;
void sof_isr () interrupt SOF_ISR using 1 {
++sofct;
if(sofct==8000) { // about 8000 sof interrupts per second at high speed
on5=!on5;
if (on5) {d5on();} else {d5off();}
sofct=0;
}
CLEAR_SOF();
}
void usbreset_isr() interrupt USBRESET_ISR {
handle_hispeed(FALSE);
CLEAR_USBRESET();
}
void hispeed_isr() interrupt HISPEED_ISR {
handle_hispeed(TRUE);
CLEAR_HISPEED();
}
------------------------------------------------------------------------------ All of the data generated in your IT infrastructure is seriously valuable. Why? It contains a definitive record of application performance, security threats, fraudulent activity, and more. Splunk takes this data and makes sense of it. IT sense. And common sense. http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________ Fx2lib-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/fx2lib-devel
