This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

FVID_dequeue is blocking in video callback

Hi

In sd_loopback example, I am trying to replace the capture FVID_exchange with a callback based on mask VPORT_INT_CCMP (0x04). The reason for doing so is to prevent the blocking condition in capture FVID_exchange when a buffer is not available. The structure of the callback is:

extern "C" void VideoCallback(Arg id, Arg mask)
{
    if (mask & VPORT_INT_CCMP)
    {                                    
            status = FVID_dequeue(capChInfo.chanHandle, &(capChInfo.frame)); 

            status = MBX_post(hmbxProcess, &capChInfo, SYS_FOREVER); 

    }
    return;
}

The main while loop is shown below. The problem is that dequeue doesn't block the first time the callback fires, but the second time the callback fires, dequeue blocks. When I say "works", I mean that the first time i leave the mbx pend, I can break at the display FVID_exchange and can see the correct video image in disChInfo.frame.

Is there a way I can debug this? I have looked that the QUE next and prev addresses and tried to understand if a buffer isn't available but no luck. I think I need to get at the Channel object parameter queEmpty or numQueBuf to understand what the blocking issue is. Can you recommend any APIs or registers to debug this issue? Or maybe I am going about this the wrong way?

Also, if I move the callback registration before the VPORT_CMD_START, the dequeue blocks the first time the callback occurs.

Another strange thing is the callback registration does not exit before the callback is called by the video driver.

    FVID_control(disChInfo.chanHandle, VPORT_CMD_START, NULL);

    FVID_control(capChInfo.chanHandle, VPORT_CMD_START, NULL);
   
    vport_callback_params.cbArg     = CAP_CALLBACK_ID;
    vport_callback_params.vIntCbFxn = VideoCallback;
    vport_callback_params.vIntMask  = VPORT_INT_CCMP; // Capture complete interrupt mask.
    status |= FVID_control (capChInfo.chanHandle, VPORT_CMD_SET_VINTCB, &vport_callback_params);

    // Enter main processing loop.
    while (1)
    {
          
        MBX_pend(hmbxProcess, &buf, SYS_FOREVER)
           
        std::memcpy((Uint8 *)disChInfo.frame->frame.iFrm.y1, (Uint8 *)buf.frame->frame.iFrm.y1, FRAME_SIZE);

        /* Invalidate the buffer before giving to capture driver */
        BCACHE_inv((Uint8 *)buf.frame->frame.iFrm.y1, (FRAME_SIZE), TRUE);

        // Give capture buffer back to vport capture driver.
        if (FVID_queue(buf.chanHandle, &(buf.frame)) != IOM_COMPLETED)

        BCACHE_wbInv((Uint8 *)disChInfo.frame->frame.iFrm.y1, (FRAME_SIZE), TRUE);

        status = FVID_exchange(disChInfo.chanHandle, &(disChInfo.frame));          
    }/* while (1) */

I removed the LOG_printf's in the above code to make it easier for viewing, but the trace shows no issues other than blocking in dequeue. The text in () are my comments I added to decode my log output for you.

0   Successfully initialized EDMA3
1   Successfully created capture channel 2. Status = 0

2   Creating display channel

3   Successfully created display channel. Status = 0

4   Start display and capture

5   ent cb 84  (enter callback, mask = 0x84)

6   ent cb dq   (enter callback dequeue)

7   x cb dq    (exit callback dequeue)

8   x cb reg    (exit callback registration)

9   mbxpend (enter mbx pend)

10   x mbxpend (exit mbxpend)

11   x memcpy  (exit memcopy)

12   dis exchg (enter display exchange)

13   ent cb 84 (enter callback, mask = 0x84)

14   ent cb dq (enter callback dequeue)  <- It stays here forever. Arg. [:(]

I am using dvsdk_1_10_00_26_DM648 and BIOS 5.33.06. Code Gen v6.08 and CCS 3.3.82.

Thanks

  • Hi

    I don't think its the callback dequeue that is the issue. The trace looks like its getting hung up first in display FVID_exchange. I replaced FVID_exchange with FVID_queue and FVID_dequeue and its now getting hung up in FVID_dequeue. I also reduced the memcpy by a factor of 4 to ensure its not a running out of MIPs issue.

    I also tried increasing the number of buffers from 3 to 5. That didn't help either. The code gets hung on  the first display dequeue.

    0   Successfully initialized EDMA3
    1   Successfully created capture channel 2. Status = 0
    2   Creating display channel
    3   Successfully created display channel. Status = 0
    4   Alloc'd and queue'd 5 buffers
    5   Strt display and capture
    6   cb 84 0     (means callback, mask = 84, call back count)
    7   cb dq
    8   x cb dq
    9   x cb reg
    10   mbxpend
    11   x mbxpend 0
    12   x memcpy
    13   dis q           (enter display FVID_queue)
    14   x dis q        (exit display FVID_queue)
    15   dis dq         (gets hung here, there should be a "x dis dq" next)
    16   cb 84 1       (means callback, mask = 84, call back count)
    17   cb dq

  • Eddie,

    The DM648 VPORT driver doesnot support non-blocking buffer exchange mechanism. The FVID dequeue always blocks even when you register a callback.

    The purpose of the callback is different - that is to get VPORT interrupts like capture overrun, display under run errors etc... It is not meant for non-blocking IO operation.

    Hence you can't use dequeue from the callback/ISR context as you have done here.

    Regards,

    Sivaraj R

  • Hi Sivaraj

    Sorry, I think I wasn't clear. Perhaps I should explain my trace sequence. I am using the capture callback interrupt "capture complete" (VPORT_INT_CCMP) to indicate when a capture is complete.Then I call capture FVID_dequeue. This seems to work OK. The problem is in the display FVID_dequeue.

    In the callback interrupt handler I call capture FVID_dequeue. You can see below in my trace that this happens at steps 6 and 7. The capture handle and frame is put in an MBX and the callback returns. The main loop is pending on MBX. The message from the callback causes MBX pend to exit (step 11). Then I memcpy the capture buffer to the display buffer. The problem is in the display FVID_dequeue blocking (step 15). Because it blocks, the capture callback eventually fires as it should because there is another capture frame available (step 16).

    There is no callback registered for the display driver.

    I have a compile switch that turns off the capture callback queueing/dequeueing and turns on capture queue/dequeue in the main loop and it works fine. The problem is that I can't have blocking because the CPU must deal with UART interrupts.

    I did try registering a callback for display errors like you suggested but it did not show any. The only interrupt I got was display complete (VPORT_INT_DCMP).

    Can you suggest a way to use the capture FVID drivers without the callback? As I said, I need to be efficient with the CPUs MIPs because there are other tasks that must be serviced. Blocking in FVID_dequeue capture would be wasting MIPs.

    It seems strange that the capture callback would be effecting the display FVID_dequeue.[:^)]

    Thx

    0   Successfully initialized EDMA3
    1   Successfully created capture channel 2. Status = 0
    2   Creating display channel
    3   Successfully created display channel. Status = 0
    4   Alloc'd and queue'd 5 buffers
    5   Strt display and capture
    6   cap cb 84 0     (means capture callback, mask = 84, cnt = 0)
    7   cap cb dq        (enter capture callback FVID_dequeue)
    8   x cap cb dq     (exit capture callback FVID_dequeue)
    9   x cap cb reg

    *** exit callback and go to main loop ****
    10   mbxpend        (enter mbx pend)
    11   x mbxpend 0  (exit mbx pend, cnt = 0)
    12   x memcpy       (exit memcpy of cap frame to dis frame)
    13   dis q                (enter display FVID_queue)
    14   x dis q             (exit display FVID_queue)
    15   dis dq              (display gets hung here, there should be a "x dis dq" next)
    16   cap cb 84 1    (means capture callback, mask = 84, cnt = 1)
    17   cap cb dq       (enter capture callback dequeue)

  • I used CLK_Getltime to timestamp the log messages.The low resolution clock time is 1 msec. As expected, the capture callback is occurring every 33 msec. (30 Hz)

    The trace is the same as my previous message, but I have added the timestamp to illustrate how much time there is between entering the display FVID_dequeue (trace 21, time = 350 msec) and when the capture callback occurs (trace 22, time = 381 msec).

    I also added the display callback to interrupt on VPORT_INT_DUND | VPORT_INT_DCMP | VPORT_INT_DCNA (// underrun  , complete, complete not ack).

    Could it be that the display dequeue cannot be interrupted?[:S] I can't understand why dequeue is taking so long considering I have allocated 5 buffers.

    Thx

    0   Successfully initialized EDMA3
    1   Successfully created capture channel 2. Status = 0
    2   Creating display channel
    3   Successfully created display channel. Status = 0
    4   Alloc'd and queue'd 5 buffers
    5   Strt display and capture, t=216
    6   x dis dq
    7   cb cap m=84 c=0
    8       t=349                      (capture callback at time = 349)
    9   cb cap dq

    10   x cap cb dq

    11   x cap cb reg
    *** exit callback and go to main loop ****
    12   Dis cb: complete 2000       (display callback)
    13   x dis cb reg                            (exit display callback)
    14   Enter while(1), t=349           (enter main loop)
    15   mbxpend, t=349
    16   x mbxpend 0 t=349
    17   Dis cb: complete 2000
    18   x memcpy t=349
    19   dis q t=350
    20   x dis q t=350
    21   dis dq t=350
    22   cb cap m=84 c=1
    23       t=381         (capture callback at time = 381, delta time = 381 - 349 = 32 msec)
    24   cb cap dq

  • By chance, the code ran for 3 captures. I found that the display FVID_dequeue was taking approx 33 msec (VERY SUSPICIOUS). Thats the max time I've got to get the task done! You can see that the first time it took over 80 msec. (step 6)

    Since I used FVID_allocBuffer/FVID_queue to assign  5 buffers to the display channel object, It shouldn't be taking this long to return a buffer, but its acting as if it only has 1 buffer. I have set VPORTCAP_Params numFrmBufs to zero for NORMAL mode and assigned the buffers as done in the sd_compositor example.

    Furthermore, when I look at QUE_Elem member "next" using the CCS watch window, I see it has pointers to at least 4 different display buffers.

    At the first instance where I request a display buffer (Trace #6), I stepped into mdSubmitChan() and then into _cmdDequeue() where the code executes

    retVal = packet->status = IOM_PENDING

    This happens is because the _cmdDequeue() code below has viop equal to &chan->qOut. Why would this be happening when there are 5 buffers allocated and its the first time I am executing FVID_dequeue and FVID_queue? I would have expected numQueBuf to be decremented.

    static Int _cmdDequeue(_VPORT_ChanObj *chan, IOM_Packet *packet)
    {
        Int retVal = IOM_COMPLETED;
        FVID_Frame *viop = NULL;

        if ((viop = (FVID_Frame *)QUE_dequeue(&chan->qOut)) != (FVID_Frame *)&
            chan->qOut)
        {

    THIS CODE IS NOT EXECUTED![^o)]
            /* only when there is no outstanding pending request */ 
            *(void**)packet->addr = (void*)viop;
            packet->size = sizeof(FVID_Frame);
            retVal = packet->status = IOM_COMPLETED;

            if (NORMAL_MODE == chan->driverMode)
            {
                /* decrement number of buffers available with driver */
                chan->numQueBuf--;
            }
        }
        else
        {

    BUT THIS IS[*N]
            chan->packetIOM = packet;
            retVal = packet->status = IOM_PENDING;
        }

        return retVal;
    }


    The strange thing is when I return from FVID_Dequeue, its status is IOM_COMPLETE. What up with that!!!!! What changed it from IOM_PENDING to IOM_COMPLETE? According to the VPORT architecture flow chart (Fig 24), I should return IOM_PENDING.

    0   Successfully initialized EDMA3
    1   Successfully created capture channel 2. Status = 0
    2   Creating display channel
    3   Successfully created display channel. Status = 0
    4   Alloc'd and queue'd 5 buffers
    5   Strt display and capture, t=217

    6   dis dq t=284         ****enter display dequeue****
    7   x dis dq t=350       ****66 msec later exit display dequeue****

    8   cb cap m=84 c=0
    9       t=350
    10   cb cap dq
    11   x cap cb dq
    12   x cap cb reg
    13   Dis cb: complete 2000
    14   x dis cb reg

    15   Enter while(1), t=350
    16   mbxpend, t=350
    17   x mbxpend 0 t=350
    18   Dis cb: complete 2000
    19   x memcpy t=351
    20   dis dq t=352        ****enter display dequeue****
    21   cb cap m=84 c=1
    22       t=359
    23   cb cap dq
    24   x cap cb dq
    25   x dis dq t=384      ****33 msec later exit display dequeue****

    26   dis q t=384
    27   x dis q t=384
    28   mbxpend, t=384
    29   x mbxpend 1 t=384
    30   Dis cb: complete 2000
    31   x memcpy t=384
    32   dis dq t=385        ****enter display dequeue****
    33   cb cap m=84 c=2
    34       t=392
    35   cb cap dq
    36   x cap cb dq
    37   x dis dq t=417      ****33 msec later exit display dequeue****
    38   dis q t=417
    39   x dis q t=417
    40   mbxpend, t=417
    41   x mbxpend 2 t=417
    42   Dis cb: complete 2000
    43   x memcpy t=418
    44   dis dq t=418        ****enter display dequeue****
    45   cb cap m=84 c=3
    46       t=426
    47   cb cap dq           ****stalled here****

  • [*sn]Found the problem but don't know how to fix it.

    I watched the QUE_elem next pointers as the allocated buffers and ran  FVID_queue to assign them. The assigned buffers (for 3 this time) are

    frame: E034c100

    queElement->next E220830C

                                  next  E01FA880

                                         next E034c100  (this one points to the current frame as it should)

    But when I step into mdSubmitChan() ->  _cmdDequeue() -> QUE_dequeue(), the queue handle is pointing to E2208314. The que element at this location wasn't assigned by FVID_queue. And since its "next" pointer is also 0xE2208314, it acts like a single buffer queue.[:@]

    I also Noted that in  _cmdDequeue(), the parameter _VPORT_ChanObjchan->qOut points to 0xE2208314. Where did this pointer come from? It doesn't appear to be linked to the link list.

    I could have somehow incorrectly setup the system to use NORMAL mode since the ChanObj qOut parameter is not pointing to the buffers I allocated. [:$]Below is my allocation code. Any ideas what is missing for NORMAL mode?[:D]

    Looking at the code for FVID_queue in vportdis.c, I don't think QUE_enqueue is being called with the chan->qOut. I set breakpoints at every instance of

     QUE_enqueue(&chan->qOut, elem);

    And none hit is when the FVID_queue buffers. It appears there may be a bug[*sn]in the NORMAL mode FVID_queue routine since it does not change the qOut parameter.[8-)]

    ****** MY INITIALIZATION CODE ********************

        vCapParamsChan.numFrmBufs = 0;
        vDisParamsChan.numFrmBufs = 0;

        /* Allocate and Queue buffers for capture driver */
        for (buf_count = 0; buf_count < NUM_FRAME_BUFFERS; buf_count++)
        {
            /* Allocate Frame buffer for display driver */
            if (FVID_allocBuffer(disChInfo.chanHandle, &(disChInfo.frame)) != IOM_COMPLETED)
            {
                LOG_printf(&trace, "Failed to allocate dis buffer");
                break;
            }

            /* Queue the buffers */
            if (FVID_queue(disChInfo.chanHandle, &(disChInfo.frame)) != IOM_COMPLETED)
            {
                LOG_printf(&trace, "Failed to Queue dis buffer");
                break;
            }
        }