3 Replies Latest reply on Jul 31, 2017 5:57 AM by user_491519953

    Problems switching DMA transfer from MANUAL to AUTO_MANY_TO_ONE




      I am developing a custom camera application derived from the UVC example. I don't need to insert the UVC header for my application, so the CPU does not need to be interrupted to modify the Bulk transfer data on DMA commit. I'm trying to get rid of the Callback by using the DMA in AUTO_MANY_TO_ONE. However the host always reports failed Xfers (0 bytes received) unless I alter the data count value(partially corrupted data due to some skipped bytes in between, but at least I get something). I include my DMA Channel and GPIF setup, maybe I'm just doing something stupid or missing something.




      /* Configure the video streaming endpoint. */
          endPointConfig.enable = 1;
          endPointConfig.epType = CY_U3P_USB_EP_BULK;
          endPointConfig.pcktSize = CY_FX_EP_BULK_VIDEO_PKT_SIZE;
          endPointConfig.isoPkts = 1;
          endPointConfig.burstLen = 16;
          endPointConfig.streams = 0;
          apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_BULK_VIDEO, &endPointConfig);


      /* Create a DMA Manual channel for sending the video data to the USB host. */
          dmaMultiConfig.size = CY_FX_UVC_STREAM_BUF_SIZE; // 32kB
          dmaMultiConfig.count = CY_FX_UVC_STREAM_BUF_COUNT; // 3
          dmaMultiConfig.validSckCount = 2;
          dmaMultiConfig.prodSckId[0] = (CyU3PDmaSocketId_t) CY_U3P_PIB_SOCKET_0;
          dmaMultiConfig.prodSckId[1] = (CyU3PDmaSocketId_t) CY_U3P_PIB_SOCKET_1;
          dmaMultiConfig.consSckId[0] = (CyU3PDmaSocketId_t) (CY_U3P_UIB_SOCKET_CONS_0
                  | CY_FX_EP_VIDEO_CONS_SOCKET);
          dmaMultiConfig.prodAvailCount = 0;


          dmaMultiConfig.prodHeader = 0; /* 12 byte UVC header to be added. */
          dmaMultiConfig.prodFooter = 0;


          /* 4 byte footer to compensate for the 12 byte header. */
          dmaMultiConfig.consHeader = 0;
          dmaMultiConfig.dmaMode = CY_U3P_DMA_MODE_BYTE;
          dmaMultiConfig.notification = CY_U3P_DMA_CB_CONS_EVENT
                  | CY_U3P_DMA_CB_PROD_EVENT;
          dmaMultiConfig.cb = CyFxUvcApplnDmaCallback;
          apiRetStatus = CyU3PDmaMultiChannelCreate(&glChHandleUVCStream,
                  CY_U3P_DMA_TYPE_AUTO_MANY_TO_ONE, &dmaMultiConfig);


      /* Start the state machine from the designated start state. */


          CyU3PGpifInitDataCounter(0, (CY_FX_UVC_BUF_FULL_SIZE / (BUS_WIDTH / 8)-2),
          RELOAD, UP_COUNT, 1);




      Please let me know if I'm doing something horribly wrong, missing something or if you need additional information.


      Thanks in advance.

        • 1. Re: Problems switching DMA transfer from MANUAL to AUTO_MANY_TO_ONE

          Hi Helmut,




          Since you are using an AUTO Many to One DMA channel, you can do the following changes:


          dmaMultiConfig.notification = 0;


           dmaMultiConfig.cb = NULL;




          Also, you can set the data counter limit as:


          ( CY_FX_UVC_STREAM_BUF_SIZE/ (BUS_WIDTH/8) )-1.

          • 2. Re: Problems switching DMA transfer from MANUAL to AUTO_MANY_TO_ONE

            Hi rghe,


            Thanks for the reply. I finally got around to continue working on this issue:


            I have already tried removing the notification and callback as you suggested. After all my main goal is not having to use them. The different data count originated from the state machine design I inherited. However I have reworked the state machine to closer resemble the design found in the UVC example (using DATA_COUNT for socket 0 and ADDRESS_COUNT for socket 1) and eliminated the LAST_PIXEL state which required this weird SIZE-2 counter limit(see below). Still I coudn't get AUTO mode to work at all. While manual mode using the callback works fine, in AUTO mode I only get errors with 0 bytes transferred. I can't really tell if there isn't anything transferred at all or just the last partial packet that completes the transmission is missing. Do I have to do some manual wrap up (in an interrupt) for the last packet?



            • 3. Re: Problems switching DMA transfer from MANUAL to AUTO_MANY_TO_ONE



              I have been fighting this issue up until now. In case some else runs into the same problem:


              The Commit Action does not seem to do the trick of wrapping up the DMA buffer and issuing the USB transfer of a partial/zero length packet, which is required to complete the BULK transfer. AN87216 shows how to use a CPU Interrupt and wrap up the transmission in firmware. Using a CPU interrupt instead of Commit and a callback that wraps up the correct producer depending on the current state did do the trick:




              CyFxApplnGPIFEventCB (
                      CyU3PGpifEventType event,               /* Event type that is being notified. */
                      uint8_t            currentState         /* Current state of the State Machine. */
                  char producer = currentState == PARTIAL_BUF_IN_SCK0 ? 0 : 1;


                  switch (event)
                  case CYU3P_GPIF_EVT_SM_INTERRUPT:
                      CyU3PDmaMultiChannelSetWrapUp(&glChHandleUVCStream, producer);
                      DebugPrint(4, "SM interrupt:MC Wrap up(State %d)\n", currentState);