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-CC2640R2: UART Callback does not work?

Part Number: LAUNCHXL-CC2640R2
Other Parts Discussed in Thread: CC2640R2F

Hi,

    The implemented UART Callback at UART Echo example program but it does not work. I use svendbt code snippets from this post below.

Here is my modified UART echo example program. It prints the "Echoing characters:" so the UART works. I place a breakpoint at uartRxCb(), but when I press a key, it does not go to uartRxCb(). Why is that? Do you have any UART example programs for CC2640R2F Launchpad that demonstrates UART Callback?

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

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

#include "string.h"

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

#define BUFTYPE char
#define PBUFTYPE char*
#define BUFSIZE 1

UART_Handle uart;

BUFTYPE rxBuf[BUFSIZE];
BUFTYPE txBuf[BUFSIZE];


static void uartRxCb(UART_Handle handle, void *buf, size_t count) {
  //Copy rxBuf to txBuf
  memset(txBuf, 0, BUFSIZE);
  memcpy(txBuf, rxBuf, count);
  UART_write(uart, txBuf, sizeof(txBuf)/sizeof(BUFTYPE));
}

/*
 *  ======== mainThread ========
 */
void *mainThread(void *arg0)
{
    const char  echoPrompt[] = "Echoing characters:\r\n";
    UART_Params uartParams;

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

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

    /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);

    uartParams.readMode = UART_MODE_CALLBACK;
    uartParams.writeMode = UART_MODE_BLOCKING;
    uartParams.readCallback = uartRxCb;
    uartParams.readEcho = UART_ECHO_OFF;
    uartParams.baudRate = 115200;

    uart = UART_open(Board_UART0, &uartParams);

    if (uart == NULL) {
        /* UART_open() failed */
        while (1);
    }

    UART_write(uart, echoPrompt, sizeof(echoPrompt));

    /* Loop forever echoing */
    while (1) {
        UART_read(uart, &rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));

    }
}

- kel

  • Hi Markel, I don't see why using your code and pressing a key, it should go to uartRxCb. Can you elaborate what would happen in your code when pressing a key?

  • Hi Yikai,

    Here are my observations below.

    1. If I press the key once and then wait for more than 30 seconds, it does not go to the uartRxCb.
    2. If I press the key repeatedly like more than 10x, it goes to the uartRxCb.

    Why do I need to press the key repeatedly for the program to go to uartRxCb?

    - kel
  • In your code, I don't see any button pressed related code. I don't see any relation about button pressing and uartRxCb. By the way, do you enable power saving when you test this?
  • Hi Yikai,

    I press a key of my laptop keyboard with Tera Term open. There are no POWER SAVING predefined symbol set at CCS. I am using uart_echo example program then modified it according to svendbt code.

    - kel
  • Hi Markel Robregado,
    Do you use the key for simulate the data on uart?
    Your BUFSIZE is 1, the callback is called after UART received 1 byte (= 8 clock). That mean is you need to press 8 times for a short time to simulate 1 byte.
  • Hi Luu Vy,

        You are correct, the program goes to uartRxCb(), after 8 key presses. But, I need to set it the callback trigger after 1 key press only. What is the recommended initialization for that? I am doing this test so that I can apply it at my product development.

        I need to parse strings like BUZZZER, LED0, and LED1.

    Here is my UART Callback for my product development.

    void UartApp__UartRxCB(UART_Handle handle, void *buf, size_t count)
    {
      
        WORD i;
    
        for ( i = 0; i < count; i++)
        {
            TestApp__DecodeData(*(((BYTE *)buf)+i));
        }
    
        return;    
    }
    void TestApp__DecodeData(BYTE rx_data)
    {
        /* read byte from buffer */
        switch (rx_data)
        {
            /* Check for terminiation char */
            case '\r': /* '\r' 0x0D */
            {
                /* Command complete and process the test command */
                TestApp__UartMsgHandler(&TestCmd[0]);
    
                /* After process the test command, reset the test command buffer to null terminated */
                MEMSET(&TestCmd[0], '\0', MAX_TEST_CMD_LEN);
    
                /* reset the test command index */
                TestCmdIndex = 0;
                break;
            }
    
            /* Delete the character to the left of the buffer */
            case '\b': /* '\b' 0x08 */
            {
                if (TestCmdIndex == 0)
                {
                    /* There are no character to delete */
                }
                else
                {
                    if (TestCmdIndex > 0)
                    {
                        TestCmdIndex--;
                    }
                    else
                    {
                        /* Do nothing */
                    }
    
                    /* Delete the character to the left of the buffer */
                    TestCmd[TestCmdIndex] = '\0';
                }
                break;
            }
    
            default:
            {
                if (((rx_data >= '0') && (rx_data <= '9')) ||
                    ((rx_data >= 'A') && (rx_data <= 'Z')) ||
                    ((rx_data >= 'a') && (rx_data <= 'z')) ||
                    ((rx_data == ' ')))
                {
                    TestCmd[TestCmdIndex] = rx_data;
                    TestCmdIndex++;
                }
                else
                {
                    /* Ignore the rest of unsupported keys */
                }
                break;
            }
        }
    
        return;
    }

    - kel

  • I have already changed my UART initialization to this below. But, still I need to press the key 8x for the program to go to UART Callback.

    UART_Params_init(&uartParams);
    
        uartParams.readMode = UART_MODE_CALLBACK;
        //uartParams.writeMode = UART_MODE_BLOCKING;
        uartParams.readCallback = uartRxCb;
        //uartParams.readEcho = UART_ECHO_OFF;
        uartParams.baudRate = 115200;
    
        uartParams.readDataMode = UART_DATA_BINARY;//UART_DATA_TEXT;
        uartParams.writeDataMode = UART_DATA_BINARY;//UART_DATA_TEXT;
        uartParams.dataLength = UART_LEN_8;
        //uartParams.stopBits = UART_STOP_ONE;
        uartParams.readReturnMode = UART_RETURN_FULL;//UART_RETURN_NEWLINE;
    
    
        uart = UART_open(Board_UART0, &uartParams);
    
        if (uart == NULL) {
            /* UART_open() failed */
            while (1);
        }
    
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
    
        /* Loop forever echoing */
        while (1) {        
            UART_read(uart, rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));
        }

    - kel

  • Problem Solved. I moved the Uart Read outside the while loop. It goes to UART Callback after 1 key press.

    const char  echoPrompt[] = "Echoing characters:\r\n";
        UART_Params uartParams;
    
        /* Call driver init functions */
        GPIO_init();
        UART_init();
    
        /* Turn on user LED */
        GPIO_write(Board_GPIO_LED0, 1);
    
        /* Create a UART with data processing off. */
        UART_Params_init(&uartParams);
    
        uartParams.readMode = UART_MODE_CALLBACK;
        uartParams.writeMode = UART_MODE_BLOCKING;
        uartParams.readCallback = uartRxCb;
        uartParams.baudRate = 115200;
    
        uartParams.readDataMode = UART_DATA_BINARY;//UART_DATA_TEXT;
        uartParams.writeDataMode = UART_DATA_BINARY;//UART_DATA_TEXT;
        uartParams.dataLength = UART_LEN_8;
        //uartParams.stopBits = UART_STOP_ONE;
        uartParams.readReturnMode = UART_RETURN_FULL;//UART_RETURN_NEWLINE;
    
    
        uart = UART_open(Board_UART0, &uartParams);
    
        if (uart == NULL) {
            /* UART_open() failed */
            while (1);
        }
    
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
        UART_read(uart, rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));
    
        /* Loop forever echoing */
        while (1) {
            //UART_read(uart, rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));
        }

    - kel

  • Hi Markel Robregado,

    But it only callback one time. You need re-call UART_read for next callback.
  • It strange that it need re-call UART_read for next callback.
  • Hi Luu Vy,

        Yes, it does callback only one time. Maybe because "uartParams.writeMode = UART_MODE_BLOCKING". Maybe I need to use semaphores from svendbt code. I notice that the callback happens when the buffer is full.

       It was really weird that I needed to press the key 8x in order to trigger a UART Read Callback.

       I have been experimenting what could cause a UART Read Callback and I notice that if I set this below, the UART Read Callback does not happen if I press "Enter Key".

    uartParams.readDataMode = UART_DATA_TEXT;
    uartParams.writeDataMode = UART_DATA_TEXT;
    uartParams.readReturnMode = UART_RETURN_NEWLINE;

       Also if I set this below, the characters are not echoed back.

    uartParams.readEcho = UART_ECHO_ON;

       Can someone from TI comment regarding why these 2 above are not supported.

    - kel

  • Hi Luu Vy,

        I was able to continuously do UART ECHO if I call UART_read() at UART Transmit Callback. Somehow seems not right way, but it works.

    /*
     *  ======== uartecho.c ========
     */
    #include <stdint.h>
    #include <stddef.h>
    
    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/UART.h>
    
    /* Example/Board Header files */
    #include "Board.h"
    #include "string.h"
    
    //added by markel
    #define BUFTYPE char
    #define PBUFTYPE char*
    #define BUFSIZE 1
    UART_Handle uart;
    
    BUFTYPE rxBuf[BUFSIZE];
    BUFTYPE txBuf[BUFSIZE];
    
    
    static void uartTxCb(UART_Handle handle, void *buf, size_t count) {
    
      UART_read(uart, rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));
    }
    
    
    //added by markel
    static void uartRxCb(UART_Handle handle, void *buf, size_t count) {
      //Copy rxBuf to txBuf
      memset(txBuf, 0, BUFSIZE);
      memcpy(txBuf, rxBuf, count);
      UART_write(uart, txBuf, count);
    
    }
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        const char  echoPrompt[] = "Echoing characters:\r\n";
        UART_Params uartParams;
    
        /* Call driver init functions */
        GPIO_init();
        UART_init();
    
        /* Turn on user LED */
        GPIO_write(Board_GPIO_LED0, 1);
    
        /* Create a UART with data processing off. */
        UART_Params_init(&uartParams);
    
        uartParams.readMode = UART_MODE_CALLBACK;
        uartParams.writeMode = UART_MODE_CALLBACK;
        uartParams.readCallback = uartRxCb;
        uartParams.writeCallback = uartTxCb;
        uartParams.baudRate = 115200;
    
        uartParams.readDataMode = UART_DATA_TEXT;//UART_DATA_BINARY;
        uartParams.writeDataMode = UART_DATA_TEXT;//UART_DATA_BINARY;
        uartParams.dataLength = UART_LEN_8;
        uartParams.stopBits = UART_STOP_ONE;
        uartParams.readReturnMode = UART_RETURN_NEWLINE;//UART_RETURN_FULL;
    
    
        uart = UART_open(Board_UART0, &uartParams);
    
        if (uart == NULL) {
            /* UART_open() failed */
            while (1);
        }
    
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
    
        UART_read(uart, rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));
    
        /* Loop forever echoing */
        while (1) {
    
        }
    }

    I have read in the forum that the best way to handle UART is to create another Task. Here below is a link to the example program.

    - kel

  • It's weird that we have to call UART_read() at UART Transmit Callback to make RX callback work. Hope someone from TI can explain this.
  • Hi Markel Robregado,

    Your code will work because its logic is correct. 
    When you receive Rx Callback. You call uart_write. After TX write is completed. TX Callback is called. In TX call function, you call uart_read again. So you can receive RX Callback again.
    We can modify code as follows.

    /*
     *  ======== uartecho.c ========
     */
    #include <stdint.h>
    #include <stddef.h>
    
    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/UART.h>
    
    /* Example/Board Header files */
    #include "Board.h"
    #include "string.h"
    
    //added by markel
    #define BUFTYPE char
    #define PBUFTYPE char*
    #define BUFSIZE 1
    UART_Handle uart;
    
    BUFTYPE rxBuf[BUFSIZE];
    BUFTYPE txBuf[BUFSIZE];
    uint8_t rxFlag = 0;
    uint8_t txFlag = 0;
    static void uartTxCb(UART_Handle handle, void *buf, size_t count) {
      txFlag = 0;
      //UART_read(uart, rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));
    }
    
    
    //added by markel
    static void uartRxCb(UART_Handle handle, void *buf, size_t count) {
      //Copy rxBuf to txBuf
      memset(txBuf, 0, BUFSIZE);
      memcpy(txBuf, rxBuf, count);
      rxFlag = 0;
      txFlag = 1;
      UART_write(uart, txBuf, count);
    
    }
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        const char  echoPrompt[] = "Echoing characters:\r\n";
        UART_Params uartParams;
    
        /* Call driver init functions */
        GPIO_init();
        UART_init();
    
        /* Turn on user LED */
        GPIO_write(Board_GPIO_LED0, 1);
    
        /* Create a UART with data processing off. */
        UART_Params_init(&uartParams);
    
        uartParams.readMode = UART_MODE_CALLBACK;
        uartParams.writeMode = UART_MODE_CALLBACK;
        uartParams.readCallback = uartRxCb;
        uartParams.writeCallback = uartTxCb;
        uartParams.baudRate = 115200;
    
        uartParams.readDataMode = UART_DATA_TEXT;//UART_DATA_BINARY;
        uartParams.writeDataMode = UART_DATA_TEXT;//UART_DATA_BINARY;
        uartParams.dataLength = UART_LEN_8;
        uartParams.stopBits = UART_STOP_ONE;
        uartParams.readReturnMode = UART_RETURN_NEWLINE;//UART_RETURN_FULL;
    
    
        uart = UART_open(Board_UART0, &uartParams);
    
        if (uart == NULL) {
            /* UART_open() failed */
            while (1);
        }
    
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
        
        rxFlag = 1;
        UART_read(uart, rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));
    
        /* Loop forever echoing */
        while (1) {
           if(rxFlag==0 && txFlag ==0)
           {
             UART_read(uart, rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));
           }
        }
    }




  • Hi Luu Vy,

        I tried your code modifications, the uart echo works, but not smoothly. It will echo the first character then you need to press a key many times to echo another character. After that it works properly. 

        Anyway, I modified the simple_peripheral and implemented UART Echo. This is based from svendbt code. I change the Semaphore to Event. The simple_peripheral UART Echo works smoothly. Here are my modifications. I am not sure if calling Uart_read() in the for loop of the Task is the best way.

    Filename: simple_peripheral.c

    #include <ti/drivers/UART.h>
    #include "simple_peripheral.h"
    
    UART_Handle huart;
    
    BUFTYPE rxBuf[BUFSIZE];
    BUFTYPE txBuf[BUFSIZE];
    
    const char  echoPrompt[] = "Echoing characters:\r\n";
    
    static void uartRxCb(UART_Handle handle, void *buf, size_t count) {
      //Copy rxBuf to txBuf
      memset(txBuf, 0, BUFSIZE);
      memcpy(txBuf, rxBuf, count);
      //Wake task to echo
      Event_post(syncEvent, SBP_UART_EVT);
    }
    
    static void SimpleBLEPeripheral_init(void)
    {
    . . .
      UART_init();
    
      //UART Init
      UART_Params uartParams;
      /* Create a UART with data processing off. */
      UART_Params_init(&uartParams);
    
      uartParams.readMode = UART_MODE_CALLBACK;
      uartParams.writeMode = UART_MODE_BLOCKING;
      uartParams.readCallback = uartRxCb;
      //uartParams.writeCallback = uartTxCb;
      uartParams.baudRate = 115200;
    
      uartParams.readDataMode = UART_DATA_BINARY;
      uartParams.writeDataMode = UART_DATA_BINARY;
      uartParams.dataLength = UART_LEN_8;
      uartParams.stopBits = UART_STOP_ONE;
      uartParams.readReturnMode = UART_RETURN_FULL;
    
      huart = UART_open(Board_UART0, &uartParams);
    
      if (huart == NULL) {
          /* UART_open() failed */
          while (1);
      }
    
      UART_write(huart, echoPrompt, sizeof(echoPrompt));
    }
    
    static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1)
    {
      // Initialize application
      SimpleBLEPeripheral_init();
    
      // Application main loop
      for (;;)
      {
        uint32_t events;
    
        // Waits for an event to be posted associated with the calling thread.
        // Note that an event associated with a thread is posted when a
        // message is queued to the message receive queue of the thread
        events = Event_pend(syncEvent, Event_Id_NONE, SBP_ALL_EVENTS,
                            ICALL_TIMEOUT_FOREVER);
    
        UART_read(huart, &rxBuf, sizeof(rxBuf)/sizeof(BUFTYPE));
    
        if (events)
        {
          . . . .
          if (events & SBP_UART_EVT)
          {
            UART_write(huart, txBuf, sizeof(txBuf)/sizeof(BUFTYPE));
          }
        }
      }
    }

    Filename: simple_peripheral.h

    // Internal Events for RTOS application
    #define SBP_ICALL_EVT                         ICALL_MSG_EVENT_ID // Event_Id_31
    #define SBP_QUEUE_EVT                         UTIL_QUEUE_EVENT_ID // Event_Id_30
    #define SBP_STATE_CHANGE_EVT                  Event_Id_00
    #define SBP_CHAR_CHANGE_EVT                   Event_Id_01
    #define SK_KEY_CHANGE_EVT                     Event_Id_02
    #define SBP_UART_EVT                          Event_Id_03
    #define SBP_PERIODIC_EVT                      Event_Id_04
    
    #ifdef FEATURE_OAD
    #define SBP_QUEUE_PING_EVT                    Event_Id_01
    
    #define SBP_ALL_EVENTS                        (SBP_ICALL_EVT        | \
                                                   SBP_QUEUE_EVT        | \
                                                   SBP_PERIODIC_EVT     | \
                                                   SBP_QUEUE_PING_EVT)
    #else
    #define SBP_ALL_EVENTS                        (SBP_ICALL_EVT        | \
                                                   SBP_QUEUE_EVT        | \
                                                   SBP_STATE_CHANGE_EVT | \
                                                   SBP_CHAR_CHANGE_EVT  | \
                                                   SK_KEY_CHANGE_EVT    | \
                                                   SBP_UART_EVT         | \
                                                   SBP_PERIODIC_EVT)
    #endif /* FEATURE_OAD */

    - kel