Failed to get buffer after first FX3->PC DMA transfer, and DMA unable to run in CyFxGpifCB

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

cross mob
Anonymous
Not applicable

I use a DMA to transfer from FX3 to PC and libUSB driver. I have two problems now. 

   

1) I noticed the IN endpoint only receives 1 transfer at PC then refuse to CyU3PDmaChannelGetBuffer. I can verify the received transfer is correct. In a multi-DMA IN EP, I could get 7 transfers before CyU3PDmaChannelGetBuffer fails. I believe the two issues share the same root cause. 

   

2) I would rather like to have the FPGAInterrupt to be called directly from CyFxGpifCB(), but it seems not working. I had to create a thread to poll for FPGA_Intr_called status and emulate an interrupt. 

   

 

   

Source segments below. 

   
    


void FPGAInterrupt()
{
    CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
    CyU3PDebugPrint(CY_FX_DEBUG_PRIORITY, "FPGAInterrupt() called \r\n");

    

    apiRetStatus = CyU3PDmaChannelGetBuffer (&glChHandleUVCControlIN, &buf_p_1, CYU3P_NO_WAIT);
    if (apiRetStatus != CY_U3P_SUCCESS) {
        CyU3PDebugPrint(CY_FX_DEBUG_PRIORITY, "FPGAInterrupt.CyU3PDmaChannelGetBuffer failed, Error code = %d\n", apiRetStatus);
    }

    

    if (apiRetStatus == CY_U3P_SUCCESS) {
        CyU3PMemSet (buf_p_1.buffer, 0, 16*CY_FX_EP_BULK_VIDEO_PKT_SIZE);
        for (int i=0; i<16*CY_FX_EP_BULK_VIDEO_PKT_SIZE; i++) {
            buf_p_1.buffer = FPGAInterrupt_header[i%24];
        }
        buf_p_1.buffer[0] = intr_cnt;
        CyU3PDebugPrint(CY_FX_DEBUG_PRIORITY, "FPGAInterrupt() memset done \r\n");
        /* Commit the full buffer with default status. */
        apiRetStatus = CyU3PDmaChannelCommitBuffer (&glChHandleUVCControlIN, buf_p_1.size, 0);
        if (apiRetStatus != CY_U3P_SUCCESS) {
            CyU3PDebugPrint(CY_FX_DEBUG_PRIORITY, "CyFxUVCDmaDownloadCallback.CyU3PDmaChannelCommitBuffer failed, Error code = %d\n", apiRetStatus);
        }
        CyU3PDebugPrint(CY_FX_DEBUG_PRIORITY, "FPGAInterrupt() memset done \r\n");
    }
    CyU3PDebugPrint(CY_FX_DEBUG_PRIORITY, "FPGAInterrupt() exits \r\n");
    return;
}

    

 

    

CyFxGpifCB (
        uint8_t currentState            /* GPIF state which triggered the interrupt. */
        )
{
    /* The ongoing video frame has ended. If we have a partial buffer sitting on the socket, we need to forcibly
     * wrap it up. We also need to toggle the FW_TRG a couple of times to get the state machine ready for the
     * next frame.
     *
     * Note: DMA channel APIs cannot be used here as this is ISR context. We are making use of the raw socket
     * APIs.
     */
    switch (currentState)
    {
        case FPGA_DO_INTR:
            intr_cnt++;
            FPGA_Intr_called = CyTrue;
//            if (FPGA_Intr_called == CyTrue) {
//                FPGAInterrupt();
//                FPGA_Intr_called = CyFalse;
//            }
      }
}     

    

 

    

 

    

void
uvcFPGAIntrThread_Entry (uint32_t input)
{
    for (;;) {
        if (FPGA_Intr_called == CyTrue) {
            FPGAInterrupt();
            FPGA_Intr_called = CyFalse;
        }

    

//        CyU3PThreadSleep(10);
        /* Allow other ready threads to run. */
        CyU3PThreadRelinquish ();
    }
}

    

 

    

 

    


    dmaCfg.size  = 16*CY_FX_EP_BULK_VIDEO_PKT_SIZE;
    dmaCfg.count = 1;
    dmaCfg.prodSckId = CY_U3P_UIB_SOCKET_PROD_5;
    dmaCfg.consSckId = CY_U3P_CPU_SOCKET_CONS;
    dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
    dmaCfg.notification = CY_U3P_DMA_CB_PROD_EVENT | CY_U3P_DMA_CB_CONS_EVENT;
    dmaCfg.cb = CyFxUVCControlDmaCallback;
    dmaCfg.prodHeader = 0;
    dmaCfg.prodFooter = 0;
    dmaCfg.consHeader = 0;
    dmaCfg.prodAvailCount = 0;
    <cut>
    
    /* Create a DMA MANUAL_OUT channel for the consumer socket. */
    dmaCfg.notification = CY_U3P_DMA_CB_CONS_EVENT;
    dmaCfg.prodSckId = CY_U3P_CPU_SOCKET_PROD;
    dmaCfg.consSckId = CY_U3P_UIB_SOCKET_CONS_4;
    apiRetStatus = CyU3PDmaChannelCreate (&glChHandleUVCControlIN,
            CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaCfg);

    

    <cut>

    


    apiRetStatus = CyU3PDmaChannelSetXfer (&glChHandleUVCControlIN, 0);

    


 

   
0 Likes
2 Replies
Anonymous
Not applicable

Hi,

   

Instead of CYU3P_NO_WAIT, can you please specify a finite timeout and see? This has been the issue in lot of similar cases.

   

Regards,

   

-Madhu Sudhan

0 Likes
Anonymous
Not applicable

Hi,

   

  I have a similar issue, According to my debug, changing the size and count of DMA could ameliorate the situation. I don't know if the situation happens only when using libusb driver? Or it's the bug of FX3 when changing the size and count of DMA?

0 Likes