MANUAL_MANY_TO_ONE MultiChannelCommitBuffer returning INVALID_SEQUENCE

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

cross mob
Anonymous
Not applicable
        I'm following AN75779 and I'm running into an issue with CyU3PDmaMultiChannelCommitBuffer returning CY_U3P_ERROR_INVALID_SEQUENCE. The multi-channel DMA is set up as follows:   
#define VIDEO_LINE_DATA_WIDTH (8272) #define VIDEO_DMA_BUFFER_COUNT (2) #define USB3_MAX_BURST (1) /* was (8) */  /* set up an auto many-to-one DMA channel to send the UVC video stream */  CyU3PMemSet((uint8_t *)&mdmaCfg, 0, sizeof(mdmaCfg));  mdmaCfg.size = VIDEO_LINE_DATA_WIDTH + 16;  mdmaCfg.count = VIDEO_DMA_BUFFER_COUNT * USB3_MAX_BURST;  mdmaCfg.prodSckId[0] = CY_U3P_PIB_SOCKET_0;  mdmaCfg.prodSckId[1] = CY_U3P_PIB_SOCKET_1;  mdmaCfg.prodHeader = 12;  mdmaCfg.prodFooter = 4;  mdmaCfg.consSckId[0] = CY_U3P_UIB_SOCKET_CONS_0 | USB_EP_VIDEO_CONS_SOCKET;  mdmaCfg.validSckCount = 2;  mdmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;  mdmaCfg.notification = CY_U3P_DMA_CB_CONS_EVENT | CY_U3P_DMA_CB_ERROR;  mdmaCfg.cb = mdma_cb;   cli_dprintf(1, "Attempting to allocate %d %d-byte buffers (%d KB total) for DMA...\n", mdmaCfg.count, mdmaCfg.size, mdmaCfg.count * mdmaCfg.size / 1024);   apiRetStatus = CyU3PDmaMultiChannelCreate(&dch_video, CY_U3P_DMA_TYPE_MANUAL_MANY_TO_ONE, &mdmaCfg);  if (apiRetStatus != CY_U3P_SUCCESS) {   cli_dprintf(1, "could not create video DMA channel (%d)\n", apiRetStatus);   CyFxAppErrorHandler(apiRetStatus);  }
The multi channel DMA creation is successful. With the values above I should have 4 8284 byte buffers, each with room for a 12 byte header and 4 byte footer to maintain the necessary alignment. The main loop looks like this:   
   status = CyU3PDmaMultiChannelGetBuffer(&dch_video, &dmabuf, CYU3P_NO_WAIT);    if (status == CY_U3P_SUCCESS) {      /* replace DMA data here, see comment below */      len = sizeof(uvc_header);     if (dmabuf.count == VIDEO_LINE_DATA_WIDTH) {      uvc_add_header(dmabuf.buffer - len, CyFalse);     } else {      uvc_add_header(dmabuf.buffer - len, CyTrue);      gotPartial = CyFalse;     }      if (status != lastgetbufferstatus) {      cli_dprintf(1, "getbuffer change: 0x%x -> 0x%x\n", lastgetbufferstatus, status);      lastgetbufferstatus = status;     }      status = CyU3PDmaMultiChannelCommitBuffer(&dch_video, dmabuf.count + len, 0);     if (status == CY_U3P_SUCCESS) {      ++tx_count;     }      if (status != lastcommitstatus) {      cli_dprintf(1, "commitbuffer change: 0x%x -> 0x%x\n", lastcommitstatus, status);      lastcommitstatus = status;     }    }     /* if everything produced has been consumed, restart DMA */    if (hitFV && tx_count == rx_count && ! gotPartial) {     tx_count = rx_count = 0;     hitFV = CyFalse;      uvc_header[1] ^= UVC_HEADER_FRAME_ID;     CyU3PDmaMultiChannelReset(&dch_video);     CyU3PDmaMultiChannelSetXfer(&dch_video, 0, 0);    }
As you can see I only ever call CyU3PDmaMultiChannelCommitBuffer() if I was able to successfully get the DMA buffer with CyU3PDmaMultiChannelGetBuffer(). My GPIF-II data is bursty so I expect that there will be considerable time when there is no GPIF data available. However, CyU3PDmaMultiChannelGetBuffer() would not give me a success return code unless there was a buffer available. What exactly does the status CY_U3P_ERROR_INVALID_SEQUENCE mean in this scenario? I get it once every 5 or 6 DMA transfers, and can go long (hundreds of transfers) times without any error. It does not appear to be a fatal error, as I do get the correct amount of data on the PC. Unfortunately the actual data values received from the GPIF-II interface are corrupt. I know that the USB transfer is fine because if I replace the contents of the DMA buffer with known data at the /* replace DMA data here */ comment above I receive the known data correctly on the PC. What causes this error, what is the correct way to recover from it and how can I prevent it from occurring?   
0 Likes
6 Replies
Anonymous
Not applicable

 Just an update -- the data corruption is a red herring; it was caused by an improper sensor configuration. The error code returned from the dma commit function is not related to the data corruption.

0 Likes
Anonymous
Not applicable

 Hi,

   

 

   

What host application are you using to read and display your image stream?

   

We have observed this error on certain combination of host apps and host controllers. It might be because the data is not being read by the host controller/app quickly enough. As a result it causes a buffer overflow scenario on the GPIF side. This, in turn is causing the GetBuffer() API to return successfully even though there never was a new buffer available. Consequently, the CommitBuffer() goes on to commit a buffer that does not actually exist and hence throws this invalid sequence error.

   

We have seen good performance while streaming image data using AmCap host software. Using VirtualDub sometimes led to this invalid sequence error scenario.

   

The best way to avoid it would be to make sure that the host is always ready to read the data as and when the device has it ready. Increasing the buffering within the FX3 would also help alleviate the issue.

   

Recovering from this woud entail having to resume streaming from the next frame onwards. Until you come across this scenario again. This will result in lost data (and hence dropped frames) from time to time.

   

 

   

Regards

   

Shashank

0 Likes
Anonymous
Not applicable

Thank you for your response.

   

I'm using VLC to look at the image as it seems FAR more tolerant of bad data than AmCap.  AmCap errors out immediately whereas VLC tries to keep pulling in data.

   

Sniffing the USB traffic indicates that VLC is grabbing data fairly quickly, although I will take a closer look and see. I have intentionally used very few DMA buffers on the FX3 to help aid my debugging; I expect that once I enable burst transfers and increase the number of buffers up to the limit of available memory this will go away.

   

Your answer about GetBuffer() returning CY_U3P_SUCCESS even though the returned buffer is not available raises an interesting question about the GetBuffer() API. GetBuffer() on a MANUAL_MANY_TO_ONE channel handle would return a buffer structure that has presumably been filled and is waiting for me to manually Commit(). I'm having trouble understanding how Commit() would return an error in this case.

   

e.g. 2 producer channels and 1 consumer channel with 2 buffers per producer:

   

Buffer 1A fills from GPIF-II
Buffer 2A fills from GPIF-II
Buffer 1B fills from GPIF-II
Buffer 2B fills from GPIF-II

   

At this point GetBuffer() should return the structure for Buffer 1A.  I Commit() it and call GetBuffer() again. This time I would get 2A, then 1B then 2B. Now all four descriptors should be indicating that their buffer is busy and waiting for transfer to the consumer.

   

If I call GetBuffer() again at this point, I would not get a buffer (i.e. the thread should either sleep since there is no buffer available or return TIMEOUT).

   

Can you elaborate on how the system gets into a situation where I am able to get a success result from GetBuffer() but not be able to Commit() that buffer? I am confused.
 

0 Likes
Anonymous
Not applicable

 Hi,

   

I just want to add one point here:

   

Amcap version 8.x works much better than 9.x with regards to hd uncompressed streams. So you can try with version 8.x once.

   

Thanks,

   

Sai Krishna.

0 Likes
Anonymous
Not applicable

 This is actually an MJPEG video stream, not uncompressed, but I'll check out the earlier version of AmCap, thank you.

   

Could you help me understand why this error is coming up? I had explained my understanding in my last message but obviously it is incorrect. 🙂

0 Likes
leda_289486
Level 5
Level 5
10 sign-ins 5 sign-ins 100 replies posted

Hi,

   

I'd like to know where to get the Amcap 8.x version, and if possible the related source code, because I'd like to compare the Amcap 9.x and 8.x behaviors and reliability.

   

Best Regards

0 Likes