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.

CC1310: UART interrupt using Callback Api's

Part Number: CC1310
Other Parts Discussed in Thread: SIMPLELINK-CC13X0-SDK, SYSBIOS

Hello.

I've been using CC1310 launcpad and learning the basics peripherals.

I've downloaded the sdk from 

I'm using this code for my UART test.

UART_Handle uart;
UART_Params uartParams;          // Globals

uint8_t dummy_buf [5];

static void fnreadCallback(UART_Handle handle, void *rxBuf, size_t size)
{
  dummy_buf [0] = ((uint8_t*)rxBuf)[0];
}

int main (void)
{
Board_initGeneral();
No_RTOS_start();

UART_init();   /*start the uart driver */

UART_Params_init(&uartParams);

uartParams.readMode = UART_MODE_CALLBACK;
uartParams.writeMode = UART_MODE_BLOCKING;
uartParams.writeTimeout = UART_WAIT_FOREVER;

uartParams.readCallback = fnreadCallback;
uartParams.writeCallback = NULL;

uartParams.writeDataMode = UART_DATA_BINARY;
uartParams.readDataMode = UART_DATA_BINARY;
uartParams.readReturnMode = UART_RETURN_FULL;
uartParams.readEcho = UART_ECHO_OFF;
uartParams.baudRate = 115200;

uart = UART_open(Board_UART0, &uartParams);

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


while(1)
{
  UART_read(uart, rxBuf, 1);

}
}

With the above code i can get one one byte data into the dummy_buf. This was verified when i printed the contents of the dummy_buf.

Now the callback is working fine if i have the Uart_read() continuously in the while loop. Can i convert this code to work with Uart interrupt? What should i initialize in order to use UART interrupt? 

Regards,

Nishit.

  • Hi Nishit,

    You are already using the UART interrupt (callback mode), so I'm not sure what you mean. You could instead call read(...) from the callback function, and just have an initial read call outside your while loop.

    dev.ti.com/.../

    See the UART driver documentation in the above link, there are two header files you can look at there, it has some examples.

    Best regards,
    Aslak
  • Hello Aslak.

    So you mean the callback mode is the interrupt mode and the callback function which i have written is the Interrupt service routine ??
    And you mentioned to call read from the callback routine, does that not invoke the callback function recursively? And why do i need to do a initial one time call of Uart_read() in the main loop? Can you tell me the how the flow and what causes these functions to invoke?

    Anyways i'll try the steps that you suggested. But i'm curious to know the above 2 questions.

    Regards,
    Nishit.
  • Hi Nishit,

    Yes that's exactly it. The callback is executed in, I suppose, Swi context. Which is to say _not_ in your task context.

    Yes, you're right, if there is already data in the ring-buffer (a background buffer in the UART driver) then the read call will be recursive. So it won't be useful in your case where you always read 1. Well, useful maybe but you'd likely overflow the call stack. My apologies, this changed at some point and I didn't pay attention.

    On the other hand, if you are expecting first 1 then 2 and those 2 are the length, and then read "len", you probably won't have such a deep recursion, and it can be useful to read these out quickly.

    You need the initial call in order for the UART to enable RX and the driver to start reading in bytes. From the on you could handle everything from outside the task context, for example set up a Swi, then call Swi_post in the uart callback, and let that Swi do a new read.

    Another aspect is that when you are using callback mode, it doesn't make a lot of sense to call read again and again because since it isn't blocking (but callback), it will be called maaaaany times very quickly and usually return UART_ERROR because a read is in progress already.

    Best regards,
    Aslak
  • Hello Aslak.

    Thanks for the guidance. I modified my Uart_Interrupt project as follows after your suggestion.

    UART_Handle uart;
    UART_Params uartParams;          // Globals
    
    uint8_t txBuff[20],txvar;
    uint8_t dummy_Buf[2];
    bool RxDone_Flag = false;
    
    static void fnreadCallback(UART_Handle handle, void *rxBuf, size_t size)
    {
      txBuff [txvar++] = ((uint8_t*)rxBuf)[0];
      UAR_read(handle,rxBuf,1);
      RxDone_Flag = true;
    }
    
    int main (void)
    {
    Board_initGeneral();
    No_RTOS_start();
    
    UART_init();   /*start the uart driver */
    
    UART_Params_init(&uartParams);
    
    uartParams.readMode = UART_MODE_CALLBACK;
    uartParams.writeMode = UART_MODE_BLOCKING;
    uartParams.writeTimeout = UART_WAIT_FOREVER;
    
    uartParams.readCallback = fnreadCallback;
    uartParams.writeCallback = NULL;
    
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.readDataMode = UART_DATA_BINARY;
    uartParams.readReturnMode = UART_RETURN_FULL;
    uartParams.readEcho = UART_ECHO_OFF;
    uartParams.baudRate = 115200;
    
    uart = UART_open(Board_UART0, &uartParams);
    
    if (uart == NULL) {
        // UART_open() failed
        while (1);
    }
    
    Uart_read(uart,dummy_Buf,1); /* To enable Rx */
    while(1)
    {
      if (true == RxDone_Flag)
      {
         RxDone_Flag = false;
         for (uint8_t dummy_cnt = 0; dummy_cnt < 20; dummy_cnt++)
         {
           UART_write(uart,(txBuff+dummy_cnt),1);
           UART_write(uart," ",1);
         }
      }
      
    }
    }

    Now if I send some data via a terminal software from PC, the RxDone_Flag gets sets and the buffer gets printed as intended. But as per your above post it mentioned you mentioned that there will be problems while reading single single bytes whenever UART_read() is called in the callback. So what should i modify in order to have my ISR detect data of size 1 byte?

    Please elaborate on what would happen if i don't change the size of the data which is 1 in my case?

    Regards,

    Nishit.

  • Hi Nishit,

    The problem of reading just 1 byte directly in the callback is that there will normally be at least 1 byte in the input buffer, and so you will get recursion and overflow the stack and crash. Perhaps not if you write with a terminal program to the device, but in normal circumstances where you send a string of bytes at a time this will be the case.

    If you want to always read 1 byte you can instead do a new read in the application thread when data is received. Alternatively as mentioned you can post a Swi from the uart callback, and in that swi issue a new read. See the Swi example program for details on this: dev.ti.com/.../ an potentially also the Swi documentation: dev.ti.com/.../ under ti/sysbios/knl/Swi.

    Best regards,
    Aslak
  • Hello Aslak.
    This has gotten me confused now. I want to send string of data to the UART and want to do this storage via Interrupt.
    I'll have a look into the SWI which you are talking about as i have no idea what swi.c does.
    So basically, the above code will crash if i use it to store and process string of data?

    Also you mentioned that i'll have to do a new read in the application thread. What you mean by that? Are you referring to the UART_read() which i invoked into the Callback function?


    Regards,
    Nishit.

  • Hi Nishit,

    1 - When you call read in the callback, and the UART driver has already received some bytes, the call will recurse.
    2 - This is unfortunate if it's done too much, because each function call uses stack space.
    3 - When you send a string, but only read 1 byte at a time, there is almost guaranteed to be a backlog of bytes, and we go to point 1 here.

    Your alternatives are as follows,
    a) Continue reading 1 byte at a time, but do not call this read from the callback. See the points above.
    b) Continue reading 1 byte at a time, but initiate the next read from a Swi (software interrupt) or from the main thread.

    c) Read 1 byte, say that this byte is the length of the following data, then call read(len) in the callback [this is still somewhat unsafe]
    d) As above but initiate following read in a Swi or in main thread

    e) Set up a read for, say 1024 bytes, but enable RETURN_PARTIAL. You may have seen this mentioned in the link I provided in my original post about the UART driver: dev.ti.com/.../_u_a_r_t_c_c26_x_x_8h.html and call read(1024) again in the callback.

    Best regards,
    Aslak
  • Hello Aslak.

    So i did tested the following codes after your suggestions.

    For alternative no. 1 : If i remove the UART_read() from the Callback then it enters the Callback only for one character and the flag gets set only once. After that any number of bytes sent, they are not printed in the while loop which has a condition which gets satisfied if the flag is set.

    Alternative no 2 : I'm yet to understand SWI. It is very complicated and it's somewhat difficult for me to decipher that file. So i'll explore that file after i finish these tests as it may take some time.

    Alternative no. 5 : In the Uartinit after UART_open () i added the following lines.

    UART_control(uart, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL);




    Above the while loop:

    Uart_read(uart,dummy_Buf,1024); /* To enable Rx */




    Inside the callback :

    UART_read(handle,rxBuf,1024); /* To enable Rx */



    Here if i send single byte data then it works fine but when i send array of characters the flag gets set and the tx_Buf prints Null characters and one or two bytes from the array of characters ie Partial data.

    Am i doing anything wrong in the Partial_return mode configuration?
    Also you said that the stack will get overloaded and the system will crash due to overflow.
    So will the controller not release stack as soon as the internal ring buffer is processed?

    Thanks,
    Nishit.

  • Hi,

    You need to check how many bytes you received with the return partial. It won't necessarily fill up the buffer for you, because it returns as soon as there has been a pause in the transmitting.

    Yes it will at some point stop using the stack, but let's say you send 1024 bytes - it will then recurse 1024 times, which is not ideal.

    Aslak
  • Hello Aslak.

    I'm still not getting the results from Partial_read method. However the method of calling Uart_read in the callback is working perfectly for me and i do not intend to send large block of bytes in my application, so i don't think that the problem of stack overflow occur.
    I was reading about Swi from the link you provided and other community posts and came to know that the ti drivers uses swi and returns the result of that as the callback. Is that right?

    Still i'm not getting any examples which can explain implementation of Swi for nortos application.
    Documentation at ti resource explorer explains swi in context of ti-rtos with no supportive examples for implementation in nortos. Can you give an insight to which documents i should refer to better understand swi and use it for nortos ?

    Also thanks for all the above alternatives and suggestions which you provided.

    Regards,
    Nishit.
  • Hello.

    Any updates?

    Regards,

    Nishit.

  • Hi Nishit,

    I had not realized you were using NoRTOS. There are things like SwiP.h and so on in the SDK, but they are not really meant for anything but drivers.

    In any case, I'm not entirely sure what you are trying to achieve, but I did give CC13x0 SDK 2.10 a whirl with no-rtos, and it seems there is no risk of recursive calls to the read callback, as the UART driver will return immediately in the read and set a Swi post, meaning the read callback is called by the swi dispatcher immediately after the read callback returns instead of recursing.

    The code snippet below replaces uartecho.c in the no-rtos uartecho example.

    /*
     * Copyright (c) 2015-2017, Texas Instruments Incorporated
     * All rights reserved.
     *
     * 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.
     */
    
    /*
     *  ======== uartecho.c ========
     */
    #include <stdint.h>
    #include <stddef.h>
    #include <stdio.h>
    #include <string.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"
    
    
    char inputBuf[128];
    char outputBuf[128 + 64];
    
    volatile int recursionLevel = 0;
    
    void uartReadCb (UART_Handle handle, void *buf, size_t count)
    {
        sprintf(outputBuf, "Got %d characters, recursion lvl: %d >> %s <<\r\n", (int)count, recursionLevel, (char *)buf);
        UART_write(handle, outputBuf, strlen(outputBuf));
    
        // Set inputBuf to all \0, so that sprintf above works with %s format for buf. // Read 1 byte less than max, to keep NULL terminator, since we printf the buffer directly
        memset(inputBuf, 0, sizeof(inputBuf));
    
        recursionLevel++;
        // Read 1 byte less than max, to keep NULL terminator, since we printf the buffer directly
        UART_read(handle, &inputBuf, sizeof(inputBuf) - 1);
        recursionLevel--;
    }
    
    void uartWriteCb (UART_Handle handle, void *buf, size_t count)
    {
        // Nothing
    }
    
    
    /*
     *  ======== 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();
    
        /* Configure the LED pin */
        GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        /* 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_BINARY;
        uartParams.readDataMode = UART_DATA_BINARY;
        uartParams.readReturnMode = UART_RETURN_FULL;
        uartParams.readEcho = UART_ECHO_OFF;
        uartParams.baudRate = 115200;
        uartParams.readCallback = uartReadCb;
        uartParams.readMode = UART_MODE_CALLBACK;
        uartParams.writeCallback = uartWriteCb;
        uartParams.writeMode = UART_MODE_CALLBACK;
    
        uart = UART_open(Board_UART0, &uartParams);
    
        UART_control(uart, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL);
    
        if (uart == NULL) {
            /* UART_open() failed */
            while (1);
        }
    
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
    
        // Read 1 byte less than max, to keep NULL terminator, since we printf the buffer directly
        UART_read(uart, &inputBuf, sizeof(inputBuf) - 1);
    
        /* Loop forever echoing */
        while (1) {
        }
    }
    

    Best regards,
    Aslak

  • Hello Aslak.
    No problem. Thanks. I'll try this example which you posted.

    Regards,
    Nishit.
  • Hi,

    I was a bit quick on the draw. It is possible to get recursion. Below is a slightly refined example. Note that here the read is for 1 byte each which is mostly to more easily provoke the error. Also return partial is disabled for similar reasons.

    /*
     * Copyright (c) 2015-2017, Texas Instruments Incorporated
     * All rights reserved.
     *
     * 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.
     */
    
    /*
     *  ======== uartecho.c ========
     */
    #include <stdint.h>
    #include <stddef.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/UART.h>
    #include <ti/drivers/UART/UARTCC26XX.h>
    #include <dpl/QueueP.h>
    
    /* Example/Board Header files */
    #include "Board.h"
    
    
    char inputBuf[2];
    char outputBuf[128 + 64];
    
    QueueP_Obj txQ;
    
    typedef struct {
        QueueP_Elem _elem;
        int len;
        char data[];
    } qNode;
    
    qNode *curNode = NULL;
    
    enum {STATE_NORMAL, STATE_FAILED_MALLOC} appState = STATE_NORMAL;
    
    volatile int recursionLevel = 0;
    
    void uartReadCb (UART_Handle handle, void *buf, size_t count)
    {
        // Create output string
        int strLength = sprintf(outputBuf, "Got %d characters, recursion lvl: %d >> %s <<\r\n", (int)count, recursionLevel, (char *)buf);
    
        // Allocate memory for output string in queue, as it may take
        // more time sending the string than receiving the next byte
        qNode *node = malloc(sizeof(qNode) + strLength);
        
        if (node == NULL)
        {
            // If failed, just return. At a later stage the state must
            // be set to normal, and UART_read must be called again
            appState = STATE_FAILED_MALLOC;
            return;
        }
    
        // Copy data to allocated memory
        memcpy(node->data, outputBuf, strLength);
        node->len = strLength;
    
        if (curNode == NULL)
        {
            // If no write ongoing call write here
            curNode = node;
            UART_write(handle, node->data, strLength);
        }
        else
        {
            // Write ongoing, queue the output string.
            QueueP_put(&txQ, &node->_elem);
        }
    
        // Set inputBuf to all \0, so that sprintf above works with %s format for buf. // Read 1 byte less than max, to keep NULL terminator, since we printf the buffer directly
        memset(inputBuf, 0, sizeof(inputBuf));
    
        recursionLevel++;
        // Read 1 byte less than max, to keep NULL terminator, since we printf the buffer directly
        UART_read(handle, &inputBuf, sizeof(inputBuf) - 1);
        recursionLevel--;
    }
    
    void uartWriteCb (UART_Handle handle, void *buf, size_t count)
    {
        // If there was an active txQ node, free it.
        if (curNode)
        {
            free(curNode);
            curNode = NULL;
        }
    
        // If there are queued writes, write now.
        // If no remaining writes, check if malloc failed, then clean up.
        if (!QueueP_empty(&txQ))
        {
            curNode = (qNode *)QueueP_get(&txQ);
            UART_write(handle, curNode->data, curNode->len);
        }
        else if (appState == STATE_FAILED_MALLOC)
        {
            UART_write(handle, "Failed malloc\r\n", 15);
            if (UART_ERROR == UART_read(handle, &inputBuf, sizeof(inputBuf) - 1))
                while(2);
            appState = STATE_NORMAL;
        }
    }
    
    
    /*
     *  ======== 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();
    
        QueueP_init(&txQ);
    
        /* Configure the LED pin */
        GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        /* 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_BINARY;
        uartParams.readDataMode = UART_DATA_BINARY;
        uartParams.readReturnMode = UART_RETURN_FULL;
        uartParams.readEcho = UART_ECHO_OFF;
        uartParams.baudRate = 115200;
        uartParams.readCallback = uartReadCb;
        uartParams.readMode = UART_MODE_CALLBACK;
        uartParams.writeCallback = uartWriteCb;
        uartParams.writeMode = UART_MODE_CALLBACK;
    
        uart = UART_open(Board_UART0, &uartParams);
    
    //    UART_control(uart, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL);
    
        if (uart == NULL) {
            /* UART_open() failed */
            while (1);
        }
    
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
    
        // Read 1 byte less than max, to keep NULL terminator, since we printf the buffer directly
        UART_read(uart, &inputBuf, sizeof(inputBuf) - 1);
    
        /* Loop forever echoing */
        while (1) {
        }
    }
    

  • Hi aslak!

    There is not a post on the internet that explains my problem better than this post...:)

    I have using uart driver on TI RTOS for quite a while now,i have never had any issues previously and everything had been working fine.

    It wasn't until I started calling uart read 1 byte at a time that my device started crashing.

    I was calling uart read function from within the uart read callback and as you have said earlier on this thread that the uart read recursion issue causes the stack to overflow,yes this is exactly what the issue is!

    i posted on the forum and the TI employee Prashant helped me out.Previously i was doing all my work in a single task.But Prashant guided me to make a separate task for uart with semaphore pend inside a while loop in that uart task and only post the semaphore in the uart read call back.i did the neccesary but the problem wont be solved.

    I am sending data from a terminal software on a PC and it is continuously sending data @38400bps baud rate.The issue only occurs when i start sending data from the terminal software and power on my board midway through the communication.If i turn on my board first and then start sending data,the issue never occurs.Also if i unplug the connector coming from pc from the board and reconnect it midway through the transmission,the software hangs and i have to restart the board.

    On power cycle or reset the problem may subside at times or may still cause the system to crash.The issue is definitely uart read call recursion.Why i don't get this issue when i first turn on my system and then start transmission is because the board would be ready before the first byte arrives and by the time 2nd byte arrives,the first byte would have already been read hence not causing the stack overflow.But when i plug,unplug wire or power cycle midway the transmission,chances are that the board powers up midway a byte is being received hence the 2nd byte is received before expected time causing the crash.

    Below is my snippet of code,i cannot read 2 bytes at a time or more.Consider it an application constrainst,unlike nishit on the forum i am using TI RTOS so you may refer to me a snippet of software interrupt example for me to resolve the issue.My application requirements may involve data cable being removed midway or the unit being power cycles any given time,hence i don't want this naggy little issue to downplay the over performance of my otherwise wonderful system.

    /*
     * Copyright (c) 2015-2016, Texas Instruments Incorporated
     * All rights reserved.
     *
     * 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.
     */
    
    /*
     *  ======== empty_min.c ========
     */
    /* XDCtools Header files */
    #include <stdlib.h>
    #include <xdc/std.h>
    #include <xdc/runtime/System.h>
    #include <xdc/runtime/Error.h>
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/drivers/UART.h>
    /* TI-RTOS Header files */
    #include <ti/drivers/PIN.h>
    
    /* Board Header files */
    #include "Board.h"
    
    /* EasyLink API Header files */
    #include "easylink/EasyLink.h"
    
    /* Undefine to not use async mode */
    #define RFEASYLINKTX_ASYNC
    
    #define RFEASYLINKTX_TASK_STACK_SIZE    1024
    #define RFEASYLINKTX_TASK_PRIORITY      2
    #define UARTRX_TASK_STACK_SIZE    1024
    #define UARTRX_TASK_PRIORITY      3
    
    
    Task_Struct txTask;    /* not static so you can see in ROV */
    static Task_Params txTaskParams;
    static Task_Params uartrxTaskParams;
    static uint8_t txTaskStack[RFEASYLINKTX_TASK_STACK_SIZE];
    static uint8_t uarrxTaskStack[UARTRX_TASK_STACK_SIZE];
    
    /* Pin driver handle */
    static PIN_Handle pinHandle;
    static PIN_State pinState;
    
    /*
     * Application LED pin configuration table:
     *   - All LEDs board LEDs are off.
     */
    PIN_Config pinTable[] = {
        Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        PIN_TERMINATE
    };
    uint8_t uart_pkt_received=0;
    static uint16_t seqNumber;
    static Semaphore_Handle txDoneSem;
    static Semaphore_Handle uartrxDoneSem;
    /*uart read call back function*/
    void uart_read_cb();
    void uart_read_cb()
    {
     Semaphore_post(uartrxDoneSem);
    }
    void txDoneCb(EasyLink_Status status)
    {
        if (status == EasyLink_Status_Success)
      {
        
     Semaphore_post(txDoneSem);
      
      }
    }
    
    static void rfEasyLinkTxFnx(UArg arg0, UArg arg1)
    {
        /* Create a semaphore for Async */
        Semaphore_Params params;
        Error_Block eb;
        /* Init params */
        Semaphore_Params_init(&params);
        Error_init(&eb);
        /* Create semaphore instance */
        txDoneSem = Semaphore_create(0, &params, &eb);
        EasyLink_init(EasyLink_Phy_Custom);
        EasyLink_setFrequency(868000000);
        EasyLink_TxPacket txPacket =  { {0}, 0, 0, {0} };
        txPacket.dstAddr[0] = 0xaa;
        /* Set output power to 14dBm */
        EasyLink_setRfPwr(14);
        /*uart related parameters*/
        UART_Handle uart;
        UART_Params uartParams;
        UART_Params_init(&uartParams);
        uartParams.writeDataMode = UART_DATA_BINARY;
        uartParams.readDataMode = UART_DATA_BINARY;
        uartParams.readReturnMode = UART_RETURN_FULL;
        uartParams.readMode=UART_MODE_CALLBACK; 
        uartParams.readcallback=(UART_CALLBACK)uart_read_cb(); 
        uartParams.readEcho = UART_ECHO_OFF;
        uartParams.baudRate = 38400;
        uart = UART_open(Board_UART0, &uartParams);
        UART_read(uart, &input,1);
     while(1) 
     { 
            if(uart_buffer_full==1)
     {
     uart_buffer_full=0;
     count=0;
            memcpy(txPacket.payload,uart_temp_buffer,16];
            txPacket.len =16;
            EasyLink_transmitAsync(&txPacket, txDoneCb);
     Semaphore_pend(txDoneSem,BIOS_WAIT_FOREVER);
         }
     }
    }
    
    static void uartrxfunction(UArg arg0, UArg arg1)
    {
        Semaphore_Params uart_rx_params;
        Error_Block uart_eb;
        /* Init params */
        Semaphore_Params_init(&uart_rx_params);
        Error_init(&uart_eb);
        /* Create semaphore instance */
        uartrxDoneSem = Semaphore_create(0, &uart_rx_params, &uart_eb);
        while(1)
     {
     semaphore_pend(uartrxDoneSem,BIOS_WAIT_FOREVER);
     uart_temp_buffer[count]=input[0];
     count++;
     if(count==16)
     {
     uart_buffer_full=1; 
     }
     UART_read(uart, &input,1);
     }
     
    }
    void txTask_init(PIN_Handle inPinHandle) 
    {
        pinHandle = inPinHandle;
        Task_Params_init(&txTaskParams);
        txTaskParams.stackSize = RFEASYLINKTX_TASK_STACK_SIZE;
        txTaskParams.priority = RFEASYLINKTX_TASK_PRIORITY;
        txTaskParams.stack = &txTaskStack;
        txTaskParams.arg0 = (UInt)1000000;
    
     Task_construct(&txTask, rfEasyLinkTxFnx,&txTaskParams, NULL);
    }
    void uartrxTask_init(PIN_Handle inPinHandle) 
    {
        pinHandle = inPinHandle;
        Task_Params_init(&uartrxTaskParams);
        uartrxTaskParams.stackSize = UARTRX_TASK_STACK_SIZE;
        uartrxTaskParams.priority = UARTRX_TASK_PRIORITY;
        uartrxTaskParams.stack = &uarrxTaskStack;
        uartrxTaskParams.arg0 = (UInt)1000000;
     Task_construct(&uartrxTask, uartrxfunction,&uartrxTaskParams,NULL);
    }
    /*
     *  ======== main ========
     */
    int main(void)
    {
        /* Call board init functions. */
        Board_initGeneral();
    
        /* Open LED pins */
        pinHandle = PIN_open(&pinState, pinTable);
        if(!pinHandle) {
            System_abort("Error initializing board LED pins\n");
        }
    
        /* Clear LED pins */
        PIN_setOutputValue(pinHandle, Board_LED1, 0);
        PIN_setOutputValue(pinHandle, Board_LED2, 0);
    
        txTask_init(pinHandle); 
        uartrxtask_init(pinHandle);
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }

    Your help is greatly appreciated

    i have not shared the complete code,i know the code looks like i could set the receive buffer threshold to 16 byte instead of 1 byte and the functionality remains the same but that is not the case,i have only shared what is relevant to the issue,rest of the code was irrelevant to the task at hand.

    Best regards

    Ali

  • Hi Ali,

    Let me first say that in the future I  would recommend that you click the "Ask a related question" button, because that creates a new thread. Old threads are not typically monitored, or if it is, then maybe by one person.

    Second, I would recommend that you insert code using the "rich text" editor on E2E and click the code snippet button. I edited your post to get some colors and formatting.

    Finally, if your problem is stack overflow, then you may "simply" do like the below, as explained in a link in one of my original answers (swi example)

    1. Construct a SWI
    2. Set a callback function for it
    3. Call uart_read in that callback function
    4. Post the Swi from the UART read callback

    Swi_Struct swi0Struct;
    Swi_Handle swi0Handle;
    
    /*
     *  ======== swi0Fxn =======
     */
    void swi0Fxn(uintptr_t arg0, uintptr_t arg1)
    {
        UART_Handle handle = (UART_Handle)arg0;
        
        UART_read(handle, ....);
    }
    
    
    /*
     *  ======== uartReadCallbackFxn =======
     */
    void uartReadCallbackFxn(UART_Handle handle, void *buf, size_t count)
    {
        // Copy out the received data or something
        // ...
        // Post to swi to read again without recursion
        Swi_post(swi0Handle);
        // Alternatively use Swi_or(swi0Handle, <number>) to send a value, then Swi_getTrigger() in the swi to get this value.
    }
    
    
    /*
     *  ======== main ========
     */
    int main()
    {
        // ....
    
        Swi_Params_init(&swiParams);
        swiParams.arg0 = (uintptr_t)uartHandle;
        swiParams.arg1 = 0;
        swiParams.priority = 2;
        swiParams.trigger = 0;
    
        Swi_construct(&swi0Struct, (Swi_FuncPtr)swi0Fxn, &swiParams, NULL);
        swi0Handle = Swi_handle(&swi0Struct);
    

    On the other hand, it looks like you are already deferring the read to another context via Semaphore, and so should not be getting recursion. Have you tried increasing the stack size for your Rx task? Alternatively also used the ROV plugin for CCS to look at the stack utilization since you're already at 1024 bytes there?

    I suppose one other question I have is that since you define the uart handle locally in the rfEasyLinkTxFnx function, how is this value usable by the uartrxfunction? Yet another question might be whether you try posting to the uartRxDoneSem before it's ever created and so you post to NULL.

    Best regards,
    Aslak

  • Hi aslak!
    thank you for your suggestions.I will definitely keep them in mind next time.
    Please help me understand what is actually happening when we use a software interrupt.
    Secondly i have declared uart handle globally so it was a mistake to write it in the rfEaslyLinkTxFnx function hence it is usable and i don't have to pass it as an argument either.
    Regarding the semaphore being posted even before it is posted,yes this is an issue,how do i overcome this??..i guess the right place to call uart_read is:
    uartrxDoneSem = Semaphore_create(0, &uart_rx_params, &uart_eb);
    here->uart_read(handle,..)
    while(1)
    {
    semaphore_pend(uartrxDoneSem,BIOS_WAIT_FOREVER);

    just after the semaphore is created and just before calling the semaphore_pend.am i right?
    Is this reason enough for the software to crash?
    please guide
    Best regards
    Ali
  • Hi,

    With regards to how Swi works, please refer to the documentation here, under DETAILS: dev.ti.com/.../index.html

    You can also read RTOS Concepts and TI-RTOS Basics in SimpleLink Academy:
    dev.ti.com/.../

    dev.ti.com/.../


    You should simply create/construct the semaphore and other shared objects before you start any tasks that depend on them, perhaps before you call BIOS_start() is the easiest place to do this.

    Yes, that's certainly enough to crash, but it's not necessarily what happens here. I can't see right now how you can get a stack overflow but you can check this with the ROV. For info on ROV see the TI-RTOS Basics lab.

    Best regards,
    Aslak
  • HI Aslak!

    I moved both semaphore creations before BIOS_START() and also moved uart read into my uart task just before semaphore pend(uarttxhandle) but i dont see any improvement,the software still crashes at will whenever i plug unplug the cable or turn on/off the board while the data is being received..

    I see a similar pattern in both cases,the board must receive a complete uart byte from the begining else the system mau crash..why is this happening???

    Will the software interrupt fix this issue?

    Best regard

    Ali

  • I dont have CCS,i have IAR embedded workbench hence i dont know about ROV
  • Hi Ali,

    No, Swi will have no impact here, I don't think. There is a ROV plugin in IAR also, but you must enable the TI-RTOS plugin in the project options.

    I'd suggest you make a new E2E thread about your issues, since they appear a bit unrelated to this. Explain there how you have determined that if you don't receive a complete byte it will crash, and also how it crashes.

    Best regards,
    Aslak