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()
	

Attachment: 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

Reply via email to