This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LAUNCHXL-CC1352P: uart2 incorrect data receivied

Part Number: LAUNCHXL-CC1352P

Hi TI,

I am attempting to use the UART2 driver but it appears there may be a bug.  I am running at 3M baud, and have sniffed the data on a logic analyzer @ 3M baud, and the data on-the-wire appears correct. 

When UART2_read returns, I receive the correct number of bytes received (256), but after 50 so bytes, there is incorrect data.  

Is this a known issue with UART2 driver?

Thanks,

Ben





  • every byte received should be 0x31, but after 55 bytes they begin to look corrupted.  

    On sdk 5.2

  • Hi Ben,

    Is this something that happens only when using that baud rate?. Or does it occur as well with lower baud rates such as 115200?

    BR,
    Andres

  • Hi again Ben,

    Looking at your code, I wonder if using Partial Return mode is the best option. I think that this might be causing issues.

    Please set it to:

        uartParams.readReturnMode = UART2_ReadReturnMode_FULL;
    

    And let me know if you experience the same.

    BR,
    Andres

  • It does not occur at baud rate = 2000000

    I do however need to fix this at 3000000 baud, as that is my application requirement.  I am using a standard FT232 FTDI to input data with flow control.

  • I do need partial return, since I'm not sure beforehand how much data will be received.  I tried full, but the problem persists at 3M baud.

  • Hi Ben,

    I think that I understand what’s happening. And it does relate to the use Return Partial.

    Return Partial mode is implemented such that it unblocks or performs a callback whenever a read timeout error occurs on the UART peripheral. The read timeout occurs if the read FIFO is non-empty and no new data has been received for a number of clock cycles.

    This (as stated in the Driver’s documentation) can be used to handle data transfers where the exact number of bytes to be read is not known. But the key thing here, is that this only works if you have a strictly constant stream of data coming from the device that is sending the data (in your case the FTDI). So, the time interval between each character sent must not be high enough to trigger the read timeout. Otherwise, the transaction ends, and you only get some data (in your case, the first 50 bytes or so).

    My guess is that the data coming from the FTDI is coming with a baud rate of 3Mbaud, but you also have some time interval between each character (you can probably see this by zooming the scope trace).

    To test this, I modified the uart2callback example to do the following.

    1. Receive 256 bytes of data at a baud rate of 3Mbaud coming from Teraterm.
    2. Wait for the callback of the read operation to execute.
    3. Echo back to Teraterm using the data that has been received.

    You can use the following code to test:

    static sem_t sem;
    
    /*
     *  ======== callbackFxn ========
     */
    void callbackFxn(UART2_Handle handle, void *buffer, size_t count,
            void *userArg, int_fast16_t status)
    {
        if (status != UART2_STATUS_SUCCESS) {
            /* RX error occured in UART2_read() */
            while (1);
        }
        sem_post(&sem);
    }
    
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        char         input[256];
        const char   echoPrompt[] = "Echoing characters:\r\n";
        int32_t      semStatus;
        UART2_Handle uart;
        UART2_Params uartParams;
        size_t       bytesWritten = 0;
        uint32_t     status = UART2_STATUS_SUCCESS;
        uint32_t     i;
    
        /* Create a UART where the default read and write mode is BLOCKING */
        UART2_Params_init(&uartParams);
        uartParams.baudRate = 3000000;
        uartParams.writeMode = UART2_Mode_BLOCKING;
    
    //    uartParams.readReturnMode = UART2_ReadReturnMode_PARTIAL;
        uartParams.readReturnMode = UART2_ReadReturnMode_FULL;
        uartParams.readMode = UART2_Mode_CALLBACK;
        uartParams.readCallback = callbackFxn;
    
        /* Create semaphore */
        semStatus = sem_init(&sem, 0, 0);
    
        if (semStatus != 0) {
            /* Error creating semaphore */
            while (1);
        }
    
        uart = UART2_open(CONFIG_UART2_0, &uartParams);
    
        if (uart == NULL) {
            /* UART2_open() failed */
            while (1);
        }
    
        UART2_write(uart, echoPrompt, sizeof(echoPrompt), &bytesWritten);
    
        /* Loop forever echoing */
        while (1) {
    
            for (i = 0; i < 256; i++) {
                input[i] = 0;
            }
    
            status = UART2_read(uart, &input, 256, NULL);
    
            if (status != UART2_STATUS_SUCCESS) {
                /* UART2_read() failed */
                 while (1);
            }
    
            /* Do not write until read callback executes */
            sem_wait(&sem);
    
            status = UART2_write(uart, &input, 256, NULL);
    
                if (status != UART2_STATUS_SUCCESS) {
                    /* UART2_write() failed */
                    while (1);
                }
        }
    }

    When using UART2_ReadReturnMode_FULL, I get all the data, but if I use UART2_ReadReturnMode_PARTIAL, I don't get all the data.

    Furthermore, if you look at the scope trace, you can see that the data transmitted from the PC host to the CC1352 device (Rx trace) took longer than the data the CC1352 transmitted back to the PC host (Tx trace). Even though both transmissions use the same baud rate.

    So I guess that your option here would be to either use Partial return mode and handle such cases, or use UART2_readTimeout() with Full return mode, while setting a sensible timeout value. Then you can use the bytesRead parameter to determine the amount of data that you have received.

    BR,
    Andres

  • Hi Andres, thanks for looking into this.  You were right, the baud rate change didn't fix it entirely, this issue started rearing its head again soon after I changed to that.  

    So my datastream coming in is definitely at 3Mbaud - no gaps.  




    So I don't think the partial read mode is to blame. 


    I actually had this working in a much simpler sense in a different project, so I went back to that to verify I can read and echo the uart data. 

    void *mainThread(void *arg0)
    {
        char         input;
        const char   echoPrompt[] = "Echoing characters:\r\n";
        UART2_Handle uart;
        UART2_Params uartParams;
        size_t       bytesRead;
        size_t       bytesWritten = 0;
        uint32_t     status = UART2_STATUS_SUCCESS;
    
        /* Call driver init functions */
        GPIO_init();
    
        /* Configure the LED pin */
        GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        /* Create a UART where the default read and write mode is BLOCKING */
        UART2_Params_init(&uartParams);
        uartParams.baudRate = 3000000;
        uartParams.readMode = UART2_Mode_BLOCKING;
        uartParams.readReturnMode = UART2_ReadReturnMode_PARTIAL;
        uartParams.writeMode = UART2_Mode_BLOCKING;
    
    
        uart = UART2_open(CONFIG_UART2_0, &uartParams);
    
        if (uart == NULL) {
            /* UART2_open() failed */
            while (1);
        }
    
        /* Turn on user LED to indicate successful initialization */
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
    
       // UART2_write(uart, echoPrompt, sizeof(echoPrompt), &bytesWritten);
        int totalBytesRead = 0;
        int totalBytesWritten = 0;
    
        uint8_t buffer[128];
        /* Loop forever echoing */
        while (1) {
            bytesRead = 0;
    
            size_t  bytesRead;
    
            int32_t status;
            status = UART2_read(uart, buffer, 128, &bytesRead);
            totalBytesRead += bytesRead;
            if (status != UART2_STATUS_SUCCESS) {
                /* UART2_read() failed */
                 while (1);
            }
    
            bytesWritten = 0;
            while (bytesWritten < bytesRead) {
                status = UART2_write(uart, buffer + bytesWritten, bytesRead - bytesWritten, &bytesWritten);
                bytesWritten += bytesWritten;
                totalBytesWritten += bytesWritten;
                if (status != UART2_STATUS_SUCCESS) {
                    /* UART2_write() failed */
                    while (1);
                }
            }
        }
    }
    

    And this works just fine at 3M with partial read mode!  

    So I went back to my project with RF stuff, and started taking stuff out to see what is affecting the UART.  I have another task that initiates the RF driver, and by putting a semaphore BEFORE my call to RF_Open, I prevent any RF stuff from initializing.   I found that once I prevent the RF_Open(), the UART echo works fine!

    So I think we have found our culprit - there is some DMA conflict between the RF driver and the UART driver?

  • Hi Ben,

    I'm glad that you found the culprit. We can then conclude that the UART2 driver is behaving as expected.

    Now, it's interesting what you are describing with RF_Open(), although it's hard for me to tell what might be causing this. I guess it depends a lot on you actual implementation. For instance, when are you using RF_Open()? Is it being called while a UART transfer is taking place?

    There's a lot of things that could happen. There could be a race condition somewhere, or it could be that the UART transfer is being momentarily interrupted by the other thread.

    BR,
    Andres

  • Hi Andres,

    I'm not sure we can conclude the UART2 driver behaves as expected - in fact - it seems to not behave as expected with another peripheral open.  

    I further simplified the failure case.  Now there's one task in my system, and I simply moved the call an rf_open() right before my uart2 echo loop:



    xdc_Void serialToUartTask(xdc_UArg arg1, xdc_UArg arg2)
    {
        UART2_Params_init(&uartParams);
        uartParams.baudRate = 3000000;
        uartParams.readMode = UART2_Mode_BLOCKING;
        uartParams.readReturnMode = UART2_ReadReturnMode_PARTIAL;
        uartParams.writeMode = UART2_Mode_BLOCKING;
    
        uart = UART2_open(CONFIG_UART2_0, &uartParams);
    
        char         input;
        size_t       bytesRead;
        size_t       bytesWritten = 0;
        uint32_t     status = UART2_STATUS_SUCCESS;
    
        uint8_t read_buffer2[128];
    
        static RF_Object rfObject;
        static RF_Handle rfHandle;
    
    
        /* Initialize the radio */
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
        /* Loop forever echoing */
        while (1) {
            bytesRead = 0;
    
            size_t  bytesRead;
    
            int32_t status;
    
            status = UART2_read(uart, read_buffer2, sizeof(read_buffer2), &bytesRead);
            if (status != UART2_STATUS_SUCCESS) {
                /* UART2_read() failed */
                 while (1);
            }
    
    
            if (bytesRead > 0)
            {
                msg.data_length = bytesRead;
                memcpy(msg.data_array, read_buffer2, bytesRead);
    
    
                int bytesWritten = 0;
                while (bytesWritten < bytesRead) {
                    status = UART2_write(uart, read_buffer2 + bytesWritten, bytesRead - bytesWritten, &bytesWritten);
                    bytesWritten += bytesWritten;
                    if (status != UART2_STATUS_SUCCESS) {
                        /* UART2_write() failed */
                        while (1);
                    }
                }
    
            }
    
            bytesWritten = 0;
    
        }
    }

    With line 26 commented out, the uart2 echo works!  With line 26 there, the data coming in after 50 or so bytes is not correct (but like I mentioned the length detected [bytesRead]) is indeed correct!

    The rf is not being used, its just opened once.  

    Can you reproduce this? This is all on a launchpad CC1352P1

  • Hi Ben,

    I see. Would you mind sharing some project files that I could use to reproduce the issue you are seeing?

    Or provide some instructions on how to use your code snippet to reproduce the issue.

    Thanks.

    BR,
    Andres

  • Hi Andres

    Here's a full code dump.  You should be able to import to ccs.  Just run it, when its running it should echo any character received.  I think you had an FTDI set up, you should see the issue if line 26 is not commented out.  If you comment out line 26, should see no issue with the UART2.

    Ben8228.ti dump.zip

  • Hi Ben,

    Thank you for the files. I'll get back to you once I've reproduced the issue.

    BR,
    Andres

  • Hi again Ben,

    Sorry for the late reply.

    I was having some issues with the project files that you submitted, but I have reproduced what you are seeing.

    To be honest, I don't really understand what might be causing this, so I need to do some additional tests and dig a little deeper. I just wanted to verify with you that the issue is only happening with return partial mode, or have you noticed anything similar with full return mode? Have you seen anything else that you would like to report?

    BR,
    Andres

  • Ah yes, I link into some common code from several workspaces so maybe that was why you were having some trouble.

    Glad you reproduced it.  Was starting to feel crazy! I can't really comment for sure if it happens in full return mode too as well, I think it did though.  I'm not in a position to go back and try and reproduce it anymore.

    I will say that the UART (not UART2) driver works with the RF_Open() (i've proceeded on the project with this driver instead) so definitely seems DMA related to me.  

  • Hi Ben,

    Thanks for the update. I'll report your findings and mine, so that this unexpected behavior can be dealt with soon.

    BR,
    Andres

  • Hi Andres - is there any update from R&D on cause for this problem?  UART driver 1 has worked OK for me this far, but my application is now CPU bound from the UART driver. It would be great to free the CPU by using the UART2 driver DMA functionality.

    Thanks

  • Hi Ben,

    I have reported this to R&D and provided the required information for them to reproduce the issue. Nevertheless, I can't tell you exactly when the issue will be addressed. 

    BR,
    Andres