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.

LP-AM243: UART RX Interrupts

Part Number: LP-AM243
Other Parts Discussed in Thread: SYSCONFIG

The echo low latency transfer example shares a way to pause your code and listen for messages on the UART buffer, and echo them back as the user types.

The echo callback code example shares a way to pause the entire code and wait for an expected message to return.

What recommendations do you have for a practical system that expects an RX messages to be received at any given time, while operating other processes. I tried adapting the callback example by removing the Semaphore pauses but it does not seem to ever trigger the read callback. I also tried to adapt the low latency transfer example but it has the issue of pausing the code to wait for a character, rather than doing something to the character when it is received in the interrupt.

On other microcontrollers I have implemented what I want here by having an ISR trigger on the UART, and in that function it simply reads the char received and does logic based on that but I still often get confused by how FreeRTOS is used here in combination with CCS's sysconfig structures. Any recommendations on settings / approach? I essentially just want an ISR to tell me what char it received without hindering the code.

  • Hi Dylan,

    What you tried to to do can be easily implemented using the uart_echo_callback_am243x-evm_r5fss0-0_freertos_ti-arm-clang:

    1. Change the

    #define MAIN_TASK_PRI  (configMAX_PRIORITIES-1) to #define MAIN_TASK_PRI  (configMAX_PRIORITIES-2)

    2. Add

    #define OTHER_TASK_PRI  (configMAX_PRIORITIES-1)

    3. Define the following:

    void other_main(void *args)
    {
        while (1)

        {

              /* do other processing here */

        }

        vTaskDelete(NULL);
    }

    OTHER_TASK_SIZE, 

    gOtherTaskStack and 

    gOtherTaskObj 

    4. Add the following in main():

    gMainTask = xTaskCreateStatic( other_main, /* Pointer to the function that implements the task. */
                                                        "other_main", /* Text name for the task. This is to facilitate debugging only. */
                                                        OTHER_TASK_SIZE, /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
                                                        NULL, /* We are not using the task parameter. */
                                                        OTHER_TASK_PRI, /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
                                                        gOtherTaskStack, /* pointer to stack base */
                                                        &gOtherTaskObj ); /* pointer to statically allocated task object memory */
    configASSERT(gOtherTask != NULL);

    5, Change APP_UART_RECEIVE_BUFSIZE from 8 to 1

    6. Change the uart_echo_read_callback() to handle your message logic.

    Keep in mind that uart_echo_read_callback will get called every time when there is a UART input. You will NOT call SemaphoreP_post(&gUartReadDoneSem) until your message logic is satisfied. You may need to have a global UART input buffer to save all the characters you received so far to implement your message logic. Meanwhile the other task - other_main() will continue to process the other stuffs in parallel. You can also change the freertos_main task to infinite loop as needed.

    Best regards,

    Ming

  • Thank you for the quick reply. I have done these steps while also creating a variable for gOtherTask and I replaced gMainTask in step 4 with gOtherTask. What happens is only the other task is played. I added debug print lines in each task.

    Here, "Other Task Started" is sent to console but not Task Started.

    main:

    #include <stdlib.h>
    #include <kernel/dpl/DebugP.h>
    #include "ti_drivers_config.h"
    #include "ti_board_config.h"
    #include "FreeRTOS.h"
    #include "task.h"
    
    #define MAIN_TASK_PRI  (configMAX_PRIORITIES-2)
    #define OTHER_TASK_PRI  (configMAX_PRIORITIES-1)
    
    #define MAIN_TASK_SIZE (16384U/sizeof(configSTACK_DEPTH_TYPE))
    StackType_t gMainTaskStack[MAIN_TASK_SIZE] __attribute__((aligned(32)));
    StaticTask_t gMainTaskObj;
    TaskHandle_t gMainTask;
    
    #define OTHER_TASK_SIZE (16384U/sizeof(configSTACK_DEPTH_TYPE))
    StackType_t gOtherTaskStack[OTHER_TASK_SIZE] __attribute__((aligned(32)));
    StaticTask_t gOtherTaskObj;
    TaskHandle_t gOtherTask;
    
    void uart_echo_callback(void *args);
    
    void freertos_main(void *args)
    {
        DebugP_log("Main Task started\r\n");
        uart_echo_callback(NULL);
    
        vTaskDelete(NULL);
    }
    
    void other_main(void *args)
    {
        DebugP_log("Other Task started\r\n");
        int k = 0;
        while (1) {
            k++;
            // Print a statement ~1 per second or so
            if((k%10000000) == 0) {
                DebugP_log("tick\r\n");
            }
        }
    
        vTaskDelete(NULL);
    }
    
    int main()
    {
        /* init SOC specific modules */
        System_init();
        Board_init();
    
        /* This task is created at highest priority, it should create more tasks and then delete itself */
        gMainTask = xTaskCreateStatic( freertos_main,   /* Pointer to the function that implements the task. */
                                      "freertos_main", /* Text name for the task.  This is to facilitate debugging only. */
                                      MAIN_TASK_SIZE,  /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
                                      NULL,            /* We are not using the task parameter. */
                                      MAIN_TASK_PRI,   /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
                                      gMainTaskStack,  /* pointer to stack base */
                                      &gMainTaskObj ); /* pointer to statically allocated task object memory */
        configASSERT(gMainTask != NULL);
    
        gOtherTask = xTaskCreateStatic( other_main, /* Pointer to the function that implements the task. */
                                        "other_main", /* Text name for the task. This is to facilitate debugging only. */
                                        OTHER_TASK_SIZE, /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
                                        NULL, /* We are not using the task parameter. */
                                        OTHER_TASK_PRI, /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
                                        gOtherTaskStack, /* pointer to stack base */
                                        &gOtherTaskObj ); /* pointer to statically allocated task object memory */
        configASSERT(gOtherTask != NULL);
    
        /* Start the scheduler to start the tasks executing. */
        vTaskStartScheduler();
    
        DebugP_assertNoLog(0);
    
        return 0;
    }
    

  • Hi Dylan,

    Since the other_main has higher priority and it is in the while loop without sleep, so the freertos_main will never get chance to run. Please add ClockP_sleep(10) in the while loop of other_main, so that the  freertos_main get chance to run.

    Best regards,

    Ming

  • While that does make it operate properly while the other task is on sleep, it does not trigger the interrupt while the other task is being ran.

    For example, if I add the sleep command to the start of OtherTask, I can input my characters before the sleep finishes and it is recognized.

    If I wait until after the sleep finishes and the program starts ticking, it will not read my characters unless I sleep again during the loop. This isn't exactly an interrupt to the code, or the other task and could result in messages not being received if the "other task" is not paused via sleep at the perfect time.

    I am trying to accomplish a fairly common program design when coding things like the MSP430s in assembly or C, where an interrupt on the UART is detected and the function for the interrupt is ran, and other things can happen while waiting for the interrupt. The examples all rely on pausing the code to wait for an interrupt, and don't seem to find interrupts at other points maybe due to the usage of semaphore waiting.

  • Hi Dylan,

    The uart_echo_read_callback() is actually get called by the UART ISR when the UART_read(gUartHandle[CONFIG_UART_CONSOLE], &trans) is fulfilled. Since you set have set the trans.count to 1, so you should receive uart_echo_read_callback() every time there is a UART input, unless the UART_read() is not called after the uart_echo_read_callback().

    Have you add the ClockP_sleep(10) in the while loop of the other_main? Can you share the modified code?

    Best regards,

    Ming

  • Sure here is the modified code.

    My problem is if I have to add ClockP_sleep(10) into the while loop that means that if I had code in the loop I must sleep / pause my code processes in order for it to read any characters, which is what I am trying to avoid.

    main:

    /*
     *  Copyright (C) 2018-2021 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdlib.h>
    #include <kernel/dpl/DebugP.h>
    #include "ti_drivers_config.h"
    #include "ti_board_config.h"
    #include "FreeRTOS.h"
    #include "task.h"
    
    #define MAIN_TASK_PRI  (configMAX_PRIORITIES-2)
    #define OTHER_TASK_PRI  (configMAX_PRIORITIES-1)
    
    #define MAIN_TASK_SIZE (16384U/sizeof(configSTACK_DEPTH_TYPE))
    StackType_t gMainTaskStack[MAIN_TASK_SIZE] __attribute__((aligned(32)));
    StaticTask_t gMainTaskObj;
    TaskHandle_t gMainTask;
    
    #define OTHER_TASK_SIZE (16384U/sizeof(configSTACK_DEPTH_TYPE))
    StackType_t gOtherTaskStack[OTHER_TASK_SIZE] __attribute__((aligned(32)));
    StaticTask_t gOtherTaskObj;
    TaskHandle_t gOtherTask;
    
    void uart_echo_callback(void *args);
    
    void freertos_main(void *args)
    {
        DebugP_log("Main Task started\r\n");
        uart_echo_callback(NULL);
    
        vTaskDelete(NULL);
    }
    
    void other_main(void *args)
    {
        ClockP_sleep(10);
        DebugP_log("Other Task started\r\n");
        int k = 0;
        while (1) {
            k++;
            if((k%10000000) == 0) {
                DebugP_log("tick\r\n");
            }
        }
    
        vTaskDelete(NULL);
    }
    
    int main()
    {
        /* init SOC specific modules */
        System_init();
        Board_init();
    
        /* This task is created at highest priority, it should create more tasks and then delete itself */
        gMainTask = xTaskCreateStatic( freertos_main,   /* Pointer to the function that implements the task. */
                                      "freertos_main", /* Text name for the task.  This is to facilitate debugging only. */
                                      MAIN_TASK_SIZE,  /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
                                      NULL,            /* We are not using the task parameter. */
                                      MAIN_TASK_PRI,   /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
                                      gMainTaskStack,  /* pointer to stack base */
                                      &gMainTaskObj ); /* pointer to statically allocated task object memory */
        configASSERT(gMainTask != NULL);
    
        gOtherTask = xTaskCreateStatic( other_main, /* Pointer to the function that implements the task. */
                                        "other_main", /* Text name for the task. This is to facilitate debugging only. */
                                        OTHER_TASK_SIZE, /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
                                        NULL, /* We are not using the task parameter. */
                                        OTHER_TASK_PRI, /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
                                        gOtherTaskStack, /* pointer to stack base */
                                        &gOtherTaskObj ); /* pointer to statically allocated task object memory */
        configASSERT(gOtherTask != NULL);
    
        /* Start the scheduler to start the tasks executing. */
        vTaskStartScheduler();
    
        /* The following line should never be reached because vTaskStartScheduler()
        will only return if there was not enough FreeRTOS heap memory available to
        create the Idle and (if configured) Timer tasks.  Heap management, and
        techniques for trapping heap exhaustion, are described in the book text. */
        DebugP_assertNoLog(0);
    
        return 0;
    }
    

    uart_echo_callback: (not modified that much mainly it just prints a debug message when it reads something (anything).

    If the other code is not told to sleep, it will not trigger the callback function at all.

    #include <string.h>
    #include <kernel/dpl/DebugP.h>
    #include "ti_drivers_config.h"
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    
    #define APP_UART_BUFSIZE              (200U)
    #define APP_UART_RECEIVE_BUFSIZE      (1U)
    
    uint8_t gUartBuffer[APP_UART_BUFSIZE];
    uint8_t gUartReceiveBuffer[APP_UART_RECEIVE_BUFSIZE];
    volatile uint32_t gNumBytesRead = 0U, gNumBytesWritten = 0U;
    
    uint8_t gUartChars[8U];
    
    /* Semaphore to indicate Write/Read completion used in callback api's */
    static SemaphoreP_Object gUartWriteDoneSem;
    static SemaphoreP_Object gUartReadDoneSem;
    
    #define APP_UART_ASSERT_ON_FAILURE(transferOK, transaction) \
        do { \
            if((SystemP_SUCCESS != (transferOK)) || (UART_TRANSFER_STATUS_SUCCESS != transaction.status)) \
            { \
                DebugP_assert(FALSE); /* UART TX/RX failed!! */ \
            } \
        } while(0) \
    
    void uart_echo_callback(void *args)
    {
        int32_t          transferOK, status;
        UART_Transaction trans;
    
        Drivers_open();
        Board_driversOpen();
    
        DebugP_log("[UART] Echo callback example started ...\r\n");
    
        status = SemaphoreP_constructBinary(&gUartWriteDoneSem, 0);
        DebugP_assert(SystemP_SUCCESS == status);
    
        status = SemaphoreP_constructBinary(&gUartReadDoneSem, 0);
        DebugP_assert(SystemP_SUCCESS == status);
    
        UART_Transaction_init(&trans);
    
        /* Send entry string */
        gNumBytesWritten = 0U;
        trans.buf   = &gUartBuffer[0U];
        strncpy(trans.buf,"This is uart echo test callback mode\r\nReceives 8 characters then echo's back. Please input..\r\n", APP_UART_BUFSIZE);
        trans.count = strlen(trans.buf);
        transferOK = UART_write(gUartHandle[CONFIG_UART_CONSOLE], &trans);
        APP_UART_ASSERT_ON_FAILURE(transferOK, trans);
    
        /* Wait for write completion */
        SemaphoreP_pend(&gUartWriteDoneSem, SystemP_WAIT_FOREVER);
        DebugP_assert(gNumBytesWritten == strlen(trans.buf));
    
        /* Read 8 chars */
        gNumBytesRead = 0U;
        trans.buf   = &gUartReceiveBuffer[0U];
        trans.count = APP_UART_RECEIVE_BUFSIZE;
        transferOK = UART_read(gUartHandle[CONFIG_UART_CONSOLE], &trans);
        APP_UART_ASSERT_ON_FAILURE(transferOK, trans);
    
        /* Wait for read completion */
        SemaphoreP_pend(&gUartReadDoneSem, SystemP_WAIT_FOREVER);
        DebugP_assert(gNumBytesRead == APP_UART_RECEIVE_BUFSIZE);
    
        /* Echo chars entered */
        gNumBytesWritten = 0U;
        trans.buf   = &gUartReceiveBuffer[0U];
        trans.count = APP_UART_RECEIVE_BUFSIZE;
        transferOK = UART_write(gUartHandle[CONFIG_UART_CONSOLE], &trans);
        APP_UART_ASSERT_ON_FAILURE(transferOK, trans);
    
        /* Wait for write completion */
        SemaphoreP_pend(&gUartWriteDoneSem, SystemP_WAIT_FOREVER);
        DebugP_assert(gNumBytesWritten == APP_UART_RECEIVE_BUFSIZE);
    
        /* Send exit string */
        gNumBytesWritten = 0U;
        trans.buf   = &gUartBuffer[0U];
        strncpy(trans.buf, "\r\nAll tests have passed!!\r\n", APP_UART_BUFSIZE);
        trans.count = strlen(trans.buf);
        transferOK = UART_write(gUartHandle[CONFIG_UART_CONSOLE], &trans);
        APP_UART_ASSERT_ON_FAILURE(transferOK, trans);
    
        /* Wait for write completion */
        SemaphoreP_pend(&gUartWriteDoneSem, SystemP_WAIT_FOREVER);
        DebugP_assert(gNumBytesWritten == strlen(trans.buf));
    
        SemaphoreP_destruct(&gUartWriteDoneSem);
        SemaphoreP_destruct(&gUartReadDoneSem);
    
        DebugP_log("All tests have passed!!\r\n");
    
        Board_driversClose();
        Drivers_close();
    
        return;
    }
    
    void uart_echo_write_callback(UART_Handle handle, UART_Transaction *trans)
    {
        DebugP_assertNoLog(UART_TRANSFER_STATUS_SUCCESS == trans->status);
        gNumBytesWritten = trans->count;
        SemaphoreP_post(&gUartWriteDoneSem);
    
        return;
    }
    
    int reads = 0;
    void uart_echo_read_callback(UART_Handle handle, UART_Transaction *trans)
    {
        DebugP_assertNoLog(UART_TRANSFER_STATUS_SUCCESS == trans->status);
        gNumBytesRead = trans->count;
        DebugP_log("READ");
        gUartChars[reads] = &gUartBuffer[0U];
        reads++;
    
        SemaphoreP_post(&gUartReadDoneSem);
    
    
        return;
    }
    

  • Hi Dylan,

    OK, in that case,  you can make the following changes to get your both task going:

    #define MAIN_TASK_PRI (configMAX_PRIORITIES-1)
    #define OTHER_TASK_PRI (configMAX_PRIORITIES-2)

    Best regards,

    Ming

  • Thanks! that makes sense.

    In case you or anyone else is interested in my solution, I set the UART as the main priority and I actually still use the Semaphore for each char. I just loop the red request and wait.

    Inside of echo_callback at the read statement I just put:

    uint8_t GPSMessage[64U];
    int gpsIndex = 0;
    while(1) {
            /* Read 8 chars */
            gNumBytesRead = 0U;
            trans.buf   = &gUartReceiveBuffer[0U];
            trans.count = APP_UART_RECEIVE_BUFSIZE;
            transferOK = UART_read(gUartHandle[CONFIG_UART_CONSOLE], &trans);
            //APP_UART_ASSERT_ON_FAILURE(transferOK, trans);
    
            /* Wait for read completion */
            SemaphoreP_pend(&gUartReadDoneSem, SystemP_WAIT_FOREVER);
            //DebugP_assert(gNumBytesRead == APP_UART_RECEIVE_BUFSIZE);
    
            char c = gUartReceiveBuffer[0U];
            if(c == '$') {
                gpsIndex = 0;
                DebugP_log(&GPSMessage);
                DebugP_log("\r\n");
    
                for(int i = 0; i < 64; i++) {
                    GPSMessage[i] = 0;
                }
            } else {
                GPSMessage[gpsIndex++] = c;
            }
        }

    Here it read the GPS while doing some "tick" which represents the other task running. Obviously it will not be able to do much on the other task since the baud rate is 9600 so sending the debug messages takes a long time but in normal operation you dont print such things.