Problems switching DMA transfer from MANUAL to AUTO_MANY_TO_ONE

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

cross mob
lock attach
Attachments are accessible only for community members.
heanc_1330791
Level 2
Level 2

Hi,

   

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.

   

<code>

   

/* 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);

   

</code>

   

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

   

Thanks in advance.

0 Likes
3 Replies
Anonymous
Not applicable

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.

0 Likes
heanc_1330791
Level 2
Level 2

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?

   

   

0 Likes
heanc_1330791
Level 2
Level 2

Hi,

   

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:

   

 

   

void
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);
    }
    break;

   

    default:
        break;
    }
}

0 Likes