You are here

CY7C68013A USB Camera problem | Cypress Semiconductor

CY7C68013A USB Camera problem

Summary: 6 Replies, Latest post by alecha on 10 Feb 2011 10:39 AM PST
Verified Answers: 0
Last post
Log in to post new comments.
simongregory's picture
User
4 posts

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.

rushilnoronha's picture
User
3 posts

Hey,

I'm sure this is going to sound real stupid, but here goes: I just got started with the USB controller and I'm pretty much doing the same thing( building a camera module). I understood the part about the FX2 Initialization Code, I however don't quite understand the transfer thread code....what exactly is it doing and where do we need to use it?

andrewsobotka's picture
User
44 posts

Simon: I don't have any problems with double-buffered 64kB transfers, but I'm only doing 192 kB/s, so it takes like 333 ms to fill up just one of the buffers. Try tuning your buffer/queue sizes so that you can go up to 500 ms or so without your thread running.

rush: the transfer thread is using non-blocking asynchronous IO. It queues up several transfers without waiting for any of them to finish. Then, as a transfer finishes, the thread starts the transfer again. A more thorough discussion of async IO is beyond the scope of this post.

alecha's picture
User
11 posts

Hi! I've a question: what is CCyCam2Dlgclass??

andrewsobotka's picture
User
44 posts

malloc in C++? You must be old school...

A 5 MHz FIFO clock is very, very slow. That's one thing that stands out to me. But that would make your buffer fill up slowly, I don't see why it would slow the host down.

How big is BUFFSIZE? Typically, you want the USB driver to transfer data in big quantities, like a few KB at a time.

It looks like you're properly queuing transfers. I would get a statistical measure on overflows, like how long it takes to get 5 overflows on average. Then double or triple the queue size and see if it takes you longer to get overflows. If it does, then it looks like the host is just being slow.

Do you have other things plugged into the USB? Are you sure you're running at Hi-Speed and not Full-Speed? Are there any Low- or Full- speed devices on the same bus? Are you going through a hub?

You could also try not using auto-in. When you manually commit transfers, toggle a GPIO. You can use this method to see how fast the host is pulling data off of the device.

simongregory's picture
User
4 posts

Definately old school.  Would much prefer not to use C++ at all, but UI design is a pain without it

The 5 MHz FIFO clock is just for testing. Will probably use 24MHz for the final version. The PLL on the image sensor is very flexible.

I tried various sizes for BUFFSIZE (up to 8k) & QUEUESIZE (up to 128), but I think I wasn't being bold enough.

Setting BUFFSIZE to ~64k, QUEUESIZE to 8 seems to mostly cure the problem. I think windows scheduling is the cause, need enough work to last 'till the next time slice for the transfer thread. This is my first High Speed device, didn't have this problem before with Full Speed devices. Still getting the occasional FIFO overflow, but I think that this is just a matter of tuning.

Thanks for the suggestions.

simongregory's picture
User
4 posts

Thanks Andrew. Up to 256k buffers, with a queue size of 32, interrupt transfers with a 1024byte packet size. 14.5MB/s sustained without corrupted frames. (1600x1200 16bit ~3.7fps). I think this is as fast as I can sensibly go without writing a full kernel mode driver. This is an order of magnitude better in both speed and reliability than the previous, FullSpeed version.
rush: The XferThread code is basically a modified version of the screamer example. Just noticed that many of the initialising for loops are missing "<" in a code section

Log in to post new comments.