Data loss when retargeting debug to Bulk Endpoint

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

cross mob
ChRO_4339966
Level 3
Level 3

Hello,

I am working on a John Hyde example (Bidir GPIF Slave interface from GPIF_Example6) where I have a Debug console attached to UART, and I am modifying it to copy these debug messages to EP1 IN (Bulk configuration).

I also followed some DualConsole example where an equivalent work is performed to retarget messages to I2C.

What I did is that I defined a manual DMA this way

     /* DMA Definition */

    // Setup and flush the endpoint

    Status = CyU3PSetEpConfig(0x81, &epConfig);

    // Create a AUTO channel for the Status to USB transfer, CPU detects and COMMITs the last short packet

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

    dmaConfig.size           = CY_U3P_DEBUG_DMA_BUFFER_SIZE;         // Use same size buffers for all USB Speeds

    dmaConfig.count          = 15;

    dmaConfig.prodSckId      = CY_U3P_CPU_SOCKET_PROD;

    dmaConfig.consSckId      = CY_U3P_UIB_SOCKET_CONS_1;

    dmaConfig.dmaMode        = CY_U3P_DMA_MODE_BYTE;

    Status = CyU3PDmaChannelCreate(&CPU2USB_Handle, CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaConfig);

    Status = CyU3PUsbFlushEp(0x81);

This DMA is then used at each call to mynew DualDebugPrint function largely inspired by John Hyde DualConsole example:

CyU3PReturnStatus_t DualDebugPrint(uint8_t Priority, char* Message, ...)

{

    // This takes the same parameters as CyU3PDebugPrint and my code is modeled on CyU3PDebugPrint

    // I format Message, including any parameters, into a DMA Buffer then Queue this buffer for EP1 IN

    // I check for Console Input after every Console Output

    // A Queue timeout is used to ensure that Console Input is called at least once a second

    CyU3PReturnStatus_t Status = CY_U3P_SUCCESS;

    va_list argp;

    CyU3PDmaBuffer_t CurrentDMABuffer;

    // First do some error checking

    if (Priority > glDebugTraceLevel) return CY_U3P_SUCCESS;

    if (CyU3PThreadIdentify() == NULL) return CY_U3P_ERROR_INVALID_CALLER;    // This function can only be called from a thread

    // OK to proceed, get a buffer then use a Cypress routine to do the Message interpretation

    CyU3PMutexGet(&EP1IN_DebugLock, CYU3P_WAIT_FOREVER);

    // Allocate the buffer for formatting the string.

    CurrentDMABuffer.buffer = CyU3PDmaBufferAlloc(CY_U3P_DEBUG_DMA_BUFFER_SIZE);

    if (CurrentDMABuffer.buffer == NULL) CheckStatus("CyU3PDmaBufferAlloc", CY_U3P_ERROR_MEMORY_ERROR);

    if (Status == CY_U3P_SUCCESS)

    {

        CurrentDMABuffer.count = CurrentDMABuffer.size = CY_U3P_DEBUG_DMA_BUFFER_SIZE;

        CurrentDMABuffer.status = 0;

        va_start(argp, Message);

        // MyDebugSNPrint updates CurrentDMABuffer.count

        Status = MyDebugSNPrint(CurrentDMABuffer.buffer, &CurrentDMABuffer.count, Message, argp);

        va_end(argp);

        // Increment the count to include the NULL character also.

        CurrentDMABuffer.count++;

    }

    if (Status == CY_U3P_SUCCESS)

    {

        // Copy the output to the UART Console also for this dual console example

        CyU3PDebugPrint(4, "%s", CurrentDMABuffer.buffer);

        // Push this message to EP1 IN

        Status = CyU3PDmaChannelSetupSendBuffer(&CPU2USB_Handle, &CurrentDMABuffer);

        //CheckStatus("CyU3PDmaChannelSetupSendBuffer", Status);

        // Wait there for DMA completion (actually a non-sense ?)

        //Status = CyU3PDmaChannelWaitForCompletion(&CPU2USB_Handle, CYU3P_WAIT_FOREVER);

    }

    if (CurrentDMABuffer.buffer != NULL)

    {

        CyU3PDmaBufferFree(CurrentDMABuffer.buffer);

    }

    CyU3PMutexPut(&EP1IN_DebugLock);

    return Status;

}

It works fine but what happens is that while UART messages are received OK, I loose frames sent to EP1 when I don't read them fast enough (via USB Control Center).

Also, looking at how loss occur, it seems that number of DMA buffers are actually lower than value configured (16 in my case).

Is there a way to make sure data are not lost within FX3 without "locking" the whole FW (eg using CyU3PDmaChannelWaitForCompletion function) and other DMAs execution ?

Thanks for help

Christophe

0 Likes
1 Solution

Hi Sridhar,

Thanks for proposal.

I actually moved to a much easier solution, pushing debug messages to USB socket at initialisation :

CyU3PDebugInit(CY_U3P_UIB_SOCKET_CONS_4, 8);

This makes my code much more compact 🙂

Regards

Christophe

View solution in original post

0 Likes
3 Replies
ChRO_4339966
Level 3
Level 3

Edit : I actually activated the call to CyU3PDmaChannelWaitForCompletion function and reduced number of messages sent at device initialisation. I could see there is no data loss.

But I am still facing the case where a single DMA buffer is actually implemented (I need to read a new buffer from my EP to allow FX3 FW to send another message). Is it possible to have multiple buffers instantiated in MANUAL DMA mode ?

Regards

Christophe

0 Likes

Hello Christophe,

You are operating the DMA in override mode using CyU3PSetupSendBuffer API.

This will allow you to send one buffer at a time,

If you want to send another buffer of data, you need wait for the host to be read the first buffer.

If you want to have multiple buffers to send from CPU to host.

You have to allocate a few buffers while creating the dma channel.

Get the buffer and copy the data and commit it to host.

Please refer BulkManualInOut example firmware in dmaexample folder of FX3 SDK.

Regards,

Sridhar

0 Likes

Hi Sridhar,

Thanks for proposal.

I actually moved to a much easier solution, pushing debug messages to USB socket at initialisation :

CyU3PDebugInit(CY_U3P_UIB_SOCKET_CONS_4, 8);

This makes my code much more compact 🙂

Regards

Christophe

0 Likes