DMA Buffers not recycling

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

cross mob
GrSe_4664521
Level 2
Level 2

I was wondering if anyone might have encountered something similar to what I'm seeing with the DMA on the FX3.  We have a DMA channel configured to pump data from the GPIF to the USB largely following the cyfxbulksrcsink.c example.  The DMA is setup as follows:

    /* Create a DMA Auto channel for the image producer socket. */

    CyU3PMemSet ((uint8_t *)&dmaCfg, 0, sizeof (dmaCfg));

    /* The buffer size will be same as packet size for the

     * full speed, high speed and super speed non-burst modes.

     * For super speed burst mode of operation, the buffers will be

     * 1024 * burst length so that a full burst can be completed.

     * This will mean that a buffer will be available only after it

     * has been filled or when a short packet is received. */

    dmaCfg.size  = (size * CY_FX_EP_BURST_LENGTH);

    /* Multiply the buffer size with the multiplier

     * for performance improvement. */

    dmaCfg.size *= CY_FX_DMA_SIZE_MULTIPLIER;

    dmaCfg.count = CY_FX_IMAGE_DMA_BUF_COUNT;

    dmaCfg.prodSckId = CY_FX_PPORT_PRODUCER_SOCKET;

    dmaCfg.consSckId = CY_FX_EP_IMAGECONSUMER_SOCKET;

    dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;

    dmaCfg.notification = 0;

    dmaCfg.cb = NULL;

    dmaCfg.prodHeader = 0;

    dmaCfg.prodFooter = 0;

    dmaCfg.consHeader = 0;

    dmaCfg.prodAvailCount = 0;

    apiRetStatus = CyU3PDmaChannelCreate (&glChHandleImage,

            CY_U3P_DMA_TYPE_AUTO, &dmaCfg);

Where:

size is 1024

CY_FX_EP_BURST_LENGTH is 16

CY_FX_DMA_SIZE_MULTIPLIER is 2

and CY_FX_IMAGE_DMA_BUF_COUNT is 3

(CY_FX_PPORT_PRODUCER_SOCKET is CY_U3P_PIB_SOCKET_0 and CY_FX_EP_IMAGECONSUMER_SOCKET is CY_U3P_UIB_SOCKET_CONS_6

From what I have been able to learn about the FX3 this all seems fine (I'm resurrecting this project that someone else started) but what I'm seeing is that when I try to get data off the sensor I get 96k bytes through the WinUsb_ReadPipe() on the PC before subsequent reads timeout.  The reads have to be done in not more than 16k chunks based on the 16k buffer size in the FX3 but it doesn't matter if the chunk size is smaller it always stops at 96k - my image is 2MB total.  The "interesting" thing is 96k is exactly how much buffer I've allocated to the DMA configuration (1024 x 16 x 2 x 3).  It seems to me that the DMA isn't cycling through the buffers once it has handed them off to the USB socket; once it has gone through the six 16k buffers I don't get any more data.

 

How are the buffers are recycled or what might prevent the DMAC from recycling them?  Seems to me that since I'm seeing the data at the PC that the buffers should be available for re-use in the FX3.  I looked through the example code, the library source code and the FX3 programmer's guide but haven't found anything explaining that process.  I suspect that there is something amiss in how I have things setup such that the DMAC callback isn't able to re-use the buffers but I don't know where the DMA callback code is or even if it is provided in source code.  Any suggestions / ideas would be appreciated.

FYI - I believe I confirmed by suspicion by doubling the number of buffers and then i received twice as much data at the PC...

Thanks,

Greg

0 Likes
1 Solution
Rashi_Vatsa
Moderator
Moderator
Moderator
5 likes given 500 solutions authored 1000 replies posted

Hello Greg,

From the description in your first response i could understand that the AUTO DMA channel is between GPIF > USB with DMA buffer size a 32 K and buffer count as 3. And DMA buffer is not switching after all the 3 if the buffers are read. Is my understanding right.

For debugging the problem can you changes the DMA channel type to AUTO SIGNAL (CY_U3P_DMA_TYPE_AUTO_SIGNAL) and register for the callback and the PROD and CONS event.

    .......

     dmaCfg.consSckId[0] = CY_FX_EP_CONSUMER_SOCKET;

     dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;

    dmaCfg.notification = CY_U3P_DMA_CB_CONS_EVENT | CY_U3P_DMA_CB_PROD_EVENT  ;

     dmaCfg.cb = GpifToUsbDmaCallback;

     dmaCfg.prodHeader = 0;

     dmaCfg.prodFooter = 0;

     dmaCfg.consHeader = 0;

     dmaCfg.prodAvailCount = 0;

     // TODO: Producer/Consumer

     apiRetStatus = CyU3PDmaChannelCreate (&glDmaChHandle, CY_U3P_DMA_TYPE_AUTO_SIGNAL, &dmaCfg);

     if (apiRetStatus != CY_U3P_SUCCESS)

     {

         CyU3PDebugPrint (4, "CyU3PDmaMultiChannelCreate failed, Error code = %d\n", apiRetStatus);

         CyFxAppErrorHandler(apiRetStatus);

     }

And in the DMA callback, can you increment a variable and then get them printed in the for {} later.

void

GpifToUsbDmaCallback (

        CyU3PDmaChannel   *chHandle,

        CyU3PDmaCbType_t   type,

        CyU3PDmaCBInput_t *input)

{

CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if (type == CY_U3P_DMA_CB_PROD_EVENT)

    {

prod ++;

    }

    if (type == CY_U3P_DMA_CB_CONS_EVENT)

    {

    cons++;

        /* Data transfer has been started. Enable the LPM disable loop. */

    }

in the thread entry function:

for (;;)

    {

    CyU3PDebugPrint (1, "\n\nprod = %d cons = %d ", prod,cons);

}

- Please let me know the GPIF state machine being used in the firmware

- Also,  check the state in which the GPIF state machine is in when you get the timeout error (i.e. DMA buffers are not switching)

You can use this API to get the GPIF state CyU3PGpifGetSMState. For more details of this API you can refer to FX3 API guide in the SDK

- Please let me know the USB endpoint size and type that you are using in your firmware

Please let me know if any query on this

Regards,

Rashi

Regards,
Rashi

View solution in original post

0 Likes
3 Replies
Rashi_Vatsa
Moderator
Moderator
Moderator
5 likes given 500 solutions authored 1000 replies posted

Hello Greg,

From the description in your first response i could understand that the AUTO DMA channel is between GPIF > USB with DMA buffer size a 32 K and buffer count as 3. And DMA buffer is not switching after all the 3 if the buffers are read. Is my understanding right.

For debugging the problem can you changes the DMA channel type to AUTO SIGNAL (CY_U3P_DMA_TYPE_AUTO_SIGNAL) and register for the callback and the PROD and CONS event.

    .......

     dmaCfg.consSckId[0] = CY_FX_EP_CONSUMER_SOCKET;

     dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;

    dmaCfg.notification = CY_U3P_DMA_CB_CONS_EVENT | CY_U3P_DMA_CB_PROD_EVENT  ;

     dmaCfg.cb = GpifToUsbDmaCallback;

     dmaCfg.prodHeader = 0;

     dmaCfg.prodFooter = 0;

     dmaCfg.consHeader = 0;

     dmaCfg.prodAvailCount = 0;

     // TODO: Producer/Consumer

     apiRetStatus = CyU3PDmaChannelCreate (&glDmaChHandle, CY_U3P_DMA_TYPE_AUTO_SIGNAL, &dmaCfg);

     if (apiRetStatus != CY_U3P_SUCCESS)

     {

         CyU3PDebugPrint (4, "CyU3PDmaMultiChannelCreate failed, Error code = %d\n", apiRetStatus);

         CyFxAppErrorHandler(apiRetStatus);

     }

And in the DMA callback, can you increment a variable and then get them printed in the for {} later.

void

GpifToUsbDmaCallback (

        CyU3PDmaChannel   *chHandle,

        CyU3PDmaCbType_t   type,

        CyU3PDmaCBInput_t *input)

{

CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if (type == CY_U3P_DMA_CB_PROD_EVENT)

    {

prod ++;

    }

    if (type == CY_U3P_DMA_CB_CONS_EVENT)

    {

    cons++;

        /* Data transfer has been started. Enable the LPM disable loop. */

    }

in the thread entry function:

for (;;)

    {

    CyU3PDebugPrint (1, "\n\nprod = %d cons = %d ", prod,cons);

}

- Please let me know the GPIF state machine being used in the firmware

- Also,  check the state in which the GPIF state machine is in when you get the timeout error (i.e. DMA buffers are not switching)

You can use this API to get the GPIF state CyU3PGpifGetSMState. For more details of this API you can refer to FX3 API guide in the SDK

- Please let me know the USB endpoint size and type that you are using in your firmware

Please let me know if any query on this

Regards,

Rashi

Regards,
Rashi
0 Likes

Yes, your understanding is correct.

I have talked to a colleague who has implemented a similar system in the past and he told me that in order to get the DMA buffers to recycle I need to use the AUTO_MANY_TO_ONE mode with the two (GPIF) producers into the one (USB) consumer.  He said that until he did this he had the same issue with the buffers not re-cycling.  I just looked through the source code for the corresponding DMA example code (cyfxbulklpautomanytoone) and I don't see a DMA callback and I'm wondering how the ping-pong works;  Does the DMAC automatically reset the channel after it has completed the transfer so that it is prepared for when it is activated next?  To use this approach I guess I would need have two sockets on the GPIF I/F.  Will committing the buffer in the state machine cause the socket to switch in the FX3?  There doesn't seem to be anything in the documentation to explain this process, there are examples but no explanation and since my project doesn't exactly match the examples it is hard to know how to proceed.

Thanks,

Greg

0 Likes

Hi Greg,

I just looked through the source code for the corresponding DMA example code (cyfxbulklpautomanytoone) and I don't see a DMA callback and I'm wondering how the ping-pong works; 

>> DMA AUTO Multi Channel doesn't need CPU intervention hence the DMA callback cannot be registered. You can check the working of the DMA system from the section 4 (setting up DMA system) of AN 75779 application note https://www.cypress.com/file/123506/download

For DMA AUTO Multi Channel whenever the DMA buffer is fully filled, through a producer socket (GPIF II), Consumer socket will be signaled and the DMA buffer is committed to the consumer socket. When the Consumer socket (USB in this case) consumes the DMA buffer the DMA buffer will be marked ready/free for next transfer.

A GPIF thread is a dedicated data path in the GPIF II block that connects the external data pins to a socket. Every GPIF II socket is mapped to one thread. As this thread switching is faster than the buffer switching (which happens when single producer socket is used in the channel.). If the rate at which the data from external source to GPIF is fast, Multi (many_to_one) DMA channel can be used to avoid loss of data. Please refer to the above mentioned application note for better understanding

Please let me know if any queries from the application note.

Regards,

Rashi

Regards,
Rashi
0 Likes