I am developing a USB camera using a Micron Tech. (Aptina) CMOS image sensor and a CY7C68013 to interface it to a PC.
At the Hardware level:-
Image Sensor CY7C68013
PIXCLK------------>IFCLK
LINE_VALID-------->SLWR (active high)
FRAME_VALID------->ORed EP2 Empty--->PKTEND (active low)
D0..D11----------->FD0..FD11
PIXCLK is running at 5MHz, can be run up to 40MHz.
Each line consists of 648 pixels x 2 bytes, the maximum burst data rate is 10MB/s for ~129us. There is then a blanking period (LINE_VALID de-asserted) of 90-819us
for a line period of 219-1038us.
Note that the data from the sensor cannot be stopped during the frame. There is no flow control between the sensor and the FX2LP.
I am using EP2IN, AutoIN,BULK transfers, 512 byte 4x buffered. The device enumerates correctly, and I can receive data at the host. AutoINbytes is set to 0x0200
Theoretically, this is well within the capabilities of the FX2LP in High speed mode.
At the Host end, I am running a separate dedicated thread using CyAPI from C++.
(Code appended). It manages transfers using Begin...Wait...End transfer, with a queue depth of 8 (Queuedepth, and transfer/buffer size are settable in the #defines). This is pretty much adapted from the Streamer example.
However, multiple times during the frame, the FIFO becomes full (FF asserts) and data is lost. It appears that the Host is not reading from the FIFO fast/often enough. Even reading one 512byte packet per uFrame should be plenty. Is there any way to prevent this from happening?
FX2 Init Code
WORD i;
// bit res;
REVCTL=0x03;
SYNCDELAY;
// set the CPU clock to 12MHz
CPUCS=0x12; //0x02
// set the slave FIFO interface to Slave
IFCONFIG = 0x03;
EP1OUTCFG = 0xA0;
EP1INCFG = 0xA0;
SYNCDELAY;
EP6CFG = 0x00;
SYNCDELAY;
EP4CFG = 0x00;
SYNCDELAY;
EP8CFG = 0x00;
SYNCDELAY;
EP2AUTOINLENH = 0x02; // EZ-USB automatically commits data in 512-byte chunks
SYNCDELAY;
EP2AUTOINLENL = 0x00;
SYNCDELAY;
EP2CFG = 0xe0; // sets EP2 valid for IN's
// and defines the endpoint for 512 byte packets, 4x buffered
SYNCDELAY;
// EP2ISOINPKTS=2;
// SYNCDELAY;
FIFORESET = 0x80; // reset all FIFOs
SYNCDELAY;
FIFORESET = 0x02;
SYNCDELAY;
FIFORESET = 0x04;
SYNCDELAY;
FIFORESET = 0x06;
SYNCDELAY;
FIFORESET = 0x08;
SYNCDELAY;
FIFORESET = 0x00;
SYNCDELAY; // this defines the external interface to be the following:
EP2FIFOCFG = 0x0d; // this lets the EZ-USB auto commit IN packets, gives the
// ability to send zero length packets,
// and sets the slave FIFO data interface to 16-bits
SYNCDELAY;
PINFLAGSAB = 0x4c; // defines FLAGA as EP2 full flag
SYNCDELAY; // FLAGB as part full flag, as pointed to by FIFOADR[1:0] (not used)
PINFLAGSCD = 0x08; // FLAGC as EP2Empty
// won't generally need FLAGD
PORTACFG = 0x00; // used PA7/FLAGD as a port pin, not as a FIFO flag
SYNCDELAY;
FIFOPINPOLAR = 0x07; // set PKTEND Active LOW, SLWR Active HIGH,EF Active HIGH,
SYNCDELAY; //all other slave FIFO interface pins as active LOW
EP2FIFOPFH = 0x01; // you can define the programmable flag (FLAGA)
SYNCDELAY; // to be active at the level you wish
EP2FIFOPFL = 0x00;
Xfer Thread Code
CCyCam2Dlg *dlg = (CCyCam2Dlg *) params;
unsigned short *inbuf=dlg->inbuf;
OVERLAPPED ol[QUEUESIZE];
UCHAR *buffer[QUEUESIZE];
UCHAR *inContext[QUEUESIZE];
long len;
int qctr;
CCyUSBEndPoint *InEndpt;
InEndpt=dlg->InEndpt; //Get endpoint from calling dlg
InEndpt->SetXferSize(BUFFSIZE); //Set transfer size to buffer size
InEndpt->TimeOut=200;
// Set up buffers/overlapped structures
for(qctr=0;qctr<QUEUESIZE;qctr++)
{
buffer[qctr]=(PUCHAR)malloc(BUFFSIZE);
memset(buffer[qctr],0,BUFFSIZE);
ol[qctr].hEvent = CreateEvent(NULL, false, false, L"CYUSB_OUT");
}
// Start initial transfers
for(qctr=0;qctr<QUEUESIZE;qctr++)
{
len=BUFFSIZE;
inContext[qctr]=InEndpt->BeginDataXfer(buffer[qctr],len,&ol[qctr]);
dlg->LastUSBError=dlg->USBDevice->UsbdStatus;
}
//set destination buffer pointer to 0
dlg->inbufptr=0;
//start with queue entry 0
qctr=0;
for (;dlg->bLooping; )
{
//Wait for current transfer to complete
if (!InEndpt->WaitForXfer(&ol[qctr],2000))
{
InEndpt->Abort();
if (InEndpt->LastError == ERROR_IO_PENDING)
WaitForSingleObject(ol[qctr].hEvent,2000);
}
//Finish the transfer
len=BUFFSIZE;
if (InEndpt->FinishDataXfer(buffer[qctr],len,&ol[qctr],inContext[qctr]))
{
if (len) //we have data
{
memcpy(&dlg->inbuf[dlg->inbufptr],buffer[qctr],len); //copy to dest. buffer
dlg->inbufptr+=len/2; //buffer is array of WORD's
dlg->nLastBytes+=len; //update counters
dlg->nTotBytes+=len;
if (len!=BUFFSIZE) // Last packet in frame
{
dlg->nLastTrans=dlg->nLastBytes; //update count of bytes this frame
dlg->nLastBytes=0; //reset counter
dlg->inbufptr=0; //reset dest. buffer pointer
}
if (dlg->inbufptr>(MAXINBUF-BUFFSIZE)) //ensure don't overrun dest. buffer
dlg->inbufptr=(MAXINBUF-BUFFSIZE); //in case we miss end of frame
}
}
//Start new transfer
len=BUFFSIZE;
inContext[qctr]=InEndpt->BeginDataXfer(buffer[qctr],len,&ol[qctr]);
dlg->LastUSBError=InEndpt->NtStatus;
//update queue counter
qctr++;
if (qctr>=QUEUESIZE)
qctr=0;
}
//de-allocate buffers
for(qctr=0;qctr<QUEUESIZE;qctr++)
if (buffer[qctr])
free(buffer[qctr]);
//we are exiting
dlg->XferThread = NULL;
return true;
Edit: - escape "<" char to restore for loops.
|