Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

USB superspeed peripherals Forum Discussions

rossi
Level 3
Level 3
25 sign-ins First solution authored 10 replies posted

Hello,

Webcam provides only isochronous endpoint for data transferring. Bulk is not supported as we know.
Therefore it looks quite obivious that the USB 2.0 host firmware which deals with webcam as a device should open its endpoint as isochronous. A question on this was dealt in the following thread.


In an effort to receive webcam MJPEG stream in my host firmware, I'm facing a problem which I can't reasonably explain.

  • Test environment
    For experiment, I defined macro "BULK" which turns on the setting for bulk transfer and on the other case(When BULK is not defined), isochronous is activated.
    • - Endpoint and DMA channel is created as below (see endpoint.c)
    • - MJPEG stream is received by UvcRecvThread function (see UvcRecvThread.c)
  • Test Results
    • - isochronous case (when "BULK" is not defined), the full log can be found in "iso.txt".
    • - bulk case, the full log is "bulk.txt"

Question

  1. I thought that the host firmware must use isochronous endpoint because webcam only supports isochronous endpoint. But as we see in the above test, it was also possible to receive data through bulk as well.
  2. Though I could receive data both in isochronous and bulk mode, there were significant difference between them.
    The MJPEG stream is a series of jpegs. A jpeg image starts with SOI(Start of Image, 0xffd8) and ends with EOI(End of Image, 0xffd9). When I searched for the iso.txt, I could find only 1 SOI while 211 EOIs. This means I lost quite a lot of SOIs except the very first one. In contrast, in bulk.txt, I could find 115 SOIs and 127 EOIs.
    I think that isochronous endpoint is the right choice but the result is not what I expected. In isochronous case, the result shows I'm missing many important data from the webcam.
  3.  Bulk test case seems quite promising regardless if it is a right one or not. In my long term test, after few hours of running, the thread gets stuck.

Regards,
Rossi

0 Likes
1 Solution
Rashi_Vatsa
Moderator
Moderator
Moderator
5 likes given 500 solutions authored 1000 replies posted

Hello,

As the issue seems to be due to bandwidth, you can try requesting more data (in multiples of 3072(max packet size)) from the USB host side (FX3) so that packets do not get dropped.

Also, can you try alternate setting with lower bandwidth to check if with lower bandwidth the packets are dropped?

Regards,
Rashi

View solution in original post

0 Likes
5 Replies
rossi
Level 3
Level 3
25 sign-ins First solution authored 10 replies posted

endpoint.c (Endpoint and DMA setup)

 

    glHostUvcEp = 0x81;
    size = 1024;    
	
	/* Initialize the UVC */
    CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof(epCfg));
#ifdef BULK
    //Bulk
    epCfg.type = CY_U3P_USB_EP_BULK;
    epCfg.mult = 1;
    epCfg.pollingRate = 1;
#else
    //Isochronous
    epCfg.type = CY_U3P_USB_EP_ISO;
    epCfg.mult = 3;
    epCfg.pollingRate = 0;
#endif
    epCfg.maxPktSize = size;
    /* Since DMA buffer sizes can only be multiple of 16 bytes and
     * also since this is an interrupt endpoint where the max data
     * packet size is same as the maxPktSize field, the fullPktSize
     * has to be a multiple of 16 bytes. */
    size = ((size + 0x0F) & ~0x0F);
    epCfg.fullPktSize = size;
    epCfg.isStreamMode = CyFalse;
    status = CyU3PUsbHostEpAdd (glHostUvcEp, &epCfg);
    if (status != CY_U3P_SUCCESS)
    {
        goto enum_error;
    }

    /* Create a DMA channel for this EP. */
    CyU3PMemSet ((uint8_t *)&dmaCfg, 0, sizeof(dmaCfg));
    dmaCfg.size = size;
    dmaCfg.count = CY_FX_HOST_DMA_BUF_COUNT;
    dmaCfg.prodSckId = (CyU3PDmaSocketId_t)(CY_U3P_UIB_SOCKET_PROD_0 + (0x0F & glHostUvcEp));
    dmaCfg.consSckId = CY_U3P_CPU_SOCKET_CONS;
    dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
    dmaCfg.notification = CY_U3P_DMA_CB_PROD_EVENT;
    dmaCfg.cb = NULL;
    dmaCfg.prodHeader = 0;
    dmaCfg.prodFooter = 0;
    dmaCfg.consHeader = 0;
    dmaCfg.prodAvailCount = 0;
    status = CyU3PDmaChannelCreate (&glHostUvcCh, CY_U3P_DMA_TYPE_MANUAL_IN, &dmaCfg);
    if (status != CY_U3P_SUCCESS)
    {
        goto app_error;
    }

 

 

 

UvcRecvThread.c

 

void
UvcRecvThread(
		uint32_t Value)
{
	uint8_t buffer[1024*4];
	CyU3PReturnStatus_t status;
    CyU3PUsbHostEpStatus_t epStatus;
    uint32_t prodXferCount = 0;
    uint32_t consXferCount = 0;
    CyU3PDmaState_t state = 0;
    CyU3PDmaBuffer_t buf_p;

#ifdef BULK
    //Bulk
    uint16_t count = 1024;
#else
    //Isochronous
    uint16_t count = 3*1024;
#endif

	CyU3PThreadSleep (3000);
	CyU3PDebugPrint(4,"UvcRecvThread starts\r\n");
	for (;;)
	{
        buf_p.buffer = buffer;
        buf_p.count  = 0;
        buf_p.size   = ((count + 0x0F) & ~0x0F);
        buf_p.status = 0;

        CyU3PDebugPrint(4,"CyU3PDmaChannelSetupRecvBuffer...\r\n");
        status = CyU3PDmaChannelSetupRecvBuffer (&glHostUvcCh, &buf_p);
        CyU3PDebugPrint(4,"CyU3PDmaChannelSetupRecvBuffer status=0x%x,size=%d\r\n",status,buf_p.size);
        if(status!=CY_U3P_SUCCESS) continue;

        CyU3PDebugPrint(4,"CyU3PUsbHostEpSetXfer(%d)...\r\n",count);
        status = CyU3PUsbHostEpSetXfer (glHostUvcEp,CY_U3P_USB_HOST_EPXFER_NORMAL, count);
        CyU3PDebugPrint(4,"CyU3PUsbHostEpSetXfer status=0x%x,count=%d\r\n",status,count);
        if(status!=CY_U3P_SUCCESS) continue;

        CyU3PDebugPrint(4,"CyU3PUsbHostEpWaitForCompletion...\r\n");
        status = CyU3PUsbHostEpWaitForCompletion (glHostUvcEp, &epStatus, 10);
        CyU3PDebugPrint(4,"CyU3PUsbHostEpWaitForCompletion status=0x%x,ep=0x%x,epStatus=0x%x\r\n",status,glHostUvcEp,epStatus);

        CyU3PDebugPrint(4,"CyU3PDmaChannelWaitForCompletion...\r\n");
        status = CyU3PDmaChannelWaitForCompletion (&glHostUvcCh, CYU3P_NO_WAIT);
        CyU3PDebugPrint(4,"CyU3PDmaChannelWaitForCompletion status=0x%x\r\n",status);
        if(status!=CY_U3P_SUCCESS) continue;

        status = CyU3PDmaChannelGetStatus (&glHostUvcCh, &state, &prodXferCount, &consXferCount);
        CyU3PDebugPrint (4,"CyU3PDmaChannelGetStatus status=0x%x state=0x%x length=%d\r\n",status,state,prodXferCount);

        for(uint32_t i=0;i<prodXferCount-1;i++) {
        	if(buffer[i]==0xff && buffer[i+1]==0xd8) CyU3PDebugPrint(4, "SOI\r\n");
        	if(buffer[i]==0xff && buffer[i+1]==0xd9) CyU3PDebugPrint(4, "EOI\r\n");
        }
	}
}

 

 

0 Likes
Rashi_Vatsa
Moderator
Moderator
Moderator
5 likes given 500 solutions authored 1000 replies posted

Hello,

As you might be aware that isochronous transfers do not guarantee the delivery of data, the loss could be due to packet drop.

Please let us know the bandwidth of the video that you are streaming to FX3 (USB 2.0 Host).

Also, can you please try increasing "count" value to 6144 bytes (x2 3072)

Regards,
Rashi
0 Likes

Hello Rashi

This is the endpoint descripor information of my webcam.

UsbDescriptors-HU205.drawio.png

From the above, I'm using Interace1, bAlternateSetting=6.

As your recommendation, I'm testing with count value of 6144 bytes. The initial test results look quite promising! The host can now catch SOIs unlike before.

I'll be back after the long term test over night.

 

Thank you

Regards,

Rossi

0 Likes
Rashi_Vatsa
Moderator
Moderator
Moderator
5 likes given 500 solutions authored 1000 replies posted

Hello,

As the issue seems to be due to bandwidth, you can try requesting more data (in multiples of 3072(max packet size)) from the USB host side (FX3) so that packets do not get dropped.

Also, can you try alternate setting with lower bandwidth to check if with lower bandwidth the packets are dropped?

Regards,
Rashi
0 Likes

Hi Rashi,

The test during the weekend was successfully ended. As expected, I could observe SOI,EOI data from the stream. So, it's reasonable to say the cause of the missing data is the bandwidth as you pointed out.

 

Thank you for your help.

Regards,

Rossi

0 Likes