Handling Commit Buffer Failures Occurred during Video Transfers using FX3 – KBA231382
Author: HemanthR_06 Version: **
Why does commit buffer failure occur with the UVC application based on AN75779? How do I handle this failure? What steps can be taken to prevent this scenario from occurring?
In the following discussion, AN75779 project is considered as a reference, and the DMA channel referred to is manual many-to-one.|
The value of the dmaMultiConfig.count parameter of the multi-dma channel used in AN75779 for video transfer is 4. So, a total of eight DMA buffers are allocated to the channel. Two producer sockets for this channel are CY_U3P_PIB_SOCKET_0 and CY_U3P_PIB_SOCKET_1. Consumer socket is CY_U3P_UIB_SOCKET_CONS_3. Each producer socket has four buffers to be filled with data.
Consider the following:
- Name the allocated buffers as: buffer0, buffer1, buffer2, buffer3, buffer4, buffer5, buffer6, and buffer7.
- Buffer0, buffer1, buffer2, and buffer3 are the buffers available for PIB_SOCKET_0 to be filled with data.
- Buffer4, buffer5, buffer6, and buffer7 are the buffers available for PIB_SOCKET_1 to be filled with data.
In the dma callback handler associated with the video channel, once a PROD event is generated:
- The available buffer from the PIB socket (that is, occupied buffer) is obtained using the CyU3PDmaMultiChannelGetBuffer()
- The obtained buffer is committed using the CyU3PDmaMultiChannelCommitBuffer()
These steps are repeated in a while loop until no more buffers are available from the PIB socket.
There are two scenarios where the commit buffer API can fail:
The CyU3PDmaMultiChannelGetBuffer() API looks for the availability of occupied buffers alternatively in PIB_SOCKET_0 and PIB_SOCKET_1. That is, if the first call to this API retuned buffer0, then the subsequent call to this API will wait for buffer4 to be available (even if buffer1 from PIB_SOCKET_0 is available). If buffer4 is not available, the API will time out. Note that for a manual many-to-one channel, committing the available buffers using the CyU3PDmaMultiChannelCommitBuffer() API should also be done alternatively, that is, a buffer from PIB_SOCKET_0, and then a buffer from PIB_SOCKET_1. For example, assume that buffer0 is committed in the first call of this API, then the subsequent call to commit buffer1, while buffer4 is still unoccupied (that is, buffer4 is not yet made available by PIB socket), will cause the commit buffer API to fail, returning the CY_U3P_ERROR_INVALID_SEQUENCE error. This is the first scenario where the commit buffer API fails. However, the CyU3PDmaMultiChannelCommitBuffer() API call after a successful CyU3PDmaMultiChannelGetBuffer() call should not cause the commit buffer API to fail.
GPIF state machine of AN75779 is designed to fill buffers of PIB_SOCKET_0 and PIB_SOCKET_1 alternatively, that is, buffer0, buffer4, buffer1, buffer5, buffer2, buffer6, buffer3, buffer7, and then back to buffer0. This continues in the same order.
Assume that while the video is streaming, there is a delay from the host in requesting video data from the device such that all eight DMA buffers are filled up and committed to the USB socket. That is, the buffers are filled and committed in the dma callback in this order: buffer0, buffer4, buffer1, buffer5, buffer2, buffer6, buffer3, and buffer7
As mentioned, in the while loop of dma callback, CyU3PDmaMultiChannelGetBuffer() is called after CyU3PDmaMultiChannelCommitBuffer() to check if there are more buffers available for a commit. After buffer7 is committed, CyU3PDmaMultiChannelGetBuffer() call will relook at buffer0. But, buffer0 is already committed (all eight buffers are committed and waiting to be consumed by the host). So, the call to CyU3PDmaMultiChannelGetBuffer()is expected to return failure. But, this does not happen in sdk 1.3.4 and lower versions; instead it returns buffer0 again. This causes the commit buffer call to fail with the CY_U3P_ERROR_INVALID_SEQUENCE error.
This behavior of CyU3PDmaMultiChannelGetBuffer() will be fixed in the next official sdk release (see Note). With the fix, in this scenario, the call to the CyU3PDmaMultiChannelGetBuffer() API, which occurs in the while loop will return a failure after buffer7 is committed, and the execution will exit the while loop.
However, note that the fix will not prevent data loss (in this case current video frame loss) that occurs due to the host being slow.
When the new library is used, follow these steps to detect the buffers that are committed to USB block of the device and waiting to be consumed by the host:
- Increment a variable, after a successful commit buffer API call.
- Decrement the same variable when the CONS event is received in the dma callback.
- In the for(;;) loop of the app thread, monitor this variable value. A value of 8 indicates a possibility of data loss.
In this case, you can design the firmware to skip the current video frame and make the GPIF state machine to wait for the next frame. This causes frame loss.
If frame loss is not acceptable, an FPGA that can buffer the data till the host resumes (flow control), is necessary in the design.
Do the following to avoid all DMA buffers from being filled up:
- Allocate the maximum possible memory to the DMA buffers.
- Configure horizontal blanking of the image sensor as high as possible (to do this vertical blanking can be reduced thereby maintaining same frame rate). While doing this make sure that vertical blanking does not go below ~350 us.
Note: A test library is available in here. However, this is not an official release.