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.

RTOS/CC1310: Uart rx byte after byte

Part Number: CC1310

Tool/software: TI-RTOS

Hi

I want to implement uart protocol, with TI-RTOS work as following:

there is gpio that is configured is input interrupt.

Whet uart is closed, when there is an "activity" on this pin, the gpio is closed as gpio,

and reconfigured as uart pin, in callback mode.

In my protocol, the rx frame's length varies, so I don't know how many bytes

I am going to receive, which means I can't use uart_read with length parameter.

The only way I can use it, is by calling uart_read with length of 1

time after time, which make me work with uart as polling mode, and

I don't want to, and also harms performance.

In Addition, I can't call uart_read in uart rx callback.

  • Hi Naor,

    I would configure the GPIO pin as input and register an interrupt callback to it. Then inside this callback you can release the pin, open up the UART driver in callback mode and post the first UART_read().
    When you have received all the data, you can close the UART again and reconfigure the gpio interrupt callback.

    There is nothing that stops you from posting another UART_read from inside the read callback itself. You will have to post another UART_read in between callbacks in order to keep receiving data and it is safe to do this inside the RX callback (typically in the end). You can read about it in the driver documentation: dev.ti.com/.../_u_a_r_t_c_c26_x_x_8h.html

    If you want to receive an unknown amount of data over the UART you can set up bigger read chunks and specify a timeout to not get stuck in an infinite read if there is no more data.
  • Hi

    Is there any way, to configure uart to auto receive (by enabling uart interrupt) at startup,
    whenever there is interrupt on rx interrupt, without calling uart read?
  • Hi,

    Currently there is no support in the driver to configure it in an "auto receive" way that you request. The closest you will get to this is making an initial call to UART_read, then again in the end of the RX callback.

    The driver will continue (without further calls to UART_read) to receive data after the initial UART_read call, however to generate an callback, the UART_read has to be called again to read out of the internal buffer.

  • What If I put the line UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT |
    UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE);

    in uart_open function?
    could this help?
  • Enabling the interrupts yourself won't help, after calling the first UART_read you would be in the same state, with the RX interrupt enabled. This is to allow for the driver to buffer incoming data in the ring buffer between read calls.

    The reason it won't work without continuously calling UART_read between callbacks is because the driver require the user to define the amount of data to read in between callbacks. This is set inside UART_read and decremented as data is received until it reaches zero, at this point the callback will be invoked. Without resetting this read size in between callbacks, another callback won't be invoked even if data have been received.

    I recommend going with re-posting the UART_read inside the callback as this will make sure that the FIFO and ring buffer is handled in the right way.

  • Hi, please follow the attached pseudo code i wrote, which demonstrates simple uart protocol

    It does not work, the pinRxCallback is never read.

    thanks

    uartPseudo.c
    /*
    	This is a pseudo code demonstrate simple uart bi-directional protocol
    	some of the functions are not defined, but by name explins there job
    */
    
    
    
    
    // timeout definitions
    QUIET_TIMEOUT 
    KEEP_ALIVE_TIMEOUT 
    TX_RETRY_TIMEOUT 
    TX_MAX_RETRY_COUNT 
    
    //tx definitions
    TX_READY
    TX_BUSY
    
    
    //event definitions
    RX_ISSUE
    MESSAGE_RECEIVED
    TX_COMMAND
    TX_ENDED
    TIMEOUT_EXPIRED
    
    
    
    //whenever activity occures in rx pin, switch it to uart rx
    pinIoCallback()
    {
    	setRxAsUartPin();
    	EventPost(RX_ACTIVITY);
    }
    
    
    //called by application
    putCommandInQueue(cmd)
    {
    	QueuePut(cmd);
    	EventPost(TX_COMMAND)
    }
    
    
    uartTaskFcn(void)
    {
    	timeout = KEEP_ALIVE_TIMEOUT;
    	while(1)
    	{
    		event = EventPend(timeout);
    		wokenTimeout = timeout;
    		timeout = KEEP_ALIVE_TIMEOUT;
    		if(event == RX_ISSUE)
    		{
    			uartRead(1);
    			timeout = QUIET_TIMEOUT;
    		}
    		
    		if(event == MESSAGE_RECEIVED)
    		{
    			if( checkIfMessageIsAck(rxBuff) )
    			{
    				//if first message in queue is acknowledge by the received message,
    				//extract it from queue
    				QueueExtract(cmd);
    				//stop tx timer
    				TxTimerStop();
    			}
    			else
    			{
    				//upload recieved message to app
    				putRecievedMsgInApp(rxBuff);
    			}
    		
    			timeout = KEEP_ALIVE_TIMEOUT;
    		}
    		if(event == TX_COMMAND)
    		{
    			//command handle and send mechanism
    			handleCommandAndSend();
    			timeout = QUIET_TIMEOUT;
    		}
    		
    		if(event == TX_ENDED)
    		{
    			//command handle and send mechanism
    			txState = TX_READY;
    			timeout = QUIET_TIMEOUT;
    		}
    		
    		if(event == TIMEOUT_EXPIRED )
    		{
    			//if the timeout expired was keepalive, close uart (power consumption considerations)
    			if(wokenTimeout == KEEP_ALIVE_TIMEOUT )
    			{
    				closeUart();
    				setRxAsGpioPin();
    			}
    		}
    
    		
    	}
    	
    }
    
    
    handleCommandAndSend()
    {
    //check if tx is ready to sent
    	if(txState == TX_READY)
    	{
    
    		//take (not extract) first waiting message
    		QueuePeek(cmd);
    		
    		
    		
    		if(retryCnt < TX_MAX_RETRY_COUNT)
    		{
    			txState = TX_BUSY;
    			WriteCmdBytesInBuffer(cmd,txBuffer);
    			uartWrite(txBuffer);
    			//open timer, and wait for ack
    			TxTimerStart(TX_RETRY_TIMEOUT );
    		}
    		else
    		{
    			retryCnt =0;
    			//no more retries, throw message away
    			QueueExtract(cmd);
    		}
    		
    	}
    	
    }
    
    uartReadCallback(byte)
    {
    	//prasing message, according to application protocol
    	//if succed, notify task
    	if(PARSE_OK == parse(byte,rxBuffer) )
    	{
    		EventPost(MESSAGE_RECEIVED);
    	}
    	//initiate next read
    	uartRead(1);	
    }
    
    
    uartWriteCallback()
    {
    	EventPost(TX_ENDED);
    }

  • I'm not able to see any reason for your pinRxCallback not getting called, you would need to supply the actual code you are using to setup the pin (what is happening inside setRxAsGpioPin).

    Here is a small example of how you could implement the "receive on interrupt" functionality. You should be able to copy paste this code into the pinInterrupt example, replacing the code in pinInterrupt.c.

    /*
     * 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.
     */
    
    /*
     *  ======== pinInterrupt.c ========
     */
    #include <unistd.h>
    
    /* Driver Header files */
    #include <ti/drivers/Power.h>
    #include <ti/drivers/power/PowerCC26XX.h>
    #include <ti/drivers/PIN.h>
    #include <ti/drivers/UART.h>
    #include <ti/drivers/pin/PINCC26XX.h>
    
    /* Example/Board Header files */
    #include "Board.h"
    
    /* Pin driver handles */
    static PIN_Handle buttonPinHandle;
    
    /* Global memory storage for a PIN_Config table */
    static PIN_State buttonPinState;
    
    /*
     * Application button pin configuration table:
     *   - Buttons interrupts are configured to trigger on falling edge.
     */
    PIN_Config buttonPinTable[] = {
        CC1310_LAUNCHXL_UART_RX  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
        PIN_TERMINATE
    };
    
    uint8_t uartReadBuffer[10];
    volatile uint8_t goToStandby = 0;
    
    void startUART();
    
    /*
     *  ======== buttonCallbackFxn ========
     */
    void buttonCallbackFxn(PIN_Handle handle, PIN_Id pinId) {
    
        /* Release the RX pin */
        PIN_remove(handle, pinId);
    
        /* Start the UART for TX/RX operation */
        startUART();
    }
    
    /*
     *  ======== uartReadCallback ========
     */
    void uartReadCallback (UART_Handle handle, void *buf, size_t count)
    {
        uint8_t msg[] = "\n\n\rBye World";
        uint8_t msgSize = sizeof(msg);
    
        /* Print "Bye" message */
        UART_write(handle, msg, msgSize);
    
        /* Mark that we want to close the UART after the write completes */
        goToStandby = 1;
    }
    
    /*
     *  ======== uartWriteCallback ========
     */
    void uartWriteCallback (UART_Handle handle, void *buf, size_t count)
    {
        /* If we are to go into standby, close the UART and reconfigure the pin */
        if(goToStandby)
        {
            /* Go back to sleep */
            UART_close(handle);
    
            /* Reconfigure the PIN interrupt */
            /* Add RX pin back to the PIN driver */
            PIN_add(buttonPinHandle, buttonPinTable[0]);
    
            /* Register callback */
            PIN_registerIntCb(buttonPinHandle, buttonCallbackFxn);
    
            goToStandby = 0;
        }
    }
    
    /*
     *  ======== startUART ========
     */
    void startUART()
    {
        uint8_t msg[] = "\n\n\rHello World";
        uint8_t msgSize = sizeof(msg);
    
        UART_Handle handle;
        UART_Params uartParams;
    
        /* Call driver init functions */
        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_FULL;
        uartParams.readEcho = UART_ECHO_OFF;
        uartParams.baudRate = 115200;
        uartParams.readMode = UART_MODE_CALLBACK;
        uartParams.readCallback = uartReadCallback;
        uartParams.writeMode = UART_MODE_CALLBACK;
        uartParams.writeCallback = uartWriteCallback;
    
        handle = UART_open(Board_UART0, &uartParams);
    
        /* Print Hello message */
        UART_write(handle, msg, msgSize);
    
        /* Start a read */
        UART_read(handle, uartReadBuffer, 1);
    }
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
    
        buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
        if(!buttonPinHandle) {
            /* Error initializing button pins */
            while(1);
        }
    
        /* Setup callback for button pins */
        if (PIN_registerIntCb(buttonPinHandle, &buttonCallbackFxn) != 0) {
            /* Error registering button callback function */
            while(1);
        }
    
        /* Loop forever */
        while(1) {
            sleep(1000);
        }
    }
    

  • Hi
    As I have mentioned in my code, I want to implement a protocol, not
    echoing or led blink.

    1)I want my functionality to be event driven,
    any uart operation is done, in task context.
    The only thing the callbacks do, is to raise an event.

    2)as for my code example:
    A troubled scenario is when the uart is closed, and the application put command in queue.
    So a Tx event is raised, and the task send cmd with uart, but I cannot receive a potential ack
    message if I don't call uart_read again.

    I think the all uart_read stuff is a big trouble, and much loses the all interrupt idea.
  • Hi,

    1)

    I understand that the example is not reflecting exactly what you want, it was not ment as solution to your protocol implementation but as "guide line" on how you can setup something similar that you could actually compile and try out. See it as an "Wake on activity" kind of example. 

    If you strip away all the print outs in the example and add some event post instead, you are left with something similar to your pseduo code. 

    2)

    I don't think I really follow you here. If the UART is closed you can neither send or receive over the UART. If you know you are expecting a ACK after a sending a command you will of course need to perform a UART_read to read it out.

    If you find calling UART_read when you expect data to be received troublesome, you could roll your own UART implementation using the driverlib level functions. You would then be in full control of the UART interrupts and don't have the driver level masking of interrupts as in the UART driver.

  • Hi,
    In case I want to use driverLib functions,
    is there a way to combine with TI-RTOS uart driver?
    with the only change is for not using uart_read
  • Hi,

    In that case, you can not use the TI-RTOS UART driver, you will have to go with either the TI-RTOS driver or a driverlib implementation.
  • Hi

    I did some modification on the code (see attachment).

    I now see rxPinCallback is reached,

    as for the uart callback, only when putting breakpoint in

    rxCallback function, I see the bytes reach, and parse workes fine (the MESSAGE_REC EIVED event is posted and task function wakes up)

    when I dont put breakpoint, it doesn't happen.

    0564.uartPseudo.c
    /*
    	This is a pseudo code demonstrate simple uart bi-directional protocol
    	some of the functions are not defined, but by name explins there job
    */
    
    
    
    
    // timeout definitions
    QUIET_TIMEOUT 
    KEEP_ALIVE_TIMEOUT 
    TX_RETRY_TIMEOUT 
    RX_SESSION_TIMEOUT
    
    TX_MAX_RETRY_COUNT 
    
    
    //event definitions
    RX_ISSUE
    MESSAGE_RECEIVED
    TX_COMMAND
    TX_ENDED
    KEEP_ALIVE_TIMEOUT_EXPIRED
    
    //bitmap definitions
    TX_READY
    RX_SESSION
    CMD_IN_QUEUE
    
    
    //whenever activity occures in rx pin, switch it to uart rx
    pinIoCallback()
    {
    	setRxAsUartPin();
    	EventPost(RX_ACTIVITY);
    }
    
    
    //called by application
    putCommandInQueue(cmd)
    {
    	QueuePut(cmd);
    	bitmapSet(CMD_IN_QUEUE);
    	EventPost(TX_COMMAND)
    }
    
    
    uartTaskFcn(void)
    {
    	timeout = KEEP_ALIVE_TIMEOUT;
    	while(1)
    	{
    		event = EventPend(FOREVER);
    
    		if(event == RX_ISSUE)
    		{
    			bitmapSet(RX_SESSION);
    			uartRead(1);
    			rxSessionTimerStart(RX_SESSION_TIMEOUT);
    		}
    		
    		if(event == MESSAGE_RECEIVED)
    		{
    			rxSessionTimerStop();
    			if( checkIfMessageIsAck(rxBuff) )
    			{
    				//if first message in queue is acknowledge by the received message,
    				//extract it from queue
    				QueueExtract(cmd);
    				
    				if(QueueIsEmpty)
    				{
    					//mark that there are no more commands
    					bitmapClear(CMD_IN_QUEUE);
    				}
    
    			}
    			else
    			{
    				//upload recieved message to app
    				putRecievedMsgInApp(rxBuff);
    			}
    		
    		}
    		if(event == TX_COMMAND)
    		{
    			//command handle and send mechanism
    			handleCommandAndSend();
    		}	
    		if(event == TX_ENDED)
    		{
    			txState = TX_READY;
    			bitmapClear(TX_BUSY)
    		}
    		
    		if(event == KEEP_ALIVE_TIMEOUT_EXPIRED)
    		{
    			SendKeepAliveMessage();
    		}
    		//check if there is no uart activity
    		if( bitmapNotContains(TX_BUSY) && bitmapNotContain(RX_SESSION) )
    		{
    			//if there are more command in queue, notify task
    			if( bitmapContains(CMD_IN_QUEUE) )
    			{
    				EventPost(TX_COMMAND);
    			}
    			else
    			{
    				closeUart();
    				setRxAsGpioPin();
    				KeepAliveTimerStart(KEEP_ALIVE_TIMEOUT);
    			}
    		}
    		
    		
    		
    	}
    	
    }
    
    
    handleCommandAndSend()
    {
    //check if tx is ready to sent
    	if(txState == TX_READY)
    	{
    		//stop tx timer
    		TxTimerStop();
    		//take (not extract) first waiting message
    		QueuePeek(cmd);
    		
    		
    		if(retryCnt < TX_MAX_RETRY_COUNT)
    		{
    			txState = TX_BUSY;
    			WriteCmdBytesInBuffer(cmd,txBuffer);
    			uartWrite(txBuffer);
    			//open timer, and wait for ack
    			TxTimerStart(TX_RETRY_TIMEOUT );
    			KeepAliveTimerStop();
    			
    			//ready to recive ack
    			bitmapSet(RX_SESSION);
    			//initiate read
    			uartRead(1);
    			rxSessionTimerStart(RX_SESSION_TIMEOUT);
    			
    		}
    		else
    		{
    			retryCnt =0;
    			//no more retries, throw message away
    			QueueExtract(cmd);
    			
    			if(QueueIsEmpty)
    			{
    				//mark that there are no more commands
    				bitmapClear(CMD_IN_QUEUE);
    			}
    		}
    		
    	}
    	
    }
    
    uartReadCallback(byte)
    {
    	//prasing message, according to application protocol
    	//if succed, notify task
    	if(PARSE_OK == parse(byte,rxBuffer) )
    	{
    		EventPost(MESSAGE_RECEIVED);
    	}
    	//initiate next read
    	uartRead(1);	
    }
    
    
    uartWriteCallback()
    {
    	EventPost(TX_ENDED);
    }
    
    TxTimerExpired()
    {
    	EventPost(TX_COMMAND);
    }
    
    KeepAliveTimerExpired()
    {
    	EventPost(KEEP_ALIVE_TIMEOUT_EXPIRED);
    }

  • It is hard to say what could be the problem, it would help to know the actual code used to setup the PIN and UART.

    Could you maybe post a more complete version of the code you are running (If you do not want to share it here, you could maybe sent it in a PM to me and I can have a look)?

    From looking at the pseudo code, the only think that strikes me is that the 'RX_ACTIVITY' event is not covered anywhere.