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-CC1310: UART_write() not calling the callback function - nortos

Part Number: LAUNCHXL-CC1310
Other Parts Discussed in Thread: CC1310

I'm trying to work out how to use the UART drivers for the CC1310. I'm starting as a nortos project just to figure it out. Ultimately, I may end up using RTOS once I have a good handle on how all the drivers work. I have the code below, and it never calls uartWriteCallbackFxn(). This is not production code. This is minimal test code to figure it out. If you send it a byte, it does process the read callback function, sets totalBytes to 1, then writes that byte repeatedly, as fast as it can. It never runs the write callback to set totalBytes back to 0. 

/*
 * This is based on the TI uartecho_CC1310_LAUNCHXL_nortos example.
 * Trying to implement the UART driver in callback mode so that
 * I can then use that mode in more complex applications.
 *
 * 12/21/2017 DJQ
 */

/*
 *  ======== uartecho.c ========
 */
#include <stdint.h>
#include <stddef.h>

/* Driver Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/UART.h>
#include <ti/drivers/uart/UARTCC26XX.h>

/* Example/Board Header files */
#include "Board.h"


int totalBytes = 0;

char    input = '\0';


// ********************************************************************
//
// Callback Functions
//
// ********************************************************************

void uartReadCallbackFxn (UART_Handle handle, void *buf, size_t count)
{
    totalBytes = 1;
}

void uartWriteCallbackFxn (UART_Handle handle, void *buf, size_t count)
{
    totalBytes = 0;
}

/*
 *  ======== mainThread ========
 */
void *mainThread(void *arg0)
{

    const char  echoPrompt[] = "Echoing characters:\r\n";
    UART_Handle uart;
    UART_Params uartParams;

    /* Call driver init functions */
    GPIO_init();
    UART_init();

    /* Turn on user LED */
    GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);

    /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_TEXT;
    uartParams.readDataMode = UART_DATA_TEXT;
    uartParams.readReturnMode = UART_RETURN_FULL;
    uartParams.readEcho = UART_ECHO_OFF;
    uartParams.baudRate = 115200;
    uartParams.readMode = UART_MODE_CALLBACK;
    uartParams.writeMode = UART_MODE_CALLBACK;
    uartParams.readCallback = &uartReadCallbackFxn;
    uartParams.writeCallback = &uartWriteCallbackFxn;

    uart = UART_open(Board_UART0, &uartParams);

    if (uart == NULL) {
        /* UART_open() failed */
        while (1);
    }
    //    UART_control(uart, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL);
    UART_write(uart, echoPrompt, sizeof(echoPrompt));


    while (1) {

        UART_read(uart, &input, 1);
        if(totalBytes == 1){
            UART_write(uart, &input, 1);
        }

    }
}

What do I have to do in order to get it to call the callback for write mode as well? I'm my final code I will end up needing the callback to be called. 

  • Hi, the driver documentation for UARTCC26XX.h contains low level code snippets for UART in callback mode, check out this page:

  • Please do not use the driver documentation example on using callback mode. There is a bug in the driver documentation callback example where an blocking UART_write is called inside an SWI context.

    This is not supported and will result in the code locking up, this has been addressed and will be updated in future SDKs. For the example to work, the UART write mode also has to be set to callback mode and a callback function defined.

    I ran your code in the CC1310 uartecho example and I'm pretty sure I know what the problem is. Due to how the driver handles flushing the TX FIFO, there is a delay between the actual write and the callback getting called.  When you do the forever spin on UART_write (while totalByte = 1), you are causing a reset of the delay clock for every write keeping it from expiring and calling the callback.

    This is a limitation in the driver, leaving a small window between "write finish" and "write callback" where the driver actually allow for the user to post another write even tho the last write was not "completed", it is a known issue.

    So what is happening is that you are simply calling UART_write to fast and to often. You should not post another UART_write without confirming that the old one has completed first otherwise you most likely will end up clobbering the previous write.

    If you instead perform the 'echo' operation within the callbacks you won't have this problem:

    void uartReadCallbackFxn (UART_Handle handle, void *buf, size_t count)
    {
        UART_write(handle, &input, 1);
    }
    
    void uartWriteCallbackFxn (UART_Handle handle, void *buf, size_t count)
    {
        UART_read(handle, &input, 1);
    }

  • Yeah I noticed the blocking UART_write() call in the callback, and you are right as I had suspected when I saw that. It runs if you put the uart write mode into callback mode as you said. Elsewhere in the documentation (locally installed with the SDK) it tells us not to use blocking calls in a callback, which makes sense as we would typically try to avoid that anyways. There seems to be another bug as well, as that example works great if you want to grab wantedRxBytes each time without ever getting a partial. The page says that "Note: The partial return is also possible in UART_MODE_CALLBACK mode." bit this seems to be not accurate, as if you call: UART_control(uart, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL); you will never receive any data. I've been messing with the code example that Fred posted for a bit. I think I'm going to try what you posted now and see how that is going to work.

    I really like the idea of sending a batch/block of data when it comes in quick enough, but sending what you have if you timeout. My planned deployment of this is basically just a UART->RF->UART connection between CC1310's to use them as a link similar to the ones used for hobby drone telemetry (3DR radio pairs), but also having the ability to ad more functionality, such as star topology and simple robot and intelligent fixture control. It's looking like partial receives with a timeout but in callback mode isn't well supported by the driver. Perhaps that works much better when using TIRTOS? Also, I may be able to just deal with getting a byte at a time.
  • There should be no problem with return partial in callback mode. Trying it out on my version of the uartecho, doing 100 byte reads with return partial enabled, I'm still able to receive the single byte callbacks.

    When in your code are you calling the UART_control(uart, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL); part? You should call it before the initial read call, if not the initial call won't take this into account and perform a "normal" read.
  • M-W's solution seems to work the best, but the link that Fred posted is definitely worth a read as that info is not easy to find when you are using the locally installed documentation that comes with the SDK
  • What I have now is this:

    #include <stdint.h> #include <stddef.h> /* Driver Header files */ #include <ti/drivers/GPIO.h> #include <ti/drivers/UART.h> #include <ti/drivers/uart/UARTCC26XX.h> /* Example/Board Header files */ #include "Board.h" #define MAX_NUM_RX_BYTES 1000 // Maximum RX bytes to receive in one go #define MAX_NUM_TX_BYTES 1000 // Maximum TX bytes to send in one go uint32_t wantedRxBytes = 16; // Number of bytes received so far uint8_t rxBuf[MAX_NUM_RX_BYTES]; // Receive buffer uint8_t txBuf[MAX_NUM_TX_BYTES]; // Transmit buffer // Callback functions static void readCallback(UART_Handle handle, void *rxBuf, size_t size) { // turn on green led to to indicate we received uart data GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON); // Make sure we received all expected bytes if (size == wantedRxBytes) { // Copy bytes from RX buffer to TX buffer for(size_t i = 0; i < size; i++) txBuf[i] = ((uint8_t*)rxBuf)[i]; // Echo the bytes received back to transmitter UART_write(handle, txBuf, size); } else { // Handle error or call to UART_readCancel() } } static void uartWriteCallbackFxn (UART_Handle handle, void *buf, size_t count) { // turn off green led to to indicate we sent uart data GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF); // start another UART read now that we have sent UART_read(handle, rxBuf, wantedRxBytes); } /* * ======== mainThread ======== */ void *mainThread(void *arg0) { const char echoPrompt[] = "Echoing characters:\r\n"; UART_Handle uart; UART_Params uartParams; /* Call driver init functions */ GPIO_init(); UART_init(); /* Create a UART with data processing off. */ UART_Params_init(&uartParams); uartParams.writeDataMode = UART_DATA_BINARY; uartParams.readDataMode = UART_DATA_BINARY; uartParams.readReturnMode = UART_RETURN_NEWLINE; uartParams.readEcho = UART_ECHO_OFF; uartParams.baudRate = 115200; uartParams.readMode = UART_MODE_CALLBACK; uartParams.writeMode = UART_MODE_CALLBACK; uartParams.readCallback = readCallback; uartParams.writeCallback = uartWriteCallbackFxn; uartParams.readTimeout = 1000; // have tried various values from 10 to 1000000 uart = UART_open(Board_UART0, &uartParams); if (uart == NULL) { /* UART_open() failed */ while (1); } UART_control(uart, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL); // if this line is uncommented, you never get UART data UART_write(uart, echoPrompt, sizeof(echoPrompt)); int rxBytes = UART_read(uart, rxBuf, wantedRxBytes); /* Turn on user LED to indicate dropping into the while(1) */ GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON); while (1) { } }

    If that UART_control() call is in there, I will never receive any data. If I comment it out it works, but not as partial.

  • Nevermind, and thanks for your help. I found my problem with the partial and feel kinda dumb. It's the test in the read callback comparing size and wantedBytes. Obviously I was never going to call UART_write() on a partial with it like that.
  • Glad it worked out, happy to help!

    http://dev.ti.com/tirex is indeed a good place to find the SDK documentation. You should be able to find the same documentations if you open the documentation overview HTML inside the 'docs' folder in your local SDK installation folder.