2 Replies Latest reply on Aug 18, 2017 1:06 PM by kelvin.xu_1593951

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

    kelvin.xu_1593951

      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[i] = 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);