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/CC2650: UART read. Missing the first byte. TIMAC 1_05_02_43299

Part Number: CC2650
Other Parts Discussed in Thread: TIMAC, , MSP430F5419A, CC2592

Tool/software: TI-RTOS

Hi, 

I'm using TIMAC  1_05_02_43299 and tirtos_simplelink_2_11_01_09. 

The CC2650 communicates with another MCU over the UART. 

In MSA_ProcessEvent() function I receiver an RF packet and send it over the UART using UART_write(). The other MCU responds but CC2650 is always missing the first byte. 

The uart runs in read callback mode but it never gets interrupt to read the first byte. 

UART_write is running in blocking mode. 

The first byte from the response comes 200 us after data is transmitted. The rest come a few ms later. 

Any ideas?

Thanks

  • Hi,

    When performing a UART_write, it is a +100us "waiting time" (can be less or more depending on the number of bytes sent) for flushing the FIDO. doing single byte transfers thus give you a high overhead until the write "actually" finish.
    Thus I expect you simply miss the first byte due to this as the MCU might be responding while you are waiting for the FIFO to flush.

    Do you have any way of delaying the first byte?
  • Hi, 

    I can't control the response from the MCU. We use CC2650 to program the MCU, which is MSP430, over the air. We put MSP430 in BSL mode and program the flash so the responses come from the BSL firmware in the MSP430. 

    But the CC2650 has two separate FIFOs for TX and RX. Why UART_write will block the RX FIFO?

    I have tried running a test BSL commands before we got into MSA_Process(), which is the main thread, and that works fine, but when I do it inside the MSA_ProcessEvent() we lose the first byte.

    I haven't used TI RTOS before so I'm still learning my way around.

  • Hi,

    Could you maybe provide a code snippet of the MSA_ProcessEvent()  function so that I can have a look at it. I could think of some scenarios that could cause you to lose the first byte, but I would need to know how you perform the write and read operations in order to say for sure.

    Also, if possible, could you provide a snippet of the "working" scenario when you do it in the main thread?

  • This is in msa.c file in timac_1_05_02_43299.

    /**************************************************************************************************
    *
    * @fn MSA_ProcessEvent
    *
    * @brief Process event from Stack
    *
    * @param macCbackEvent_t
    *
    * @return status
    *
    **************************************************************************************************/
    uint_least16_t MSA_ProcessEvent(TimacMSG_MacCbackEvent_t *pMsg)
    {
    TimacMSG_MacCbackEvent_t* pData;

    #ifdef MSA_FFD
    uint8 j, panflag;
    #endif

    #if defined(NV_RESTORE)
    #if defined(FEATURE_MAC_SECURITY)
    uint8 i;
    #endif
    #endif

    #ifdef FEATURE_MAC_SECURITY
    uint_least16_t panID;
    uint_least16_t panCoordShort;
    Timac_sAddrExt_t panCoordExtAddr;
    #endif /* FEATURE_MAC_SECURITY */

    switch (pMsg->hdr.event)
    {
    .......
    case MAC_MCPS_DATA_IND:
    pData = (TimacMSG_MacCbackEvent_t *)pMsg;
    if(pData->dataInd.msdu.len < sizeof(radioRxBuf))
    {
    memcpy(radioRxBuf,pData->dataInd.msdu.p, pData->dataInd.msdu.len ); // copy the data from the RF buffer for further processing
    ParseRfPAcket(radioRxBuf); // process the RF data.
    if(!bBSLMode)
    {
    serTxNbr = serialTxData(radioRxBuf,(uint16_t) pData->dataInd.msdu.len);
    }
    else
    {
    // reset the BSL timeout timer
    Clock_stop(Clock_handle(&msaBslClkStruct));
    Clock_setPeriod(Clock_handle(&msaBslClkStruct), (UInt32)MSA_BSL_PERIOD);
    Clock_start(Clock_handle(&msaBslClkStruct));

    }
    }
    break;

    }
    }

    void ParseRfPAcket(uint8 *pData)
    {

    uint32 delayVar;


    if(pData[0]!=HOST_PACKET_HEADER)
    return;
    switch(pData[1])
    {
    case ENTER_BSL_MODE: // Setup MSP430 in BSL mode
    progInterfaceInit(); // initialize the second uart. CC2650 has only one UART so this assings different TX/RX pins to the UART.
    uartStartReading(); // start reading.
    Reset_MSP430F5419A_BSL();
    bBSLMode = true;
    wPacketLen = WriteBSLModeEnteredResp(msa_Data1);
    MSA_McpsDataReq((uint8*)msa_Data1,wPacketLen,TRUE,msa_CoordShortAddr );
    break;
    case BSL_PROGRAM_DATA: // Program data in MSP430 flash.
    serTxNbr = serialTxData(&pData[6],(uint16_t) pData[5]); // send the data to MSP430
    // delayVar = 800000; // I've tried to do the delay this way but the result is the same. First byte missing.
    // while(delayVar--);
    Task_sleep(150000 / Clock_tickPeriod); // wait around 100ms for the response
    wPacketLen = WriteProgramDataResp(msa_Data1); // here we read the response from MSP430 and the first byte is missing
    MSA_McpsDataReq((uint8*)msa_Data1,wPacketLen,TRUE,msa_CoordShortAddr );
    break;
    case ENTER_APP_MODE: // Reset MSP430 in application mode.
    Reset_MSP430F5419A_Application();
    bBSLMode = false;
    wPacketLen = WriteAppModeEnteredResp(msa_Data1);
    MSA_McpsDataReq((uint8*)msa_Data1,wPacketLen,TRUE,msa_CoordShortAddr );
    progInterfaceClose(); // close the second uart
    break;
    default:

    break;
    }
    }

    // here are UART params

    params.baudRate = PROG_UART_BAUD_RATE;
    params.readMode = UART_MODE_CALLBACK; 
    params.writeMode = UART_MODE_CALLBACK;// First tried in Blocking mode - no difference
    params.writeDataMode = UART_DATA_BINARY; //Data is not processed
    params.readDataMode = UART_DATA_BINARY; //Data is not processed
    params.readReturnMode = UART_RETURN_FULL; //UART_RETURN_FULL unblocks or performs a callback when the read buffer has been filled.
    params.readEcho = UART_ECHO_OFF;
    params.readCallback = uartReadCallback;
    params.writeCallback = uartWriteCallback;
    params.pinSel = UART_PROG_PINS; // select programming pins.
    params.stopBits = UART_STOP_ONE;

  • UARTCC2650.c
    /*
     * Copyright (c) 2015, 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.
     */
    
    #include <stdint.h>
    #include <xdc/runtime/Error.h>
    #include <xdc/runtime/Assert.h>
    #include <xdc/runtime/Diags.h>
    #include <xdc/runtime/Log.h>
    #include <xdc/runtime/Types.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/family/arm/m3/Hwi.h>
    #include <ti/sysbios/family/arm/cc26xx/Power.h>
    #include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
    //#include <ti/drivers/uart/UARTCC2650.h>
    #include <ti/drivers/pin/PINCC26XX.h>
    
    #include "Board.h"
    #include "UARTCC2650.h"
    
    /* driverlib header files */
    #include <inc/hw_memmap.h>
    #include <inc/hw_ints.h>
    #include <inc/hw_types.h>
    #include <driverlib/uart.h>
    #include <driverlib/sys_ctrl.h>
    #include <driverlib/ioc.h>
    #include <driverlib/aon_ioc.h>
    
    
    /* UARTCC2650 functions */
    //void         UARTCC2650_close(UART_Handle handle);
    //int          UARTCC2650_control(UART_Handle handle, unsigned int cmd, void *arg);
    //void         UARTCC2650_init(UART_Handle handle);
    //UART_Handle  UARTCC2650_open(UART_Handle handle, UART_Params *params);
    //int          UARTCC2650_read(UART_Handle handle, void *buffer, size_t size);
    //int          UARTCC2650_readPolling(UART_Handle handle, void *buf, size_t size);
    //void         UARTCC2650_readCancel(UART_Handle handle);
    //int          UARTCC2650_write(UART_Handle handle, const void *buffer,
    //                            size_t size);
    //int          UARTCC2650_writePolling(UART_Handle handle, const void *buf,
    //                                   size_t size);
    //void         UARTCC2650_writeCancel(UART_Handle handle);
    
    /* UARTCC2650 internal functions */
    static void  UARTCC2650_initHw(UART_Handle handle);
    static bool  UARTCC2650_initIO(UART_Handle handle);
    static Power_NotifyResponse uartPostNotify(Power_Event eventType, uint32_t clientArg);
    
    /* UART function table for UARTCC2650 implementation */
    const UART_FxnTable UARTCC2650_fxnTable = {
        UARTCC2650_close,
        UARTCC2650_control,
        UARTCC2650_init,
        UARTCC2650_open,
        UARTCC2650_read,
        UARTCC2650_readPolling,
        UARTCC2650_readCancel,
        UARTCC2650_write,
        UARTCC2650_writePolling,
        UARTCC2650_writeCancel
    };
    
    static const uint32_t dataLength[] = {
        UART_CONFIG_WLEN_5, /* UART_LEN_5 */
        UART_CONFIG_WLEN_6, /* UART_LEN_6 */
        UART_CONFIG_WLEN_7, /* UART_LEN_7 */
        UART_CONFIG_WLEN_8  /* UART_LEN_8 */
    };
    
    static const uint32_t stopBits[] = {
        UART_CONFIG_STOP_ONE,   /* UART_STOP_ONE */
        UART_CONFIG_STOP_TWO    /* UART_STOP_TWO */
    };
    
    static const uint32_t parityType[] = {
        UART_CONFIG_PAR_NONE,   /* UART_PAR_NONE */
        UART_CONFIG_PAR_EVEN,   /* UART_PAR_EVEN */
        UART_CONFIG_PAR_ODD,    /* UART_PAR_ODD */
        UART_CONFIG_PAR_ZERO,   /* UART_PAR_ZERO */
        UART_CONFIG_PAR_ONE     /* UART_PAR_ONE */
    };
    
    #define CC2650_UARTS            1
    UARTCC2650_Object uartCC2650Objects[CC2650_UARTS];
    
    /* UART hardware parameter structure, also used to assign UART pins */
    const UARTCC2650_HWAttrs uartCC2650HWAttrs[CC2650_UARTS] = {
        {    /* CC2650_UART0 */
            .baseAddr = UART0_BASE,
            .intNum = INT_UART0,
            .powerMngrId = PERIPH_UART0,
            .txPin = Board_UART_TX,
            .rxPin = Board_UART_RX,
            .ctsPin = PIN_UNASSIGNED,
            .rtsPin = PIN_UNASSIGNED,
    	.txPinAlt1 = Board_PROG_UART_TX,	//--DD feb 28 2018
    	.rxPinAlt1 = Board_PROG_UART_RX		//--DD feb 28 2018
        },
    };
    
    /* UART configuration structure */
    UART_Config UARTCC2650_config = {
         &UARTCC2650_fxnTable, &uartCC2650Objects[0], &uartCC2650HWAttrs[0] 
    };
    
    UART_Handle user_UART_Handle = &UARTCC2650_config;
    /*
     *  ======================== PIN driver objects ================================
     *  Simple callback to post a semaphore for the blocking mode.
     */
    /* PIN driver state object */
    static PIN_State pinState;
    /* PIN driver handle */
    static PIN_Handle hPin;
    
    /*
     *  ================================= Macro ====================================
     *  TODO: Move me
     */
    #define MIN(a,b) (((a)<(b))?(a):(b))
    
    /*
     *  ======== writeSemCallback ========
     *  Simple callback to post a semaphore for the blocking mode.
     */
    static void writeSemCallback(UART_Handle handle, void *buffer, size_t count)
    {
        UARTCC2650_Object *object = handle->object;
    
        Log_print1(Diags_USER1, "UART:(%p) posting write semaphore",
                    ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr);
    
        Semaphore_post(Semaphore_handle(&(object->writeSem)));
    }
    
    /*
     *  ======== readSemCallback ========
     *  Simple callback to post a semaphore for the blocking mode.
     */
    static void readSemCallback(UART_Handle handle, void *buffer, size_t count)
    {
        UARTCC2650_Object *object = handle->object;
    
        Log_print1(Diags_USER1, "UART:(%p) posting read semaphore",
                    ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr);
    
        Semaphore_post(Semaphore_handle(&(object->readSem)));
    }
    
    /*
     *  ======== writeData ========
     *  Write and process data to the UART.
     */
    static int32_t writeData(UART_Handle handle, int32_t size)
    {
        UARTCC2650_Object           *object;
        UARTCC2650_HWAttrs const    *hwAttrs;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Send characters until FIFO is full or done. */
        while (size) {
            /* Send the next character and increment counts. */
            if (!UARTCharPutNonBlocking(hwAttrs->baseAddr, *(unsigned char *)(object->writeBuf))) {
                /* Character was not sent */
                break;
            }
            Log_print2(Diags_USER2, "UART:(%p) Wrote character 0x%x",
                       hwAttrs->baseAddr, *(unsigned char *)object->writeBuf);
            object->writeBuf = (unsigned char *)object->writeBuf + 1;
            size--;
            object->writeCount++;
        }
        return (size);
    }
    
    /*
     *  ======== readData ========
     *  Read and process data from the UART.
     */
    static int32_t readData(UART_Handle handle, int32_t size)
    {
        int32_t                     readIn;
        UARTCC2650_Object           *object;
        UARTCC2650_HWAttrs const    *hwAttrs;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Receive chars until empty or done. */
        while (size && (readIn = (int32_t)UARTCharGetNonBlocking(hwAttrs->baseAddr)) != -1) {
    
            Log_print2(Diags_USER2, "UART:(%p) Read character 0x%x",
                                     hwAttrs->baseAddr, (uint8_t)readIn);
    
            /* Update status. */
            *((unsigned char *)object->readBuf) = (uint8_t)readIn;
            object->readBuf = (unsigned char *)object->readBuf + 1;
            object->readCount++;
            size--;
        }
        return (size);
    }
    
    /*
     *  ======== readFinishedDoCallback ========
     *  Read finished - make callback
     *
     *  When all expected bytes are received or receive timeout has occured, read
     *  has succeeded. The RX interrupts are disabled and standby is allowed again,
     *  but RX is not disabled. The application should either issue a new read to
     *  ensure we don't get an overflow or call readCancel(...) so the RX is turned
     *  off.
     *
     *  @param(handle)         The UART_Handle for ongoing read.
     */
    static void readFinishedDoCallback(UART_Handle handle)
    {
        UARTCC2650_Object           *object;
        UARTCC2650_HWAttrs const    *hwAttrs;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /*       Release power constraint. */
        Power_releaseConstraint(Power_SB_DISALLOW);
    
        /*       Disable RX interrupts */
        UARTIntDisable(hwAttrs->baseAddr, UART_INT_OE | UART_INT_BE
                       | UART_INT_PE | UART_INT_FE | UART_INT_RT |
                       UART_INT_RX);
    
        /* Reset the read buffer so we can pass it back */
        object->readBuf = (unsigned char *)object->readBuf - object->readCount;
    
        /* Do Callback */
        object->readCallback(handle, object->readBuf,
                             object->readCount);
    
        Log_print2(Diags_USER1, "UART:(%p) Read finished, %d bytes read",
                   hwAttrs->baseAddr, object->readCount);
    }
    
    /*
     *  ======== startTxFifoEmptyClk ========
     *  Last write to TX FIFO is done, but not shifted out yet. Start a clock
     *  which will trigger when the TX FIFO should be empty.
     *
     *  @param(handle)         The UART_Handle for ongoing write.
     *  @param(numOfDataInFifo) The number of data present in FIFO after last write
     */
    static void startTxFifoEmptyClk(UART_Handle handle, unsigned int numOfDataInFifo)
    {
        UARTCC2650_Object           *object;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* No more to write, but data is not shiftet out properly yet.
         *   1. Compute appropriate wait time for FIFO to empty out
         *       - 1 bit for start bit
         *       - 5+(object->dataLength) for total data length
         *       - 50 (50us) for margin (TODO: make param?)
         *       - 1000000 because Clock_tickPeriod resolution is 1 us
         */
        unsigned int writeTimeoutUs = (numOfDataInFifo*(1+5+(object->dataLength)+(stopBits[object->stopBits]))*1000000)/object->baudRate + 50;
        /*   2. Configure clock object to trigger when FIFO is empty */
        Clock_setTimeout((Clock_Handle) &(object->txFifoEmptyClk), (writeTimeoutUs/Clock_tickPeriod));
        Clock_start((Clock_Handle) &(object->txFifoEmptyClk));
    }
    
    /*
     *  ======== writeFinishedDoCallback ========
     *  Write finished - make callback
     *
     *  This function is called when the txFifoEmptyClk times out. The TX FIFO
     *  should now be empty and all bytes have been transmitted. The TX will be
     *  turned off, TX interrupt is disabled and standby is allowed again.
     *
     *  @param(handle)         The UART_Handle for ongoing write.
     */
    static void writeFinishedDoCallback(UART_Handle handle)
    {
        UARTCC2650_Object           *object;
        UARTCC2650_HWAttrs const    *hwAttrs;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Stop the txFifoEmpty clock */
        Clock_stop((Clock_Handle) &(object->txFifoEmptyClk));
    
        /*   1. Function verifies that the FIFO is empty via BUSY flag */
        /*   2. Polls this flag if not yet ready (should not be necessary) */
        /*   TODO: remove while, use another clock wait instead */
        while(UARTBusy(hwAttrs->baseAddr));
    
        /* Release constraint since transaction is done */
        Power_releaseConstraint(Power_SB_DISALLOW);
    
        /* Disable TX interrupt */
        UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
    
        /* Disable TX */
        HWREG(UART0_BASE + UART_O_CTL) &= ~(UART_CTL_TXE);
    
        /* Reset the write buffer so we can pass it back */
        object->writeBuf = (unsigned char *)object->writeBuf - object->writeCount;
    
        /* Make callback */
        object->writeCallback(handle, (uint8_t*)object->writeBuf,
                              object->writeCount);
        Log_print2(Diags_USER1, "UART:(%p) Write finished, %d bytes written",
                   hwAttrs->baseAddr, object->writeCount);
    }
    
    /*
     *  ======== UARTCC2650_hwiIntFxn ========
     *  Hwi function that processes UART interrupts.
     *
     *  Six UART interrupts are enabled when configured for RX: Receive timeout,
     *  receive FIFO is 4/8 full and all four error interrupts.
     *
     *  One interrupt is enabled when configured for TX: Transmit FIFO is 7/8
     *  empty.
     *
     *  The RX and TX can operate independently of each other.
     *
     *  When the read or write is finished they will
     *  post the semaphore or make the callback and log the transfer.
     *
     *  @param(arg)         The UART_Handle for this Hwi.
     */
    void UARTCC2650_hwiIntFxn(UArg arg)
    {
        unsigned long            intStatus;
        unsigned long            errStatus;
        UARTCC2650_Object        *object;
        UARTCC2650_HWAttrs const *hwAttrs;
    
        /* Get the pointer to the object and hwAttrs */
        object = ((UART_Handle)arg)->object;
        hwAttrs = ((UART_Handle)arg)->hwAttrs;
    
        /* Clear interrupts */
        intStatus = UARTIntStatus(hwAttrs->baseAddr, true);
        UARTIntClear(hwAttrs->baseAddr, intStatus);
    
        Log_print2(Diags_USER2, "UART:(%p) Interrupt with mask 0x%x",
                                 hwAttrs->baseAddr, intStatus);
    
        /* Basic error handling */
        if(intStatus & (UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE)) {
    
            /* If overrun, the error bit is set immediately */
            if(intStatus & UART_INT_OE) {
                /* check receive status register */
                errStatus = UARTRxErrorGet(hwAttrs->baseAddr);
                UARTRxErrorClear(hwAttrs->baseAddr);
                /* read out min of readsize and fifo size */
                int32_t bytesToRead = MIN(UARTCC2650_FIFO_SIZE, object->readSize);
                readData((UART_Handle)arg, bytesToRead);
            }
            else {
                /*
                 * else, for break, framing and par. error bits are at error index
                 * (we would like to keep the "surviving" bits)
                 */
                while(object->readSize > 0) {
                    /* read one data */
                    readData((UART_Handle)arg, 1);
                    /* check receive status register if byte is OK */
                    errStatus = UARTRxErrorGet(hwAttrs->baseAddr);
                    UARTRxErrorClear(hwAttrs->baseAddr);
                    if(errStatus != 0) {
                        /*
                         * last read was not including data, reset data vars
                         * (i.e. upd readBuf pointer, decr readCount)
                         */
                        object->readBuf = (unsigned char *)object->readBuf - 1;
                        object->readCount--;
                        /* the FIFO index with error is reached, stop reading more. */
                        break;
                    }
                    else {
                        /* current read was not the problem update readSize */
                        object->readSize--;
                    }
                }
            }
    
            /* Report current error status */
            object->status = (UART_Status)errStatus;
    
            /* Break and clean up any ongoing transaction */
            UARTCC2650_readCancel((UART_Handle)arg);
        }
        else {
            /*   If RT (Receive Timeout) occured it means we are reading */
            /*   (handle in swi?) */
            if(intStatus & UART_INT_RT) {
                /* Read data from FIFO.*/
                object->readSize = readData((UART_Handle)arg, object->readSize);
                /*     If return partial is set */
                if(object->readRetPartial) {
                    /* Partial read accepted, read succeeded by def, set readSize
                    * to allow callback to trigger new _read()
                    */
                    object->readSize = 0;
                    /*       Read succeeded */
                    readFinishedDoCallback((UART_Handle)arg);
                }
                /*     else - return when all bytes have arrived  */
                else {
                /*       If FIFO contained last bytes */
                    if(!object->readSize) {
                /*         Read succeeded  */
                        readFinishedDoCallback((UART_Handle)arg);
                    }
                }
            }
            else {
                /* If we are reading (i.e. readSize != 0) */
                /* (RX interrupt, since CTS is not supported yet) */
                if (intStatus & UART_INT_RX) {
                    /* Read whatever is less of:
                    *   - FIFO_THR bytes - 1 (leave one byte to trigger RT timeout)
                    *   - object->readSize (never read more than requested from application)
                    * since RT timeout will only trigger if FIFO is not empty.
                    */
                    int32_t bytesToRead = MIN(object->readFifoThreshold-1, object->readSize);
                    /* Do read, all bytes we request to read, are present in FIFO */
                    readData((UART_Handle)arg, bytesToRead);
                    /* Decrement objec->readSize with the actual number of bytes read
                    *  There will always be at least bytesToRead number of bytes in FIFO
                    */
                    object->readSize -= bytesToRead;
                    /*      If FIFO contained last bytes */
                    if (!object->readSize) {
                    /*        Read succeeded. */
                        readFinishedDoCallback((UART_Handle)arg);
                    }
                }
            }
        }
        /* Write if there are characters to be written. */
        if (object->writeSize) {
            /* Using writtenLast=writeSize before last write
             *(since writeSize=0 when the last finishes)
             */
            uint32_t writtenLast = object->writeSize;
            object->writeSize = writeData((UART_Handle)arg, object->writeSize);
            if(!object->writeSize) {
                /* No more to write, but data is not shiftet out properly yet.
                 * Start TX FIFO Empty clock, which will trigger the txFifoEmptyClk
                 * function.
                 * +4 because it is 4 bytes left in TX FIFO when the TX FIFO
                 * threshold interrupt occurs.
                 */
                 startTxFifoEmptyClk((UART_Handle)arg, (writtenLast+4));
            }
        }
    }
    
    /*!
     *  @brief UART CC26XX initialization
     *
     *  @pre    Calling context: Hwi, Swi, Task, Main
     *
     *  @param handle  A UART_Handle
     *
     */
    void UARTCC2650_init(UART_Handle handle)
    {
        UARTCC2650_Object           *object;
    
        /* Get the pointer to the object */
        object = handle->object;
    
        object->opened = false;
    }
    
    /*!
     *  @brief  Function to initialize the CC26XX UART peripheral specified by the
     *          particular handle. The parameter specifies which mode the UART
     *          will operate.
     *
     *  The function will set a dependency on it power domain, i.e. power up the
     *  module and enable the clock. The IOs are allocated. Neither the RX nor TX
     *  will be enabled, and none of the interrupts are enabled.
     *
     *  @pre    UART controller has been initialized
     *          Calling context: Task
     *
     *  @param  handle        A UART_Handle
     *
     *  @param  params        Pointer to a parameter block, if NULL it will use
     *                        default values
     *
     *  @return A UART_Handle on success or a NULL on an error or if it has been
     *          already opened
     *
     *  @sa     UARTCC2650_close()
     */
    UART_Handle UARTCC2650_open(UART_Handle handle, UART_Params *params)
    {
        unsigned int                    key;
        /* Use union to save on stack allocation */
        union {
            Hwi_Params                  hwiParams;
            Semaphore_Params            semParams;
            Clock_Params                clkParams;
        } paramsUnion;
        UARTCC2650_Object               *object;
        UARTCC2650_HWAttrs const        *hwAttrs;
        UART_Params                     uartParams;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Disable preemption while checking if the UART is open. */
        key = Hwi_disable();
    
        /* Check if the UART is open already with the base addr. */
        if (object->opened == true) {
            Hwi_restore(key);
    
            Log_warning1("UART:(%p) already in use.", hwAttrs->baseAddr);
    
            return (NULL);
        }
        object->opened = true;
        Hwi_restore(key);
    
        /* If params are NULL use defaults. */
        if (params == NULL) {
            UART_Params_init(&uartParams);
            params = &uartParams;
        }
    
        /* Check that a callback is set */
        Assert_isTrue((params->readMode != UART_MODE_CALLBACK) ||
                      (params->readCallback != NULL), NULL);
        Assert_isTrue((params->writeMode != UART_MODE_CALLBACK) ||
                      (params->writeCallback != NULL), NULL);
    
        /* Initialize the UART object */
        object->readMode       = params->readMode;
        object->writeMode      = params->writeMode;
        object->readTimeout    = params->readTimeout;
        object->writeTimeout   = params->writeTimeout;
        object->readCallback   = params->readCallback;
        object->writeCallback  = params->writeCallback;
        object->readReturnMode = params->readReturnMode;
        object->readDataMode   = params->readDataMode;
        object->writeDataMode  = params->writeDataMode;
        object->baudRate       = params->baudRate;
        object->dataLength     = params->dataLength;
        object->stopBits       = params->stopBits;
        object->parityType     = params->parityType;
        object->pinSel     	   = params->pinSel; 	//--DD feb 28 2018 
    	
    
        /* Set UART transaction variables to defaults. */
        object->writeBuf = NULL;
        object->readBuf = NULL;
        object->writeCount = 0;
        object->readCount = 0;
        object->writeSize = 0;
        object->readSize = 0;
        object->writeCR = false;
        object->readRetPartial = false;
        object->readFifoThreshold = UART_TH_FIFO_RX4_8;
        object->writeFifoThreshold = UART_FIFO_TX1_8;
    
        /* Register power dependency - i.e. power up and enable clock for UART. */
        Power_setDependency(hwAttrs->powerMngrId);
    
        /* Initialize the UART hardware module */
        UARTCC2650_initHw(handle);
    
        /* Configure IOs, make sure it was successful */
        if(!UARTCC2650_initIO(handle)) {
            /* Trying to use UART driver when some other driver or application
            *  has already allocated these pins, error!
            */
            Log_warning0("Could not allocate pins, already in use.");
            /* Disable UART */
            UARTDisable(hwAttrs->baseAddr);
            /* Release power dependency - i.e. potentially power down serial domain. */
            Power_releaseDependency(hwAttrs->powerMngrId);
            /* Mark the module as available */
            key = Hwi_disable();
            object->opened = false;
            Hwi_restore(key);
            /* Signal back to application that UART driver was not succesfully opened */
            return (NULL);
        }
    
        /* Create Hwi object for this UART peripheral. */
        Hwi_Params_init(&(paramsUnion.hwiParams));
        paramsUnion.hwiParams.arg = (UArg)handle;
        Hwi_construct(&(object->hwi), hwAttrs->intNum, UARTCC2650_hwiIntFxn,
                      &(paramsUnion.hwiParams), NULL);
    
        /* Initialize semaphore */
        Semaphore_Params_init(&(paramsUnion.semParams));
        paramsUnion.semParams.mode = Semaphore_Mode_BINARY;
    
        /* If write mode is blocking create a semaphore and set callback. */
        if (object->writeMode == UART_MODE_BLOCKING) {
            Semaphore_construct(&(object->writeSem), 0, &(paramsUnion.semParams));
            object->writeCallback = &writeSemCallback;
        }
    
        /* If read mode is blocking create a semaphore and set callback. */
        if (object->readMode == UART_MODE_BLOCKING) {
            Semaphore_construct(&(object->readSem), 0, &(paramsUnion.semParams));
            object->readCallback = &readSemCallback;
        }
    
        /* Create clock object to be used for write FIFO empty callback */
        Clock_Params_init(&paramsUnion.clkParams);
        paramsUnion.clkParams.period    = 0;
        paramsUnion.clkParams.startFlag = false;
        paramsUnion.clkParams.arg       = (UArg) handle;
        Clock_construct(&(object->txFifoEmptyClk),
                        (Clock_FuncPtr) &writeFinishedDoCallback,
                        10, &(paramsUnion.clkParams));
    
        /* Register notification function */
        Power_registerNotify(&object->uartPostObj, Power_AWAKE_STANDBY, (Fxn)uartPostNotify, (uint32_t)handle, NULL );
    
        /* UART opened successfully */
        Log_print1(Diags_USER1, "UART:(%p) opened", hwAttrs->baseAddr);
    
        /* Return the handle */
        return (handle);
    }
    
    /*!
     *  @brief  Function to close a given CC26XX UART peripheral specified by the
     *          UART handle.
     *
     *  Will disable the UART, disable all UART interrupts and release the
     *  dependency on the corresponding power domain.
     *
     *  @pre    UARTCC2650_open() had to be called first.
     *          Calling context: Task
     *
     *  @param  handle  A UART_Handle returned from UART_open()
     *
     *  @sa     UARTCC2650_open
     */
    void UARTCC2650_close(UART_Handle handle)
    {
        unsigned int                 key;
        UARTCC2650_Object            *object;
        UARTCC2650_HWAttrs const     *hwAttrs;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Deallocate pins */
        PIN_close(hPin);
    
        /* Disable all UART module interrupts. */
        UARTIntDisable(hwAttrs->baseAddr, UART_INT_OE | UART_INT_BE | UART_INT_PE |
                                          UART_INT_FE | UART_INT_RT | UART_INT_TX |
                                          UART_INT_RX | UART_INT_CTS);
        /* Disable UART */
        UARTDisable(hwAttrs->baseAddr);
    
        /* Release power dependency - i.e. potentially power down serial domain. */
        Power_releaseDependency(hwAttrs->powerMngrId);
    
        /* Destruct the SYS/BIOS objects. */
        Hwi_destruct(&(object->hwi));
        Semaphore_destruct(&(object->writeSem));
        Semaphore_destruct(&(object->readSem));
        Clock_destruct(&(object->txFifoEmptyClk));
    
        /* Mark the module as available */
        key = Hwi_disable();
        object->opened = false;
        Hwi_restore(key);
    
        /* Unregister power notification objects */
        Power_unregisterNotify(&object->uartPostObj);
    
        Log_print1(Diags_USER1, "UART:(%p) closed", hwAttrs->baseAddr);
    }
    
    
    /*!
     *  @brief  Function for setting control parameters of the UART
     *          after it has been opened.
     *
     *  @pre    UARTCC2650_open() has to be called first.
     *          Calling context: Hwi, Swi, Task
     *
     *  @param  handle A UART handle returned from UARTCC2650_open()
     *
     *  @param  cmd  The command to execute, supported commands are:
     *              | Command                               | Description             |
     *              |-------------------------------------- |-------------------------|
     *              | ::UARTCC2650_RETURN_PARTIAL_ENABLE    | Enable RETURN_PARTIAL   |
     *              | ::UARTCC2650_RETURN_PARTIAL_DISABLE   | Disable RETURN_PARTIAL  |
     *
     *  @param  *arg  Pointer to command arguments, currently not in use, set to NULL.
     *
     *  @return ::UARTCC2650_CMD_SUCCESS if success, or error code if error.
     */
    int UARTCC2650_control(UART_Handle handle, unsigned int cmd, void *arg)
    {
        /* Locals */
        UARTCC2650_Object            *object;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Initialize return value*/
    	int ret = UARTCC2650_CMD_UNDEFINED;
        /* Do command*/
    	switch(cmd) {
    
    		case UARTCC2650_RETURN_PARTIAL_ENABLE:
    			/* Enable RETURN_PARTIAL */
    			object->readRetPartial = true;
                ret = UARTCC2650_CMD_SUCCESS;
    			break;
    
    		case UARTCC2650_RETURN_PARTIAL_DISABLE:
    			/* Disable RETURN_PARTIAL */
    			object->readRetPartial = false;
                ret = UARTCC2650_CMD_SUCCESS;
    			break;
    
    		default:
                /* This command is not defined */
                ret = UARTCC2650_CMD_UNDEFINED;
    			break;
    	}
    
        /* Return */
    	return (ret);
    }
    
    /*!
     *  @brief  Function that writes data to a UART
     *
     *  This function initiates an operation to write data to CC26XX UART
     *  controller.
     *
     *  In ::UART_MODE_BLOCKING, UART_write will block task execution until all
     *  the data in buffer has been written.
     *
     *  In ::UART_MODE_CALLBACK, UART_write does not block task execution, but calls a
     *  callback function specified by writeCallback when the data has been written.
     *
     *  When the write function is called, TX is enabled, TX interrupt is enabled,
     *  and standby is not allowed.
     *
     *  @pre    UARTCC2650_open() has to be called first.
     *          Calling context: Hwi and Swi (only if using ::UART_MODE_CALLBACK), Task
     *
     *  @param  handle      A UART_Handle returned from UARTCC2650_open()
     *
     *  @param  buffer      A pointer to buffer containing data to be written
     *
     *  @param  size        The number of bytes in buffer that should be written
     *                      onto the UART.
     *
     *  @return Returns the number of bytes that have been written to the UART,
     *          UART_ERROR on an error.
     *
     */
    int UARTCC2650_write(UART_Handle handle, const void *buffer, size_t size)
    {
        unsigned int                     key;
        UARTCC2650_Object                *object;
        UARTCC2650_HWAttrs const         *hwAttrs;
    
        /* Get the pointer to the object */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Check that there is data to write */
        Assert_isTrue(size != 0, NULL);
    
        /* Disable preemption while checking if the UART is in use. */
        key = Hwi_disable();
        if (object->writeSize) {
            Hwi_restore(key);
            Log_warning1("UART:(%p) Could not write data, uart in use.",
                        ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr);
    
            return (UART_ERROR);
        }
    
        /* Stop the txFifoEmpty clock in case it was running due to a previous write operation */
        Clock_stop((Clock_Handle) &(object->txFifoEmptyClk));
    
        /* Update the status of the UART module */
        object->status = UART_OK;
    
        /* Save the data to be written and restore interrupts. */
        object->writeBuf = buffer;
        object->writeCount = 0;
    
        Hwi_restore(key);
    
        /* Set constraints to guarantee transaction */
        Power_setConstraint(Power_SB_DISALLOW);
    
        /* Enable TX */
        HWREG(UART0_BASE + UART_O_CTL) |= UART_CTL_TXE;
    
        /* Fill up TX FIFO */
        if (!(object->writeSize = writeData(handle, size))) {
            /* No more data to transmit - Write is finished but all bytes
            *  may not have been shifted out. */
            startTxFifoEmptyClk((UART_Handle)handle, (size));
    
            /* If writeMode is blocking, block and get the status. */
            if (object->writeMode == UART_MODE_BLOCKING) {
                /* Pend on semaphore and wait for Hwi to finish. */
                Semaphore_pend(Semaphore_handle(&(object->writeSem)),
                                object->writeTimeout);
                return (object->writeCount);
            }
        } else {
    
            /* Enable TX interrupts */
            UARTIntEnable(hwAttrs->baseAddr, UART_INT_TX);
    
            /* If writeMode is blocking, block and get the status. */
            if (object->writeMode == UART_MODE_BLOCKING) {
                /* Pend on semaphore and wait for Hwi to finish. */
                if (!Semaphore_pend(Semaphore_handle(&(object->writeSem)),
                                    object->writeTimeout)) {
                    /* Semaphore timed out, make the write empty and log the write. */
                    object->writeSize = 0;
    
                    Log_print2(Diags_USER1, "UART:(%p) Write timed out, %d bytes written",
                          ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr,
                            object->writeCount);
    
                }
    
                /* Return the numbers of samples written */
                return (object->writeCount);
            }
        }
        /* This return will only be active in UART_MODE_CALLBACK mode. */
        return (0);
    }
    
    /*!
     *  @brief This function is NOT supported
     *
     *  @pre    UARTCC2650_open() and has to be called first.
     *          Calling context: Task
     *
     *  @param handle       The UART_Handle for ongoing write.
     *
     *  @param  buffer      A pointer to buffer containing data to be written
     *
     *  @param  size        The number of bytes in buffer that should be written
     *                      onto the UART.
     *
     *  @return Always ::UARTCC2650_CMD_UNDEFINED
     */
    int UARTCC2650_writePolling(UART_Handle handle, const void *buf, size_t size)
    {
        /* Not supported */
        return (UARTCC2650_CMD_UNDEFINED);
    }
    
    /*!
     *  @brief Function that cancel UART write. Will disable TX interrupt, disable
     *         TX and allow standby.
     *
     *  @pre    UARTCC2650_open() and has to be called first.
     *          Calling context: Task
     *
     *  @param handle         The UART_Handle for ongoing write.
     */
    void UARTCC2650_writeCancel(UART_Handle handle)
    {
        unsigned int                key;
        UARTCC2650_Object           *object;
        UARTCC2650_HWAttrs const    *hwAttrs;
    
        /* Get the pointer to the object */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Disable interrupts to avoid writing data while changing state. */
        key = Hwi_disable();
    
        /* Return if there is no write. */
        if (!object->writeSize) {
            Hwi_restore(key);
            return;
        }
    
        /* Set size = 0 to prevent writing and restore interrupts. */
        object->writeSize = 0;
        Hwi_restore(key);
    
        /* Disable TX interrupt */
        UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
    
        /* Disable UART TX */
        HWREG(UART0_BASE + UART_O_CTL) &= ~(UART_CTL_TXE);
    
        /* TODO: FIFO is flushed (not possible according to Saeeid -> test to verify) */
    
        /* Release constraint since transaction is done */
        Power_releaseConstraint(Power_SB_DISALLOW);
    
        /* Reset the write buffer so we can pass it back */
        object->writeBuf = (unsigned char *)object->writeBuf - object->writeCount;
        object->writeCallback(handle, (uint8_t*)object->writeBuf,
                              object->writeCount);
    
        Log_print2(Diags_USER1, "UART:(%p) Write canceled, "
                                "%d bytes written",
                 ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr,
                   object->writeCount);
    }
    
    /*!
     *  @brief  Function for reading from UART interface.
     *
     *  The function will enable the RX, enable all RX interrupts and disallow
     *  chip from going into standby.
     *
     *  @pre    UARTCC2650_open() has to be called first.
     *          Calling context: Hwi and Swi (only if using ::UART_MODE_CALLBACK), Task
     *
     *  @param  handle A UART handle returned from UARTCC2650_open()
     *
     *  @param  *buffer  Pointer to read buffer
     *
    *  @param  size  Number of bytes to read. If ::UARTCC2650_RETURN_PARTIAL_ENABLE
     *                has been set, the read will
     *                return if the reception is inactive for a 32-bit period
     *                (i.e. before all bytes are received).
     *
     *  @return Number of samples read
     *
     *  @sa     UARTCC2650_open(), UARTCC2650_readCancel()
     */
    int UARTCC2650_read(UART_Handle handle, void *buffer, size_t size)
    {
        unsigned int                     key;
        UARTCC2650_Object                *object;
        UARTCC2650_HWAttrs const         *hwAttrs;
    
        /* Get the pointer to the object */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Disable preemption while checking if the uart is in use. */
        key = Hwi_disable();
        if (object->readSize) {
            Hwi_restore(key);
    
            Log_warning1("UART:(%p) Could not read data, uart in use.",
                 ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr);
    
            return (UART_ERROR);
        }
    
        /* Set readSize */
        object->readSize = size;
    
        /* Update the status of the UART module */
        object->status = UART_OK;
    
        /* Save the data to be read and restore interrupts. */
        object->readBuf = buffer;
        object->readCount = 0;
    
        Hwi_restore(key);
    
        /* Set constraint for sleep to guarantee transaction */
        Power_setConstraint(Power_SB_DISALLOW);
    
        /* Enable RX */
        HWREG(UART0_BASE + UART_O_CTL) |= UART_CTL_RXE;
    
        /* Enable RX interrupts */
        UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT |
                      UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE);
    
        /* If readMode is blocking, block and get the status. */
        if (object->readMode == UART_MODE_BLOCKING) {
            /* Pend on semaphore and wait for Hwi to finish. */
            if (!Semaphore_pend(Semaphore_handle(&(object->readSem)),
                                object->readTimeout)) {
                /* Semaphore timed out, make the read empty and log the read. */
                object->readSize = 0;
    
                Log_print2(Diags_USER1, "UART:(%p) Read timed out, %d bytes read",
                         ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr,
                           object->readCount);
    
            }
            /* return the numbers of samples read */
            return (object->readCount);
        }
    
        return (0);
    }
    
    /*
     *  ======== UARTCC2650_readPolling ========
     */
    int UARTCC2650_readPolling(UART_Handle handle, void *buf, size_t size)
    {
        /* Not supported */
        return (UARTCC2650_CMD_UNDEFINED);
    }
    
    /*!
     *  @brief Function that cancel UART read. Will disable all RX interrupt,
     *         disable
     *         RX and allow standby. Should also be called after a succeeding UART
     *         read if no more bytes are expected and standby is wanted.
     *
     *  @pre    UARTCC2650_open() has to be called first.
     *          Calling context: Task
     *
     *  @param handle         The UART_Handle for ongoing write.
     */
    void UARTCC2650_readCancel(UART_Handle handle)
    {
        unsigned int                 key;
        UARTCC2650_Object            *object;
        UARTCC2650_HWAttrs const     *hwAttrs;
    
        /* Get the pointer to the object */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Disable interrupts to avoid reading data while changing state. */
        key = Hwi_disable();
    
        /* Return if there is no read. */
        if (!object->readSize) {
            Hwi_restore(key);
            return;
        }
    
        /* Set size = 0 to prevent reading and restore interrupts. */
        object->readSize = 0;
        Hwi_restore(key);
    
        /* Disable RX interrupts */
        UARTIntDisable(hwAttrs->baseAddr, UART_INT_OE | UART_INT_BE | UART_INT_PE |
                                          UART_INT_FE | UART_INT_RT | UART_INT_RX);
    
        /* Disable RX */
        HWREG(UART0_BASE + UART_O_CTL) &= ~(UART_CTL_RXE);
    
        /* Release constraint since transaction is done */
        Power_releaseConstraint(Power_SB_DISALLOW);
    
        /* Reset the read buffer so we can pass it back */
        object->readBuf = (unsigned char *)object->readBuf - object->readCount;
        object->readCallback(handle, object->readBuf, object->readCount);
    
        Log_print2(Diags_USER1, "UART:(%p) Read canceled, "
                                "%d bytes read",
                 ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr,
                   object->readCount);
    }
    
    /*
     *  ======== UARTCC2650_initHW ========
     *  This functions initializes the UART hardware module.
     *
     *  @pre    Function assumes that the UART handle is pointing to a hardware
     *          module which has already been opened.
     */
    static void UARTCC2650_initHw(UART_Handle handle) {
        UARTCC2650_Object *object;
        UARTCC2650_HWAttrs const *hwAttrs;
        Types_FreqHz freq;
        uint32_t rxFifoThreshold[] = {
            UART_FIFO_RX1_8,
            UART_FIFO_RX2_8,
            UART_FIFO_RX4_8,
            UART_FIFO_RX6_8,
            UART_FIFO_RX7_8
        };
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /* Disable UART function. */
        UARTDisable(hwAttrs->baseAddr);
    
        /* Disable all UART module interrupts. */
        UARTIntDisable(hwAttrs->baseAddr, UART_INT_OE | UART_INT_BE | UART_INT_PE |
                                          UART_INT_FE | UART_INT_RT | UART_INT_TX |
                                          UART_INT_RX | UART_INT_CTS);
    
        /* Clear all UART interrupts */
        UARTIntClear(hwAttrs->baseAddr, UART_INT_OE | UART_INT_BE | UART_INT_PE |
                                        UART_INT_FE | UART_INT_RT | UART_INT_TX |
                                        UART_INT_RX | UART_INT_CTS);
    
        /* Set the FIFO level to 7/8 empty and 4/8 full. The setting was initially
         * 7/8 full, but has been changed to 4/8 full. Consider implementing the
         * FIFO levels as parameters in struct.
         */
        UARTFIFOLevelSet(hwAttrs->baseAddr, object->writeFifoThreshold, rxFifoThreshold[(object->readFifoThreshold/8)]);
    
        /* Configure frame format and baudrate */
        BIOS_getCpuFreq(&freq);
        UARTConfigSetExpClk(hwAttrs->baseAddr,
                            freq.lo,
                            object->baudRate,
                           (dataLength[object->dataLength] |
                            stopBits[object->stopBits] |
                            parityType[object->parityType]));
    
        Log_print3(Diags_USER1, "UART:(%p) CPU freq: %d; UART baudrate to %d",
                                    hwAttrs->baseAddr,
                                    freq.lo,
                                    object->baudRate);
    
        /* Enable UART FIFOs */
        HWREG(UART0_BASE + UART_O_LCRH) |= UART_LCRH_FEN;
    
        /* Enable the UART module */
        HWREG(UART0_BASE + UART_O_CTL) |= UART_CTL_UARTEN;
    }
    
    /*
     *  ======== UARTCC2650_initIO ========
     *  This functions initializes the UART IOs.
     *
     *  @pre    Function assumes that the UART handle is pointing to a hardware
     *          module which has already been opened.
     */
    static bool UARTCC2650_initIO(UART_Handle handle) {
        /* Locals */
        UARTCC2650_HWAttrs const *hwAttrs;
        PIN_Config uartPinTable[5];
        uint32_t i = 0;
    	UARTCC2650_Object *object;	
    	
        /* Get the pointer to the object and hwAttrs */
        hwAttrs = handle->hwAttrs;
        object = handle->object;
    	
        /* Build local list of pins, allocate through PIN driver and map HW ports */
        /* Make sure UART_TX pin is driven high after calling PIN_open(...) until
        *  we've set the correct peripheral muxing in PINCC26XX_setMux(...)
        *  This is to avoid falling edge glitches when configuring the UART_TX pin.
        */
    	//--DD feb 28 2018 
    	// Added a new property to select a TX/RX pins. To select the new pins close the port and open it with new params.custom value.
    	
    	switch (object->pinSel) {
    		case 0: 
    			uartPinTable[i++] = hwAttrs->rxPin | PIN_INPUT_EN;
    			uartPinTable[i++] = hwAttrs->txPin | PIN_INPUT_DIS | PIN_PUSHPULL | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH;
                            break;
    		case 1: 	
    			uartPinTable[i++] = hwAttrs->rxPinAlt1 | PIN_INPUT_EN;
    			uartPinTable[i++] = hwAttrs->txPinAlt1 | PIN_INPUT_DIS | PIN_PUSHPULL | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH;
    			break;
    		default: 
    			uartPinTable[i++] = hwAttrs->rxPin | PIN_INPUT_EN;
    			uartPinTable[i++] = hwAttrs->txPin | PIN_INPUT_DIS | PIN_PUSHPULL | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH;
                            break;
    	}
    	
    //	uartPinTable[i++] = hwAttrs->rxPinAlt1 | PIN_INPUT_EN;
    //	uartPinTable[i++] = hwAttrs->txPinAlt1 | PIN_INPUT_DIS | PIN_PUSHPULL | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH;
    	
    	
        if(hwAttrs->ctsPin != PIN_UNASSIGNED && hwAttrs->rtsPin != PIN_UNASSIGNED) {
            // If both CTS and RTS are assigned pins -> enable hardware flow control
            // TODO: bEnableHwFlowControl = 1;
            uartPinTable[i++] = hwAttrs->ctsPin | PIN_INPUT_EN;
            uartPinTable[i++] = hwAttrs->rtsPin | PIN_PUSHPULL;
        }
        /* Terminate pin list */
        uartPinTable[i++] = PIN_TERMINATE;
    
        /* Open and assign pins through pin driver */
        hPin = PIN_open(&pinState, uartPinTable);
    
        /* Are pins already allocated */
        if (!hPin) {
            return false;
        }
    
        /* Set IO muxing for the UART pins */
    //    PINCC26XX_setMux(hPin, hwAttrs->rxPin, IOC_PORT_MCU_UART0_RX);
    //   PINCC26XX_setMux(hPin, hwAttrs->txPin, IOC_PORT_MCU_UART0_TX);
    //    PINCC26XX_setMux(hPin, hwAttrs->rxPinAlt1, IOC_PORT_MCU_UART0_RX);
    //    PINCC26XX_setMux(hPin, hwAttrs->txPinAlt1, IOC_PORT_MCU_UART0_TX);
    
        PINCC26XX_setMux(hPin, (PIN_Id) (uartPinTable[0]&0x000000FF), IOC_PORT_MCU_UART0_RX);
        PINCC26XX_setMux(hPin, (PIN_Id) (uartPinTable[1]&0x000000FF), IOC_PORT_MCU_UART0_TX);
    
        
        
        if(hwAttrs->ctsPin != PIN_UNASSIGNED && hwAttrs->rtsPin != PIN_UNASSIGNED) {
            PINCC26XX_setMux(hPin, hwAttrs->ctsPin, IOC_PORT_MCU_UART0_CTS);
            PINCC26XX_setMux(hPin, hwAttrs->rtsPin, IOC_PORT_MCU_UART0_RTS);
        }
    
        /* Success */
        return true;
    }
    
    
    /*
     *  ======== uartPostNotify ========
     *  This functions is called to notify the UART driver of an ongoing transition
     *  out of sleep mode.
     *
     *  @pre    Function assumes that the UART handle (clientArg) is pointing to a
     *          hardware module which has already been opened.
     */
    Power_NotifyResponse uartPostNotify(Power_Event eventType, uint32_t clientArg)
    {
        /* Reconfigure the hardware if returning from sleep */
        if(eventType == Power_AWAKE_STANDBY) {
            UARTCC2650_initHw((UART_Handle) clientArg);
        }
        return Power_NOTIFYDONE;
    }
    

    CC2650 UART driver is attached

    When I use the test BSL mode before the main treads starts everything is fine.

    /**************************************************************************************************
    *
    * @fn msa_task
    *
    * @brief Application task entry point for the TIMAC Sample Appication.
    *
    * @param none
    *
    * @return void
    *
    **************************************************************************************************/
    void msa_task(void)
    {
    /* Initialize application */
    MSA_Init();

    #ifdef NV_RESTORE
    IntMasterDisable();
    MSA_NvRestore();
    IntMasterEnable();
    #endif

    #ifdef PA_LNA_CC2592
    {
    int8 power = 20;

    /* Set TX power */
    MAC_MlmeSetReq(MAC_PHY_TRANSMIT_POWER_SIGNED, &power);
    }
    #endif /* PA_LNA_CC2592 */

    msa_IsStarted = TRUE;
    msa_IsDirectMsg = MSA_DIRECT_MSG_ENABLED;
    msa_DevShortAddr = MSA_DEV_SHORT_ADDR;
    /* Setup MAC_SHORT_ADDRESS - obtained from Association */
    MAC_MlmeSetReq(MAC_SHORT_ADDRESS, &msa_DevShortAddr);
    MSA_DeviceStartup();
    commInterfaceInit();
    uartStartReading();
    initAntSwitch();
    InitBslModePins();


    TestBSLMode(); // when the BSL communication happens here. No bytes are missed


    /* No return from MSA process */
    MSA_Process();
    }



    void TestBSLMode(void)
    {
    // TEST BSL MODE
    uint32 wCounter;
    uint8 bCnt1;
    uint8 testBuf[128];
    uint8 testRxBuf[128];

    while(1)
    {

    progInterfaceInit(); // initialize the second uart
    uartStartReading();
    Reset_MSP430F5419A_BSL();
    wCounter = 5000000;
    while(wCounter--);
    MSP430_BSL_Erase(testBuf);
    serTxNbr = serialTxData(testBuf,(uint16_t)6);
    wCounter = 700000;
    while(wCounter--);
    bCnt1 = (uint8)getNbrRxBytes();
    serialRxData(testRxBuf,(size_t) bCnt1); // copy the MCU response in the RF packet data.
    wCounter = 500000;
    while(wCounter--);
    SetMSP430_BSL_Password(testBuf);
    serTxNbr = serialTxData(testBuf,(uint16_t)38);
    wCounter = 20000;
    while(wCounter--);
    bCnt1 = (uint8)getNbrRxBytes();
    serialRxData(testRxBuf,(size_t) bCnt1); // copy the MCU response in the RF packet data.
    wCounter = 500000;
    while(wCounter--);
    GetMSP430_BSL_Version(testBuf);
    serTxNbr = serialTxData(testBuf,(uint16_t)6);
    wCounter = 10000;
    while(wCounter--);
    bCnt1 = (uint8)getNbrRxBytes();
    serialRxData(testRxBuf,(size_t) bCnt1); // copy the MCU response in the RF packet data.
    wCounter = 500000;
    while(wCounter--);
    MSP430_BSL_Get_Buf_Size(testBuf);
    serTxNbr = serialTxData(testBuf,(uint16_t)6);
    wCounter = 20000;
    while(wCounter--);
    bCnt1 = (uint8)getNbrRxBytes();
    serialRxData(testRxBuf,(size_t) bCnt1); // copy the MCU response in the RF packet data.
    wCounter = 5000000;
    while(wCounter--);
    }
    // END of Test BSL

    }

  • Thanks for the code snippets, I can't see anything that seem really strange, but it looks to me the flow is not the same in both cases (in terms of delay and order), is this correct?

    Are you experiencing the same problem when using the original driver?

    Just a note: Seems like you did your own driver to be able to use the UART on two ports. You could do the same with the original driver by defining two entries in UARTCC26XX_HwAttrs and UART_Config where the only difference is the hwAttrs is the pins. You then open either object[0] or object[1] depending on what port you want to use.
  • Hi, 

    Thanks for the replay. 

    Setting the UART in UARTCC2650_RETURN_PARTIAL_ENABLE mode seems to fix the problem. 

    Thank you all for the support. 

    Now I have different problem with slow wake up from reset. I measured that it takes 122ms after reset for the RTOS / TIMAC to boot.

    Is there a way to make it faster? I'll post this in separate topic so we don't mess up this one.

  • Hi,

    That solution is quite interesting as the resulting buffer should be the same in the end so I would not expect this to solve it. I'm starting to wonder if there might be some kind of corner case going on here. When you start the initial read, how many bytes are you expecting to read?

    When you then read out the data at WriteProgramDataResp(), what is the status of the UART at this point? Have the RX callback been called before hitting this point? Having a second look at the code I realize that you simply wait for a specific amount of time before checking the answer, do you verify anywhere that the RX is actually done?
  • Hi,

    It doesn't make sense to me either.

    Basically I was messing with the code and the last thing I remember doing is that:)

    The number of RX bytes varies, that is why I wait for timeout.

    Does the TI RTOS have any conditioning done in the ISR before calling the RX callback?

    When I was debugging and had a breakpoint in the RX callback on rare occasions it triggered on the first byte but if the breakpoint was after the timeout the first byte, which is always 0x00, was always missing.

  • The UART driver do some minor things before calling the RX callback depending on how you reached the RX callback (timeout, error, all done etc). Just for testing, have you tried if you get the first byte if you do only single byte reads (no timeouts)?

    Also, I don't see the part of your code where you set the RX timeout, where do you set this?
    Could you provide the code for "uartStartReading" and "WriteProgramDataResp" as well?
  • Hi, 

    The RX/TX timeouts are set in the UART_Params_init() to the default ones 

    readTimeout = BIOS_WAIT_FOREVER;
    writeTimeout = BIOS_WAIT_FOREVER;

    Here are the functions :

    uint8 WriteProgramDataResp(uint8 *pData)
    {
    uint8 bCnt = 0;

    pData[0] = WTTTS_PACKET_HEADER; // packet header
    pData[1] = BSL_PROGRAM_DATA; // packet type
    pData[2] = 0x00; // Sequence Number
    pData[3] = 0x00; //WTTTS Timestamp Byte 1
    pData[4] = 0x00; //WTTTS Timestamp Byte 2
    bCnt = (uint8)getNbrRxBytes();
    pData[5] = bCnt; //Packet Size
    serialRxData(&pData[6],(size_t) bCnt); // copy the MCU response in the RF packet data.
    bCnt = 6+pData[5];
    pData[bCnt] = 0x00; //Checksum
    bCnt++;
    return bCnt;

    }

    void uartStartReading(void)
    {
    rxBytes = UARTCC2650_read(handle, uartRxBuf, UART_READ_BYTES);
    }


    int UARTCC2650_read(UART_Handle handle, void *buffer, size_t size)
    {
    unsigned int key;
    UARTCC2650_Object *object;
    UARTCC2650_HWAttrs const *hwAttrs;

    /* Get the pointer to the object */
    object = handle->object;
    hwAttrs = handle->hwAttrs;

    /* Disable preemption while checking if the uart is in use. */
    key = Hwi_disable();
    if (object->readSize) {
    Hwi_restore(key);

    Log_warning1("UART:(%p) Could not read data, uart in use.",
    ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr);

    return (UART_ERROR);
    }

    /* Set readSize */
    object->readSize = size;

    /* Update the status of the UART module */
    object->status = UART_OK;

    /* Save the data to be read and restore interrupts. */
    object->readBuf = buffer;
    object->readCount = 0;

    Hwi_restore(key);

    /* Set constraint for sleep to guarantee transaction */
    Power_setConstraint(Power_SB_DISALLOW);

    /* Enable RX */
    HWREG(UART0_BASE + UART_O_CTL) |= UART_CTL_RXE;

    /* Enable RX interrupts */
    UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT |
    UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE);

    /* If readMode is blocking, block and get the status. */
    if (object->readMode == UART_MODE_BLOCKING) {
    /* Pend on semaphore and wait for Hwi to finish. */
    if (!Semaphore_pend(Semaphore_handle(&(object->readSem)),
    object->readTimeout)) {
    /* Semaphore timed out, make the read empty and log the read. */
    object->readSize = 0;

    Log_print2(Diags_USER1, "UART:(%p) Read timed out, %d bytes read",
    ((UARTCC2650_HWAttrs const *)(handle->hwAttrs))->baseAddr,
    object->readCount);

    }
    /* return the numbers of samples read */
    return (object->readCount);
    }

    return (0);
    }

    Thanks

  • Is there a reason why you doing UART read in callback mode? While it is not super clear to my where you do read the data or what the readCallback does, I don't see anything in place that makes sure that the read has actually finished before trying to read the data (I'm going on comments here to figure out where you read the UART response). 

    Furthermore, the driver inside the tirtos 2_11 example is very old and there have been many changes to the driver to make it better. While you have found a solution that works for you, if you have time to test it out you could try pulling in a newer UART driver and see if that makes a difference. The newer versions include a ring buffer and some other changes so you would have to do some modifications to the board file setting up the UART HW attributes.