FX3 UART to USB DMA "Wrap Up" problem.

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

cross mob
AnMc_4664421
Level 1
Level 1

I have an application based on the UsbUart example.  The only major difference is that I am using the alternative UART TxD and RxD pins, compared to those used on the Dev Kit.

The PC host application polls the hardware attached to the FX3 as ~1 second intervals, the response messages vary in length from a few bytes to ~120 bytes.

My problem is that occasionally return messages get "garbled".  My guess is that the periodic, but asynchronous to incoming requests, "wrap up" operation in the `for (;;)` loop in `USBUARTAppThread_Entry()`  with its disable/enable of the UART is causing the problem.

If I omit the "wrap up" then incomplete messages are returned, with the tail of the previous coming through with the beginning of the next, and shorter messages don't get through until (I assume) the DMA buffer is filled.  I've experimented with different buffer sizes, which can help with the longer responses if larger, but makes it worse for the shorter ones.

If I omit the disable/enable, then after a while (~1 hour) the serial communications over USB lock up altogether.

I have tried making the USB to UART DMA channel "AUTO_SIGNAL" and using the notification of a CONSUME event to set a flag to expect to need to wrap up, which could later be cleared after wrap up to avoid unnecessary disable/enable sequences, but this never seems to get triggered.  Would making it MANUAL work?, If so, what should the callback look like?  OTOH, should I just bypass the DMA altogether, and if so, can you give me some pointers as how this should look?

I thought that this thread:  FX3 : UART to USB minimal DMA size workaround   might hold a solution, since the described problem seemed to match mine, but the solution suggested seemed just to point back to implementing the UsbUart example, and thus back to square one.

0 Likes
1 Solution

Hello Andy,

I understood the application.

The idea of tracking the CONS event of USB to UART (AUTO SIGNAL) channel and then enabling the CyU3PDmaChannelSetWrapUp up API is correct.

To track the CONS event you can use a variable instead of LED. Try incrementing the variable and check if that value of that variable is incremented or not. You can also try setting an event and check in the for{} loop by Event GET.

Note: There is a possibility that CyU3PDmaChannelSetWrapUp is called before the complete data is filled in the DMA buffer so to avoid that a timer can be used to give enough time to get the data into the DMA buffer and then wrapping the DMA buffer

Please let me know the results that are you observing any change in the variable which is incremented when CONS  event  (USB > UART channel) occur

Let me know if any queries on this

Regards,

Rashi

Regards,
Rashi

View solution in original post

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

Hello,

The CyU3PDmaChannelSetWrapUp API is used to wrap and commit the partial buffer to the consumer socket. If the CyU3PDmaChannelSetWrapUp API is not called the DMA buffer only be committed when it is FULL.

- Is there some pattern of the data sent through UART? Is the size of the data to be transferred fixed?

- Can you share the debug prints of the problem that is faced while using CyU3PDmaChannelSetWrapUp API. This will help me to understand the problem better.

- Please let me know the DMA buffer size being used in the firmware.

I have tried making the USB to UART DMA channel "AUTO_SIGNAL" and using the notification of a CONSUME event to set a flag to expect to need to wrap up, which could later be cleared after wrap up to avoid unnecessary disable/enable sequences, but this never seems to get triggered.

>> The CONS event is triggered when the consumer (USB in this case) consumes the data. Please let me why do you use this approach.

To get the CONS event, it should be registered as shown below and then this event needs to be parsed in dmacallback

dmaConfig.notification   = CY_U3P_DMA_CB_PROD_EVENT | CY_U3P_DMA_CB_CONS_EVENT;

void

CyFxApplnDmaCallback (

        CyU3PDmaMultiChannel *chHandle,

        CyU3PDmaCbType_t      type,

        CyU3PDmaCBInput_t    *input

        )

{

    CyU3PDmaBuffer_t    dmaBuffer;

    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if (type == CY_U3P_DMA_CB_PROD_EVENT)

    {

}

else if (type == CY_U3P_DMA_CB_CONS_EVENT)

    {  

}

Regards,

Rashi

Regards,
Rashi
0 Likes

RashiV_61 wrote:

The CyU3PDmaChannelSetWrapUp API is used to wrap and commit the partial buffer to the consumer socket. If the CyU3PDmaChannelSetWrapUp API is not called the DMA buffer only be committed when it is FULL.

This I understand.

- Is there some pattern of the data sent through UART?

- Is the size of the data to be transferred fixed?

Not really, most messages end with a CRLF sequence, but some larger transfers include CRLF within the message to format it for human readability with a simple terminal program.

The data size is not fixed.

The hardware attached to the UART and the application interrogating it are 3rd party and I have no control over these.  My H/W with the FX3 is intended to be a transparent middle man in the exchange of messages.

- Can you share the debug prints of the problem that is faced while using CyU3PDmaChannelSetWrapUp API. This will help me to understand the problem better.

There is no debug channel, and with my hardware assembled to the target hardware, I physically can't connect a JTAG debugger.  I rely on a logging facility in the 3rd party application to give me some insight into what it is seeing and how it is interpreting the responses.

- Please let me know the DMA buffer size being used in the firmware.

I started with the 32 bytes from the UsbUart example, and I have also tried 16 bytes (the minimum) and 128 bytes (just a bit longer than the most frequent and most useful response).

The CONS event is triggered when the consumer (USB in this case) consumes the data. Please let me why do you use this approach.

No, I have tried using the CONS event in the USB -> UART channel to indicate that a request has been sent to the attached hardware and a response is to be expected which will require "wrapping up".

I have in my code:

     ...

     dmaCfg.notification = CY_U3P_DMA_CB_PROD_EVENT | CY_U3P_DMA_CB_CONS_EVENT;

     dmaCfg.cb           = CyFxUSB2UARTDmaCallback;

     ...

    /* AWM - Made AUTO_SIGNAL to attempt to synchronise with incoming requests */

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

and the callback function is:

/* Callback for USB to UART DMA events:

* If the USB has produced data, signal via the RED LED OFF,

* if the UART has consumed the data, signal via RED LED ON

* and clear the buffer-flushed flag.

* This is an AUTO DMA channel, no data commit required.     */

void CyFxUSB2UARTDmaCallback (CyU3PDmaChannel *chHandle,  /* Handle to the DMA channel. */

                              CyU3PDmaCbType_t type,      /* Callback type.             */

                              CyU3PDmaCBInput_t *input)   /* Callback status.           */

{

    if (type == CY_U3P_DMA_CB_PROD_EVENT)

    {

        CyU3PGpioSetValue(RED_LED_GPIO, LED_OFF);

    }

    else if (type == CY_U3P_DMA_CB_CONS_EVENT)

    {

        /* Clear the buffer-flushed flag, so the channel will get wrapped up */

        glUART_RxBufferFlushed = CyFalse;

        CyU3PGpioSetValue(RED_LED_GPIO, LED_OFF);

    }

}

Here, the RED LED is used as a means of signalling to me, via a 'scope, that something is happening, but I never see this event.

The UART to USB DMA callback is as follows:

/* Callback for UART to USB DMA events:

* If the UART has produced data, commit it to the USB channel. */

void CyFxUART2USBDmaCallback (CyU3PDmaChannel *chHandle, /* Handle to the DMA channel. */

                              CyU3PDmaCbType_t type,     /* Callback type.             */

                              CyU3PDmaCBInput_t *input)  /* Callback status.           */

{

    if (type == CY_U3P_DMA_CB_PROD_EVENT)

    {

        CyU3PDmaChannelCommitBuffer(&glChHandleUarttoUsb, input->buffer_p.count, 0);

        glPktsPending++;

    }

    else if (type == CY_U3P_DMA_CB_CONS_EVENT)

    {

        /* Decrement the packets pending counter, limiting at 0 */

        if (glPktsPending >= 1)

        {

            glPktsPending--;

        }

        else

        {

            glPktsPending = 0;

        }

    }

}

Finally, the periodic wrap up is as follows:

    for (;;)

    {

        if (glIsAppUARTlnActive)

        {

            /* While the application is active, check for data sent during the

             * last 50 ms. If no data has been sent to the host, use the channel

             * wrap-up feature to send any partial buffer to the USB host.    */

            if (glPktsPending == 0)

            {

                /* AWM - Do we really need to disable the UART??

                 * Perhaps it's to avoid incoming during "Wrap Up".

                 * It certainly seems that without it, the comms lock up,

                 * but with it, the comms are occasionally garbled. */

                /* Check if the UART to USB DMA channel needs "wrapping up". */

                if (glUART_RxBufferFlushed != CyTrue)

                {

                    /* Disable UART Receiver Block */

                    UART->lpp_uart_config = regValueDs;

                    CyU3PDmaChannelSetWrapUp(&glChHandleUarttoUsb);

                    /* Re-enable UART Receiver Block */

                    UART->lpp_uart_config = regValueEn;

                    glUART_RxBufferFlushed = CyTrue;          /* Clear flag */

                }

            }

            /* AWM - Why do this? To signify a check has been made? */

            /* AWM- Commented out while we try doing the decrement in the DMA call-back,

             * which appears to be working. */

//          glPktsPending = 0;

        }

        CyU3PThreadSleep(50);

    }

Cheers,

Andy

0 Likes

Hello Andy,

Here is what I understood from your previous posts and I am having few questions for better understanding of the issue

>>Data is sent from UART to USB when host application polls USB endpoint. Is this correct? Or is the data sent from USB to UART?

>> Is some data sent from USB to UART while polling?

>> what is the minimum bytes of data that is transferred?

No, I have tried using the CONS event in the USB -> UART channel to indicate that a request has been sent to the attached hardware and a response is to be expected which will require "wrapping up".

>> Is this channel used as feedback ?. I understood based on the response from the hardware connected to UART the CyU3PDmaChannelSetWrapUp API will be called. Is this correct?

The consumer event will occur if the UART consumes the data which is sent by USB. You can try calling CyU3PDeviceReset (CyFalse) in the condition where the consumer event is checked.

You can refer to this thread with a similar problem Re: Can ASCII ETX be used to produce EOP signal to DMA channel connected to FX3 UART  and let me know if this is what you are looking for.

Regards,

Rashi

Regards,
Rashi
0 Likes

Hi Rashi,

Thanks for your ongoing support.

RashiV_61 wrote:

Here is what I understood from your previous posts and I am having few questions for better understanding of the issue

>>Data is sent from UART to USB when host application polls USB endpoint. Is this correct? Or is the data sent from USB to UART?

The host application sends a character (typically a single character, no CRLF or similar) on the VCOM port provided by the FX3, which is forwarded to the UART Tx channel and thus to the attached hardware. This causes a response to be sent back on the Rx channel of the UART.  This response is of variable length, typically between 5 and 125 characters, but it can be much longer.  This response is returned to the host on the USB.

>> Is some data sent from USB to UART while polling?

As described above, the "polling" is always accompanied by data from USB to UART and thus to the attached hardware.  The host does not poll the IN endpoint in the FX3.

>> what is the minimum bytes of data that is transferred?

To the attached hardware on the UART Tx it is 1 byte.

From the attached hardware on the UART Rx, it is 4 or 5 bytes.

>> Is this channel used as feedback ?. I understood based on the response from the hardware connected to UART the CyU3PDmaChannelSetWrapUp API will be called. Is this correct?

My intention is that when a USB -> UART event occurs, the FX3 "knows" to expect a response on the UART Rx, which will need to be sent back to the host on the USB, and that this will need wrapping up because the message length is unlikely to be exactly an integral number of DMA buffer-size bytes.  The idea behind "knowing" that a wrap-up is required is to only do the wrap-up when necessary, and not every 50ms.

You can try calling CyU3PDeviceReset (CyFalse) in the condition where the consumer event is checked.

What will this do for me?  A reset seems quite drastic.

You can refer to this thread with a similar problem Re: Can ASCII ETX be used to produce EOP signal to DMA channel connected to FX3 UART  and let me know if this is what you are looking for.

At first glance, it does not appear to address my problem, but I will re-read it more carefully.

Regards,

Andy

0 Likes

Hello Andy,

I understood the application.

The idea of tracking the CONS event of USB to UART (AUTO SIGNAL) channel and then enabling the CyU3PDmaChannelSetWrapUp up API is correct.

To track the CONS event you can use a variable instead of LED. Try incrementing the variable and check if that value of that variable is incremented or not. You can also try setting an event and check in the for{} loop by Event GET.

Note: There is a possibility that CyU3PDmaChannelSetWrapUp is called before the complete data is filled in the DMA buffer so to avoid that a timer can be used to give enough time to get the data into the DMA buffer and then wrapping the DMA buffer

Please let me know the results that are you observing any change in the variable which is incremented when CONS  event  (USB > UART channel) occur

Let me know if any queries on this

Regards,

Rashi

Regards,
Rashi
0 Likes

Hello Rashi,

Working with a colleague, we have come up with pretty much the solution that you suggest, thanks.  The delay in replying is because we wanted to do some overnight testing.

To track the CONS event you can use a variable instead of LED. Try incrementing the variable and check if that value of that variable is incremented or not. You can also try setting an event and check in the for{} loop by Event GET.

The LED was only ever used to provide some external indication of what was going on inside.  We did come up with the idea to increment a variable to detect changes and test for changes in the external timed loop.

Note: There is a possibility that CyU3PDmaChannelSetWrapUp is called before the complete data is filled in the DMA buffer so to avoid that a timer can be used to give enough time to get the data into the DMA buffer and then wrapping the DMA buffer

My colleague spotted this possibility too.  So, the first time the test is made in the for (;;) loop, which, as you say could be too soon, we flag that the variable had not incremented then wait another delay time to check again.  Two non-increments in a row means that we wrap up the buffer, if there is an increment, then the new variable value is stored locally for the next comparison, the "has_not_changed" flag is cleared and we sleep again.

This all appears to be working, but further testing is required.

I do have one more question:  Why is it necessary to disable the UART before doing the wrap-up, then re-enable it afterwards?  This appears to be sometimes causing us further problems.

Andy

0 Likes

Hi Andy,

Is the problem resolved?

Regards,

Rashi

Regards,
Rashi
0 Likes

Rashi asked:

Is the problem resolved?

I'm afraid not.

Were you able to get an answer to my question:

Why is it necessary to disable the UART before doing the wrap-up, then re-enable it afterwards?

I found that when implementing the original version, closely based on the Cypress UsbUart example project, omitting this step got away from the "garbling" of the return data from UART to USB, but caused the communications to completely lock up after an hour or so.  Since improving the logic for the wrap-up, as discussed above in the thread, I have also tried removing the disable again, with better results.  I am now going to run an extended test of this arrangement.

However, I would still like to know why it was put in in the first place?  Was it to improve the behaviour with the incomplete solution as provided in the example?

It is looking more and more as though we will have to abandon the DMA approach and do a register based byte-by-byte transfer.  Do you have any pointers for an implementation, especially the mechanism for getting the data from the UART Rx FIFO into the USB IN Endpoint for return to the host?

Cheers,

Andy

0 Likes

Hello Andy,

Why is it necessary to disable the UART before doing the wrap-up, then re-enable it afterwards?

>> CyU3PDmaChannelSetWrapUp API will wrap up the current socket and commit the data to the consumer socket. In the UsbUart example, the wrapup is done for the UART >USB channel. The receiver of the UART is disabled before wrapping up the data to avoid the incoming data to the current socket (UART socket) while the socket is being wrapped up.

In your application, the data from UART to USB is definite i.e. 4-5 bytes and there will no data coming to UART (RX) till a request is made by host you can try removing the UART RX enable/disable which is used in the default usbuart project.

Do you have any pointers for implementation, especially the mechanism for getting the data from the UART Rx FIFO into the USB IN Endpoint for return to the host?

>> For using the UART in register mode you can refer to UartLpRegmode example of the SDK. As the received data (at UART) need to be sent to USB IN endpoint a DMA channel is needed. You can use a MANUAL_OUT channel for UART > USB. The data received at the RX FIFO needs to be copied to a buffer and then the buffer can be sent through MANUAL_OUT channel to USB IN endpoint.

You can refer to bulksrcsink example of the SDK which implements the MANUAL_OUT channel.

Regards,

Rashi

Regards,
Rashi
0 Likes

Andy,

Adding to my previous response

The UART can be configured either in DMA mode or in register mode. It cannot be configured in both simultaneously.

Regards,

Rashi

Regards,
Rashi
0 Likes

Hi Rashi,

Thanks for your help so far.

We didn't manage to get the callback in the USB -> UART Tx DMA channel working in AUTO_SIGNAL mode, so we implemented a register interface to and from the UART, with USB -> CPU and CPU -> USB as MANUAL_IN and MANUAL_OUT DMA channels.

(Confusingly here IN and OUT are relative to the CPU, and not the USB host as applied when setting up the USN endpoints.)

Cheers,

Andy

0 Likes

Hello Andy,

We didn't manage to get the callback in the USB -> UART Tx DMA channel working in AUTO_SIGNAL mode, so we implemented a register interface

>> The CONS event for USB >UART channel will only be generated if the UART TX consumes the data from the DMA buffer. Is the 1-byte data received by the UART hardware that is connected to FX3?

It would be convenient for you to configure the UART in DMA mode and implement the previously mentioned suggestion.

- Please check whether the event CY_U3P_DMA_CB_CONS_EVENT is generated using a variable and then printing the variable in for {}. If the data is received by the external hardware (UART), the CONS event would be generated.

Yes, MANUAL IN ( CPU is a consumer), and MANUAL OUT (CPU is producer) channels are named with respect to the CPU and not the USB host.

Regards,

Rashi

Regards,
Rashi
0 Likes