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.

CC2640 UART Hardware Flow Control

How do I enable (or disable) UART hardware flow control in BLE Stack 2.0? I looked at "struct UART_Params" in UART.h, and there is none attribute relating to flow control.

  • Hello. The current RTOS UART driver does not support hardware flow control. This should be implmemented in an upcoming release.
  • Hi Tim,

    Thanks for the reply. We are porting some cc254x projects for client which originally require UART flow control. Is there a way to quick hack the current release to enable UART flow control - e.g. by setting some h/w registers directly? Waiting for next release, unless it is due next couple wks, has significant impact to us.

    ../ming

  • Hi Ming,

    The TI RTOS released planned for start of May will have a driver with UART flow control built in in addition to some other fixes (thread safe handling of power constraints).

    I have attached a preliminary version to this thread that you can use to work with until then but it is not guaranteed that this will work 100% or that it will be the final version.

    You will need to add the .c files to your project to override the UART driver which is linked in by the pre-compiled library in our example projects.

    Regards,

    Svend

    /*
     * 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/UARTCC26XX.h>
    #include <ti/drivers/pin/PINCC26XX.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>
    
    /* UARTCC26XX functions */
    void         UARTCC26XX_close(UART_Handle handle);
    int          UARTCC26XX_control(UART_Handle handle, unsigned int cmd, void *arg);
    void         UARTCC26XX_init(UART_Handle handle);
    UART_Handle  UARTCC26XX_open(UART_Handle handle, UART_Params *params);
    int          UARTCC26XX_read(UART_Handle handle, void *buffer, size_t size);
    int          UARTCC26XX_readPolling(UART_Handle handle, void *buf, size_t size);
    void         UARTCC26XX_readCancel(UART_Handle handle);
    int          UARTCC26XX_write(UART_Handle handle, const void *buffer,
                                size_t size);
    int          UARTCC26XX_writePolling(UART_Handle handle, const void *buf,
                                       size_t size);
    void         UARTCC26XX_writeCancel(UART_Handle handle);
    
    /* UARTCC26XX internal functions */
    static void  UARTCC26XX_initHw(UART_Handle handle);
    static bool  UARTCC26XX_initIO(UART_Handle handle);
    static Power_NotifyResponse uartPostNotify(Power_Event eventType, uint32_t clientArg);
    
    /* UART function table for UARTCC26XX implementation */
    const UART_FxnTable UARTCC26XX_fxnTable = {
        UARTCC26XX_close,
        UARTCC26XX_control,
        UARTCC26XX_init,
        UARTCC26XX_open,
        UARTCC26XX_read,
        UARTCC26XX_readPolling,
        UARTCC26XX_readCancel,
        UARTCC26XX_write,
        UARTCC26XX_writePolling,
        UARTCC26XX_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 */
    };
    
    /* Guard to avoid power constraints getting out of sync */
    static volatile bool uartPowerConstraint;
    
    /*
     *  ======================== 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))
    #define MAX(a,b) (((a)>(b))?(a):(b))
    
    /*
     * Function for checking whether flow control is enabled.
     */
    static inline bool isFlowControlEnabled(UARTCC26XX_HWAttrs const  *hwAttrs) {
        return ((hwAttrs->ctsPin != PIN_UNASSIGNED) && (hwAttrs->rtsPin != PIN_UNASSIGNED));
    }
    
    /*
     * Ensure safe setting of the standby disallow constraint.
     */
    static inline void threadSafeStdbyDisSet() {
        unsigned int  key;
    
        /* Disable interrupts */
        key = Hwi_disable();
    
        if (!uartPowerConstraint) {
          /* Set constraints to guarantee operation */
          Power_setConstraint(Power_SB_DISALLOW);
          uartPowerConstraint = true;
        }
    
        /* Re-enable interrupts */
        Hwi_restore(key);
    }
    
    /*
     * Ensure safe releasing of the standby disallow constraint.
     */
    static inline void threadSafeStdbyDisRelease() {
        unsigned int  key;
    
        /* Disable interrupts */
        key = Hwi_disable();
    
        if (uartPowerConstraint) {
            /* release constraint since operation is done */
            Power_releaseConstraint(Power_SB_DISALLOW);
            uartPowerConstraint = false;
        }
    
        /* Re-enable interrupts */
        Hwi_restore(key);
    }
    
    /*
     *  ======== writeSemCallback ========
     *  Simple callback to post a semaphore for the blocking mode.
     */
    static void writeSemCallback(UART_Handle handle, void *buffer, size_t count)
    {
        UARTCC26XX_Object *object = handle->object;
    
        Log_print1(Diags_USER1, "UART:(%p) posting write semaphore",
                    ((UARTCC26XX_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)
    {
        UARTCC26XX_Object *object = handle->object;
    
        Log_print1(Diags_USER1, "UART:(%p) posting read semaphore",
                    ((UARTCC26XX_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)
    {
        UARTCC26XX_Object           *object;
        UARTCC26XX_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;
        UARTCC26XX_Object           *object;
        UARTCC26XX_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)
    {
        UARTCC26XX_Object           *object;
        UARTCC26XX_HWAttrs const    *hwAttrs;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        /*       Release power constraint. */
        threadSafeStdbyDisRelease();
    
        /*       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)
    {
        UARTCC26XX_Object           *object;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Ensure that the clock is stopped so we can set a new timeout */
        Clock_stop((Clock_Handle) &(object->txFifoEmptyClk));
    
        /* 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
         *       - +1 to "map" from stopBits to actual number of bits
         *       - 1000000 so we get 1 us resolution
         *       - 100 (100us) for margin
         */
        unsigned int writeTimeoutUs = (numOfDataInFifo*(1+5+(object->dataLength)+(stopBits[object->stopBits]+1))*1000000)/object->baudRate + 100;
        /*   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)
    {
        UARTCC26XX_Object           *object;
        UARTCC26XX_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));
    
        /*   Function verifies that the FIFO is empty via BUSY flag */
        /*   If not yet ready start the periodic timer and wait another period*/
        /*   Return.. */
        if(UARTBusy(hwAttrs->baseAddr)){
            /* The UART is still busy.
             * Wait 500 us before checking again or 1 tick period if the
             * Clock_tickPeriod is larger than 500 us.
             */
            Clock_setTimeout((Clock_Handle) &(object->txFifoEmptyClk), MAX((500/Clock_tickPeriod),1));
            Clock_start((Clock_Handle) &(object->txFifoEmptyClk));
            return;
        }
    
        /* Release constraint since transaction is done */
        threadSafeStdbyDisRelease();
    
        /* 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);
    }
    
    /*
     *  ======== writeTxFifoFlush ========
     *  Write cancelled or timed out, the TX FIFO must be flushed out.
     *
     *  This function is called either from writeCancel or when a blocking write
     *  has timed out. The HW does not support a simple API for flushing the TX FIFO
     *  so a workaround is done in SW.
     *
     *  @pre The TX FIFO empty clock must have been started in blocking mode.
     *
     *  @param object         Pointer to UART object
     *  @param hwAttrs        Pointer to UART hwAttrs
     */
    static void writeTxFifoFlush(UARTCC26XX_Object  *object, UARTCC26XX_HWAttrs const  *hwAttrs)
    {
        /*It is not possible to flush the TX FIFO with simple write to HW, doing workaround:
         * 0. Disable TX interrupt
         */
        UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
        /* 1. Ensure TX IO will stay high when connected to GPIO */
        PIN_setOutputEnable(hPin, hwAttrs->txPin, 1);
        PIN_setOutputValue(hPin, hwAttrs->txPin, 1);
        /* 2. Disconntect tx from IO, and set it as "GPIO" */
        PINCC26XX_setMux(hPin, hwAttrs->txPin, IOC_PORT_GPIO);
        /* 3. Disconnect cts */
        PINCC26XX_setMux(hPin, hwAttrs->ctsPin, IOC_PORT_GPIO);
        /*4. Wait for TX FIFO to become empty.
         *    CALLBACK: Idle until the TX FIFO is empty, i.e. no longer busy.
         *    BLOCKING: Periodically check if TX is busy emptying the FIFO.
         *              Must be handled at TX FIFO empty clock timeout:
         *                - the timeout/finish function must check the status
         */
        if(object->writeMode == UART_MODE_CALLBACK) {
            /* Wait until the TX FIFO is empty. CALLBACK mode can be used from
             * hwi/swi context, so we cannot use semaphore..
             */
            while(UARTBusy(hwAttrs->baseAddr));
        } else { /* i.e. UART_MODE_BLOCKING */
            /* Pend on semaphore again..(this time forever since we are flushing
             * TX FIFO and nothing should be able to stop it..
             */
            Semaphore_pend(Semaphore_handle(&(object->writeSem)), BIOS_WAIT_FOREVER);
        }
        /* 5. Revert to active pins before returning */
        PINCC26XX_setMux(hPin, hwAttrs->txPin, IOC_PORT_MCU_UART0_TX);
        if(isFlowControlEnabled(hwAttrs)) {
            PINCC26XX_setMux(hPin, hwAttrs->ctsPin, IOC_PORT_MCU_UART0_CTS);
        }
    }
    
    /*
     *  ======== UARTCC26XX_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 UARTCC26XX_hwiIntFxn(UArg arg)
    {
        unsigned long            intStatus;
        unsigned long            errStatus;
        UARTCC26XX_Object        *object;
        UARTCC26XX_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(UARTCC26XX_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 */
            UARTCC26XX_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 {
                /* RX interrupt, since CTS is handled by HW */
                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 ((intStatus & UART_INT_TX) && 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.
                 * +UART_TH_FIFO_1_8 because it is 4 bytes left in TX FIFO when the TX FIFO
                 * threshold interrupt occurs.
                 */
                 startTxFifoEmptyClk((UART_Handle)arg, (writtenLast+UART_TH_FIFO_1_8));
            }
        }
    }
    
    /*!
     *  @brief UART CC26XX initialization
     *
     *  @pre    Calling context: Hwi, Swi, Task, Main
     *
     *  @param handle  A UART_Handle
     *
     */
    void UARTCC26XX_init(UART_Handle handle)
    {
        UARTCC26XX_Object           *object;
    
        /* Get the pointer to the object */
        object = handle->object;
        object->opened = false;
    
        /* Init the power constraint flag. */
        uartPowerConstraint = 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     UARTCC26XX_close()
     */
    UART_Handle UARTCC26XX_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;
        UARTCC26XX_Object               *object;
        UARTCC26XX_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;
    
        /* 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_4_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 */
        UARTCC26XX_initHw(handle);
    
        /* Configure IOs, make sure it was successful */
        if(!UARTCC26XX_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, UARTCC26XX_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    UARTCC26XX_open() had to be called first.
     *          Calling context: Task
     *
     *  @param  handle  A UART_Handle returned from UART_open()
     *
     *  @sa     UARTCC26XX_open
     */
    void UARTCC26XX_close(UART_Handle handle)
    {
        unsigned int                 key;
        UARTCC26XX_Object            *object;
        UARTCC26XX_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));
        if (object->writeMode == UART_MODE_BLOCKING) {
            Semaphore_destruct(&(object->writeSem));
        }
        if (object->readMode == UART_MODE_BLOCKING) {
            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    UARTCC26XX_open() has to be called first.
     *          Calling context: Hwi, Swi, Task
     *
     *  @param  handle A UART handle returned from UARTCC26XX_open()
     *
     *  @param  cmd  The command to execute, supported commands are:
     *          | Command                               | Description             |
     *          |-------------------------------------- |-------------------------|
     *          | ::UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE | Enable RETURN_PARTIAL  |
     *          | ::UARTCC26XX_CMD_RETURN_PARTIAL_DISABLE| Disable RETURN_PARTIAL |
     *
     *  @param  *arg  Pointer to command arguments, currently not in use, set to NULL.
     *
     *  @return ::UART_STATUS_SUCCESS if success, or error code if error.
     */
    int UARTCC26XX_control(UART_Handle handle, unsigned int cmd, void *arg)
    {
        /* Locals */
        UARTCC26XX_Object            *object;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Initialize return value*/
    	int ret = UART_STATUS_UNDEFINEDCMD;
        /* Do command*/
    	switch(cmd) {
    
    		case UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE:
    			/* Enable RETURN_PARTIAL */
    			object->readRetPartial = true;
                ret = UART_STATUS_SUCCESS;
    			break;
    
    		case UARTCC26XX_CMD_RETURN_PARTIAL_DISABLE:
    			/* Disable RETURN_PARTIAL */
    			object->readRetPartial = false;
                ret = UART_STATUS_SUCCESS;
    			break;
    
    		default:
                /* This command is not defined */
                ret = UART_STATUS_UNDEFINEDCMD;
    			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    UARTCC26XX_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 UARTCC26XX_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 UARTCC26XX_write(UART_Handle handle, const void *buffer, size_t size)
    {
        unsigned int                     key;
        UARTCC26XX_Object                *object;
        UARTCC26XX_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.",
                        ((UARTCC26XX_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 */
        threadSafeStdbyDisSet();
    
        /* Enable TX */
        HWREG(UART0_BASE + UART_O_CTL) |= UART_CTL_TXE;
    
        uint32_t writtenLast = size;
        /* 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, writtenLast);
    
            /* 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)) {
                    /* Reset writeSize */
                    object->writeSize = 0;
    
                    /* Set status to TIMED_OUT */
                    object->status = UART_TIMED_OUT;
    
                    /* Workaround for flushing the TX FIFO */
                    writeTxFifoFlush(object, hwAttrs);
    
                    /* Release constraint */
                    threadSafeStdbyDisRelease();
    
                    Log_print2(Diags_USER1, "UART:(%p) Write timed out, %d bytes written",
                               ((UARTCC26XX_HWAttrs const *)(handle->hwAttrs))->baseAddr,
                               object->writeCount);
    
                    /* Return UART_ERROR to indicate something went wrong, object->status set to UART_TIMED_OUT*/
                    return UART_ERROR;
                }
                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. */
    
                    /* Starting a timer to enable the posting of semaphore used in writeTxFifoFlush.
                     * writtenLast in this case is equal to full TX FIFO. This is a conservative number as
                     * some of the data might have been sent.
                     */
                    startTxFifoEmptyClk((UART_Handle)handle, writtenLast);
    
                    /* Reset writeSize */
                    object->writeSize = 0;
    
                    /* Set status to TIMED_OUT */
                    object->status = UART_TIMED_OUT;
    
                    /* Workaround for flushing the TX FIFO */
                    writeTxFifoFlush(object, hwAttrs);
    
                    /* Release constraint */
                    threadSafeStdbyDisRelease();
    
                    Log_print2(Diags_USER1, "UART:(%p) Write timed out, %d bytes written",
                               ((UARTCC26XX_HWAttrs const *)(handle->hwAttrs))->baseAddr,
                               object->writeCount);
    
                    /* Return UART_ERROR to indicate something went wrong (object->status set to UART_TIMED_OUT)*/
                    return UART_ERROR;
                }
    
                /* 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    UARTCC26XX_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 ::UART_ERROR
     */
    int UARTCC26XX_writePolling(UART_Handle handle, const void *buf, size_t size)
    {
        /* Not supported */
        return (UART_ERROR);
    }
    
    /*!
     *  @brief Function that cancel UART write. Will disable TX interrupt, disable
     *         TX and allow standby.
     *
     *  @pre    UARTCC26XX_open() and has to be called first.
     *          Calling context: Task
     *
     *  @param handle         The UART_Handle for ongoing write.
     */
    void UARTCC26XX_writeCancel(UART_Handle handle)
    {
        unsigned int                key;
        UARTCC26XX_Object           *object;
        UARTCC26XX_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 nothing to write and TX FIFO is empty. */
        if ((!object->writeSize) && (!UARTBusy(hwAttrs->baseAddr))) {
            Hwi_restore(key);
            return;
        }
    
        /* Set size = 0 to prevent writing and restore interrupts. */
        object->writeSize = 0;
        Hwi_restore(key);
    
        /* If flow control is enabled, a workaround for flushing the fifo is needed..*/
        if (isFlowControlEnabled(hwAttrs)) {
            writeTxFifoFlush(object, hwAttrs);
        }
    
        /* Disable TX interrupt */
        UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
    
        /* Disable UART TX */
        HWREG(UART0_BASE + UART_O_CTL) &= ~(UART_CTL_TXE);
    
        /* Release constraint since transaction is done */
        threadSafeStdbyDisRelease();
    
        /* 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",
                 ((UARTCC26XX_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    UARTCC26XX_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 UARTCC26XX_open()
     *
     *  @param  *buffer  Pointer to read buffer
     *
    *  @param  size  Number of bytes to read. If ::UARTCC26XX_CMD_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     UARTCC26XX_open(), UARTCC26XX_readCancel()
     */
    int UARTCC26XX_read(UART_Handle handle, void *buffer, size_t size)
    {
        unsigned int                     key;
        UARTCC26XX_Object                *object;
        UARTCC26XX_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.",
                 ((UARTCC26XX_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 */
        threadSafeStdbyDisSet();
    
        /* 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;
    
                /* Set status to TIMED_OUT */
                object->status = UART_TIMED_OUT;
    
                Log_print2(Diags_USER1, "UART:(%p) Read timed out, %d bytes read",
                         ((UARTCC26XX_HWAttrs const *)(handle->hwAttrs))->baseAddr,
                           object->readCount);
    
            }
            /* return the numbers of samples read */
            return (object->readCount);
        }
    
        return (0);
    }
    
    /*
     *  ======== UARTCC26XX_readPolling ========
     */
    int UARTCC26XX_readPolling(UART_Handle handle, void *buf, size_t size)
    {
        /* Not supported */
        return (UART_ERROR);
    }
    
    /*!
     *  @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    UARTCC26XX_open() has to be called first.
     *          Calling context: Task
     *
     *  @param handle         The UART_Handle for ongoing write.
     */
    void UARTCC26XX_readCancel(UART_Handle handle)
    {
        unsigned int                 key;
        UARTCC26XX_Object            *object;
        UARTCC26XX_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 */
        threadSafeStdbyDisRelease();
    
        /* 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",
                 ((UARTCC26XX_HWAttrs const *)(handle->hwAttrs))->baseAddr,
                   object->readCount);
    }
    
    /*
     *  ======== UARTCC26XX_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 UARTCC26XX_initHw(UART_Handle handle) {
        UARTCC26XX_Object *object;
        UARTCC26XX_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;
    
        /* If Flow Control is enabled, configure hardware controlled flow control */
        if(isFlowControlEnabled(hwAttrs)) {
            HWREG(UART0_BASE + UART_O_CTL) |= (UART_CTL_CTSEN | UART_CTL_RTSEN);
        }
    }
    
    /*
     *  ======== UARTCC26XX_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 UARTCC26XX_initIO(UART_Handle handle) {
        /* Locals */
        UARTCC26XX_HWAttrs const *hwAttrs;
        PIN_Config uartPinTable[5];
        uint32_t i = 0;
    
        /* Get the pointer to the object and hwAttrs */
        hwAttrs = handle->hwAttrs;
    
        /* Build local list of pins, allocate through PIN driver and map HW ports */
        uartPinTable[i++] = hwAttrs->rxPin | PIN_INPUT_EN;
        /* 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.
        */
        uartPinTable[i++] = hwAttrs->txPin | PIN_INPUT_DIS | PIN_PUSHPULL | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH;
        if(isFlowControlEnabled(hwAttrs)) {
            uartPinTable[i++] = hwAttrs->ctsPin | PIN_INPUT_EN;
            /* Avoiding glitches on the RTS, see comment for TX pin above. */
            uartPinTable[i++] = hwAttrs->rtsPin | PIN_INPUT_DIS | PIN_PUSHPULL | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH;
        }
        /* 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);
        if(isFlowControlEnabled(hwAttrs)) {
            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) {
            UARTCC26XX_initHw((UART_Handle) clientArg);
        }
        return Power_NOTIFYDONE;
    }
    

    UARTCC26XX.h

    /*
     * Copyright (c) 2014, 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.
     */
    
    /*
     *  ====================== Board.c =============================================
     *  This file is responsible for setting up the board specific items for the
     *  SRF06EB with the CC2650EM_7ID board.
     */
    
    
    /*
     *  ====================== Includes ============================================
     */
    #include <inc/hw_memmap.h>
    #include <inc/hw_ints.h>
    #include <driverlib/ioc.h>
    #include <driverlib/udma.h>
    #include <xdc/std.h>
    #include <xdc/runtime/System.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/PIN.h>
    #include "Board.h"
    
    /*
     *  ========================= IO driver initialization =========================
     *  From main, PIN_init(BoardGpioInitTable) should be called to setup safe
     *  settings for this board.
     *  When a pin is allocated and then de-allocated, it will revert to the state
     *  configured in this table.
    */
    PIN_Config BoardGpioInitTable[] = {
    
        Board_LED1       | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW   | PIN_PUSHPULL | PIN_DRVSTR_MAX,     /* LED initially off             */
        Board_LED2       | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW   | PIN_PUSHPULL | PIN_DRVSTR_MAX,     /* LED initially off             */
        Board_LED3       | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW   | PIN_PUSHPULL | PIN_DRVSTR_MAX,     /* LED initially off             */
        Board_LED4       | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW   | PIN_PUSHPULL | PIN_DRVSTR_MAX,     /* LED initially off             */
        Board_KEY_SELECT | PIN_INPUT_EN  | PIN_PULLUP | PIN_HYSTERESIS,                             /* Button is active low          */
        Board_KEY_UP     | PIN_INPUT_EN  | PIN_PULLUP | PIN_HYSTERESIS,                             /* Button is active low          */
        Board_KEY_DOWN   | PIN_INPUT_EN  | PIN_PULLUP | PIN_HYSTERESIS,                             /* Button is active low          */
        Board_KEY_LEFT   | PIN_INPUT_EN  | PIN_PULLUP | PIN_HYSTERESIS,                             /* Button is active low          */
        Board_KEY_RIGHT  | PIN_INPUT_EN  | PIN_PULLUP | PIN_HYSTERESIS,                             /* Button is active low          */
        Board_3V3_EN     | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW    | PIN_PUSHPULL,                     /* 3V3 domain off initially      */
        Board_LCD_MODE   | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH   | PIN_PUSHPULL,                     /* LCD pin high initially        */
        Board_LCD_RST    | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH   | PIN_PUSHPULL,                     /* LCD pin high initially        */
        Board_LCD_CSN    | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH   | PIN_PUSHPULL,                     /* LCD pin high initially        */
        Board_UART_TX    | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH   | PIN_PUSHPULL,                     /* UART TX pin at inactive level */
        PIN_TERMINATE                                                                               /* Terminate list                */
    };
    /*============================================================================*/
    
    /*
     *  ============================= UART begin ===================================
    */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(UART_config, ".const:UART_config")
    #pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs")
    #endif
    
    /* Include drivers */
    #include <ti/drivers/UART.h>
    #include <ti/drivers/uart/UARTCC26XX.h>
    
    /* UART objects */
    UARTCC26XX_Object uartCC26XXObjects[CC2650_UARTCOUNT];
    
    /* UART hardware parameter structure, also used to assign UART pins */
    const UARTCC26XX_HWAttrs uartCC26XXHWAttrs[CC2650_UARTCOUNT] = {
        {    /* 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
        },
    };
    
    /* UART configuration structure */
    const UART_Config UART_config[] = {
        { &UARTCC26XX_fxnTable, &uartCC26XXObjects[0], &uartCC26XXHWAttrs[0] },
        { NULL, NULL, NULL }
    };
    /*
     *  ============================= UART end =====================================
    */
    
    /*
     *  ============================= UDMA begin ===================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config")
    #pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs")
    #endif
    
    /* Include drivers */
    #include <ti/drivers/dma/UDMACC26XX.h>
    
    /* UDMA objects */
    UDMACC26XX_Object UdmaObjects[CC2650_UDMACOUNT];
    
    /* UDMA configuration structure */
    const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650_UDMACOUNT] = {
        { UDMA0_BASE, INT_UDMAERR, PERIPH_UDMA },
    };
    
    /* UDMA configuration structure */
    const UDMACC26XX_Config UDMACC26XX_config[] = {
        {&UdmaObjects[0], &udmaHWAttrs[0]},
        {NULL, NULL},
    };
    /*
     *  ============================= UDMA end =====================================
    */
    
    /*
     *  ========================== SPI DMA begin ===================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(SPI_config, ".const:SPI_config")
    #pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs")
    #endif
    
    /* Include drivers */
    #include <ti/drivers/spi/SPICC26XXDMA.h>
    
    /* SPI objects */
    SPICC26XX_Object spiCC26XXDMAObjects[CC2650_SPICOUNT];
    
    /* SPI configuration structure, describing which pins are to be used */
    const SPICC26XX_HWAttrs spiCC26XXDMAHWAttrs[CC2650_SPICOUNT] = {
        {   /* SRF06EB_CC2650_SPI0 */
            .baseAddr = SSI0_BASE,
            .intNum = INT_SSI0,
            .defaultTxBufValue = 0,
            .powerMngrId = PERIPH_SSI0,
            .rxChannelBitMask = 1<<UDMA_CHAN_SSI0_RX,
            .txChannelBitMask = 1<<UDMA_CHAN_SSI0_TX,
            .mosiPin = Board_SPI0_MOSI,
            .misoPin = Board_SPI0_MISO,
            .clkPin = Board_SPI0_CLK,
            .csnPin = Board_SPI0_CSN
        },
        {   /* SRF06EB_CC2650_SPI1 */
            .baseAddr = SSI1_BASE,
            .intNum = INT_SSI1,
            .defaultTxBufValue = 0,
            .powerMngrId = PERIPH_SSI1,
            .rxChannelBitMask  = 1<<UDMA_CHAN_SSI1_RX,
            .txChannelBitMask  = 1<<UDMA_CHAN_SSI1_TX,
            .mosiPin = Board_SPI1_MOSI,
            .misoPin = Board_SPI1_MISO,
            .clkPin = Board_SPI1_CLK,
            .csnPin = Board_SPI1_CSN
        }
    };
    
    /* SPI configuration structure */
    const SPI_Config SPI_config[] = {
        /* SRF06EB_CC2650_SPI0 */
        {&SPICC26XXDMA_fxnTable, &spiCC26XXDMAObjects[0], &spiCC26XXDMAHWAttrs[0]},
        /* SRF06EB_CC2650_SPI1 */
        {&SPICC26XXDMA_fxnTable, &spiCC26XXDMAObjects[1], &spiCC26XXDMAHWAttrs[1]},
        {NULL, NULL, NULL},
    };
    /*
     *  ========================== SPI DMA end =====================================
    */
    
    
    /*
     *  ========================== LCD begin =======================================
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(LCD_config, ".const:LCD_config")
    #pragma DATA_SECTION(lcdHWAttrs, ".const:lcdHWAttrs")
    #endif
    
    /* Include drivers */
    #include <ti/drivers/lcd/LCDDogm1286.h>
    
    /* LCD object */
    LCD_Object lcdObject;
    
    /* LCD hardware attribute structure */
    const LCD_HWAttrs lcdHWAttrs = {
        .LCD_initCmd = &LCD_initCmd,
        .lcdResetPin = Board_LCD_RST,       /* LCD reset pin */
        .lcdModePin = Board_LCD_MODE,       /* LCD mode pin */
        .lcdCsnPin = Board_LCD_CSN,         /* LCD CSn pin */
        .spiIndex = Board_SPI0
    };
    
    /* LCD configuration structure */
    const LCD_Config LCD_config = {&lcdObject, &lcdHWAttrs};
    /*
     *  ========================== LCD end =========================================
    */
    
    /*
     *  ========================== Crypto begin =======================================
     *  NOTE: The Crypto implementaion should be considered experimental and not validated!
    */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config")
    #pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs")
    #endif
    
    /* Include drivers */
    #include <ti/drivers/crypto/CryptoCC26XX.h>
    
    /* Crypto objects */
    CryptoCC26XX_Object cryptoCC26XXObjects[CC2650_CRYPTOCOUNT];
    
    /* Crypto configuration structure, describing which pins are to be used */
    const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650_CRYPTOCOUNT] = {
        {CRYPTO_BASE, INT_CRYPTO, PERIPH_CRYPTO}
    };
    
    /* Crypto configuration structure */
    const CryptoCC26XX_Config CryptoCC26XX_config[] = {
        {&cryptoCC26XXObjects[0], &cryptoCC26XXHWAttrs[0]},
        {NULL, NULL}
    };
    
    /*
     *  ========================== Crypto end =========================================
    */
    

    Board.h

  • Thank, Svend. I tried with your files and got the following compilation error:

    "C:/ti/tirtos_simplelink_2_11_01_09/packages/ti/drivers/uart/UARTCC26XX.c"
    "C:/ti/tirtos_simplelink_2_11_01_09/packages/ti/drivers/uart/UARTCC26XX.c", line 846: error #20: identifier "UART_STATUS_UNDEFINEDCMD" is undefined
    "C:/ti/tirtos_simplelink_2_11_01_09/packages/ti/drivers/uart/UARTCC26XX.c", line 850: error #20: identifier "UART_CMD_RESERVED" is undefined
    "C:/ti/tirtos_simplelink_2_11_01_09/packages/ti/drivers/uart/UARTCC26XX.c", line 853: error #20: identifier "UART_STATUS_SUCCESS" is undefined
    3 errors detected in the compilation of "C:/ti/tirtos_simplelink_2_11_01_09/packages/ti/drivers/uart/UARTCC26XX.c".
    
    >> Compilation failure
    gmake: *** [Drivers/UART/UARTCC26XX.obj] Error 1
    
    **** Build Finished ****
    

    I am using CCS. I replaced the UARTCC26XX set files in C:\ti\tirtos_simplelink_2_11_01_09\packages\ti\drivers\uart, and Board set files in C:\ti\tirtos_simplelink_2_11_01_09\packages\ti\boards\SRF06EB\CC2650EM_7ID.

    Also, want to confirm how to enable UART flow control: replace the line ".ctsPin = PIN_UNASSIGNED" with ".ctsPin = BOARD_UART_CTS", and the line ".rtsPin = PIN_UNASSIGNED" with ".rtsPin = BOARD_UART_RTS". Is that correct?

  • Correct, and then assign the pin you want to use in Board.h.

    The defines are still work-in-progress. Two of them were defined in the released UARTCC26XX.h file which the reserved currently needs to be added by you (e.g. defined as 1).

    Regards,
    Svend