knx/source/ti/drivers/uart/UARTCC26XX.c
Nanosonde e51b65f8c2 Squashed 'examples/knx-cc1310/coresdk_cc13xx_cc26xx/' content from commit 0d78d32
git-subtree-dir: examples/knx-cc1310/coresdk_cc13xx_cc26xx
git-subtree-split: 0d78d3280357416a5c0388148cda13717c9ffaa5
2020-10-21 10:00:49 +02:00

1684 lines
61 KiB
C

/*
* Copyright (c) 2015-2019, 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 <ti/drivers/dpl/DebugP.h>
#include <ti/drivers/dpl/HwiP.h>
#include <ti/drivers/dpl/SemaphoreP.h>
#include <ti/drivers/dpl/SwiP.h>
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC26XX.h>
#include <ti/drivers/uart/UARTCC26XX.h>
#include <ti/drivers/pin/PINCC26XX.h>
#include <ti/devices/DeviceFamily.h>
#include DeviceFamily_constructPath(inc/hw_memmap.h)
#include DeviceFamily_constructPath(inc/hw_ints.h)
#include DeviceFamily_constructPath(inc/hw_types.h)
#include DeviceFamily_constructPath(driverlib/uart.h)
#include DeviceFamily_constructPath(driverlib/sys_ctrl.h)
#include DeviceFamily_constructPath(driverlib/ioc.h)
#include DeviceFamily_constructPath(driverlib/aon_ioc.h)
/* UARTCC26XX functions */
void UARTCC26XX_close(UART_Handle handle);
int_fast16_t UARTCC26XX_control(UART_Handle handle, uint_fast16_t cmd,
void *arg);
void UARTCC26XX_init(UART_Handle handle);
UART_Handle UARTCC26XX_open(UART_Handle handle, UART_Params *params);
int_fast32_t UARTCC26XX_read(UART_Handle handle, void *buffer, size_t size);
int_fast32_t UARTCC26XX_readPolling(UART_Handle handle, void *buf,
size_t size);
void UARTCC26XX_readCancel(UART_Handle handle);
int_fast32_t UARTCC26XX_write(UART_Handle handle, const void *buffer,
size_t size);
int_fast32_t 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 int uartPostNotify(unsigned int eventType, uintptr_t eventArg, uintptr_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 */
};
/* Array for mapping of FIFO threshold defines selected by board files to: */
/* - TX FIFO threshold define used by driverlib */
/* FIFO threshold defines (enum UARTCC26XX_FifoThreshold) must be used as */
/* array index. */
/* Index 0 handles backward compatibility with legacy board files that don't */
/* select any FIFO thresholds. */
static const uint8_t txFifoThreshold[6] = {
UART_FIFO_TX1_8, /* UARTCC26XX_FIFO_THRESHOLD_DEFAULT */
UART_FIFO_TX1_8, /* UARTCC26XX_FIFO_THRESHOLD_1_8 */
UART_FIFO_TX2_8, /* UARTCC26XX_FIFO_THRESHOLD_2_8 */
UART_FIFO_TX4_8, /* UARTCC26XX_FIFO_THRESHOLD_4_8 */
UART_FIFO_TX6_8, /* UARTCC26XX_FIFO_THRESHOLD_6_8 */
UART_FIFO_TX7_8 /* UARTCC26XX_FIFO_THRESHOLD_7_8 */
};
/* Array for mapping of FIFO threshold defines selected by board files to: */
/* - RX FIFO threshold define used by driverlib */
/* FIFO threshold defines (enum UARTCC26XX_FifoThreshold) must be used as */
/* array index. */
/* Index 0 handles backward compatibility with legacy board files that don't */
/* select any FIFO thresholds. */
static const uint8_t rxFifoThreshold[6] = {
UART_FIFO_RX4_8, /* UARTCC26XX_FIFO_THRESHOLD_DEFAULT */
UART_FIFO_RX1_8, /* UARTCC26XX_FIFO_THRESHOLD_1_8 */
UART_FIFO_RX2_8, /* UARTCC26XX_FIFO_THRESHOLD_2_8 */
UART_FIFO_RX4_8, /* UARTCC26XX_FIFO_THRESHOLD_4_8 */
UART_FIFO_RX6_8, /* UARTCC26XX_FIFO_THRESHOLD_6_8 */
UART_FIFO_RX7_8 /* UARTCC26XX_FIFO_THRESHOLD_7_8 */
};
/* Array for mapping of FIFO threshold defines selected by board files to: */
/* - Number of TX FIFO bytes */
/* FIFO threshold defines (enum UARTCC26XX_FifoThreshold) must be used as */
/* array index. */
/* Index 0 handles backward compatibility with legacy board files that */
/* don't select any FIFO thresholds. */
static const uint8_t txFifoBytes[6] = {
4, /* UARTCC26XX_FIFO_THRESHOLD_DEFAULT */
4, /* UARTCC26XX_FIFO_THRESHOLD_1_8 */
8, /* UARTCC26XX_FIFO_THRESHOLD_2_8 */
16, /* UARTCC26XX_FIFO_THRESHOLD_4_8 */
24, /* UARTCC26XX_FIFO_THRESHOLD_6_8 */
28 /* UARTCC26XX_FIFO_THRESHOLD_7_8 */
};
/* Array for mapping of FIFO threshold defines selected by board files to: */
/* - Number of RX FIFO bytes */
/* FIFO threshold defines (enum UARTCC26XX_FifoThreshold) must be used as */
/* array index. */
/* Index 0 handles backward compatibility with legacy board files that */
/* don't select any FIFO thresholds. */
static const uint8_t rxFifoBytes[6] = {
16, /* UARTCC26XX_FIFO_THRESHOLD_DEFAULT */
4, /* UARTCC26XX_FIFO_THRESHOLD_1_8 */
8, /* UARTCC26XX_FIFO_THRESHOLD_2_8 */
16, /* UARTCC26XX_FIFO_THRESHOLD_4_8 */
24, /* UARTCC26XX_FIFO_THRESHOLD_6_8 */
28 /* UARTCC26XX_FIFO_THRESHOLD_7_8 */
};
/*
* ======================== PIN driver objects ================================
*/
/*
* ================================= Macro ====================================
* TODO: Move me
*/
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define UNIT_DIV_ROUNDUP(x,d) ((x + ((d) - 1)) / (d))
#define READ_DONE 0x1 /* Mask to trigger Swi on a read complete */
#define WRITE_DONE 0x2 /* Mask to trigger Swi on a write complete */
/*
* Function for checking whether flow control is enabled.
*/
static inline bool isFlowControlEnabled(UARTCC26XX_HWAttrsV2 const *hwAttrs) {
return ((hwAttrs->ctsPin != PIN_UNASSIGNED) && (hwAttrs->rtsPin != PIN_UNASSIGNED));
}
/*
* Ensure safe setting of the standby disallow constraint.
*/
static inline void threadSafeStdbyDisSet(volatile bool *pConstraint) {
unsigned int key;
/* Disable interrupts */
key = HwiP_disable();
/* Only act if the current constraint is not previously set */
if (!*pConstraint) {
/* Set constraints to guarantee operation */
Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY);
*pConstraint = true;
}
/* Re-enable interrupts */
HwiP_restore(key);
}
/*
* Ensure safe releasing of the standby disallow constraint.
*/
static inline void threadSafeStdbyDisRelease(volatile bool *pConstraint) {
unsigned int key;
/* Disable interrupts */
key = HwiP_disable();
if (*pConstraint) {
/* release constraint since operation is done */
Power_releaseConstraint(PowerCC26XX_DISALLOW_STANDBY);
*pConstraint = false;
}
/* Re-enable interrupts */
HwiP_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;
DebugP_log1("UART:(%p) posting write semaphore",
((UARTCC26XX_HWAttrsV2 const *)(handle->hwAttrs))->baseAddr);
SemaphoreP_post(&(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;
DebugP_log1("UART:(%p) posting read semaphore",
((UARTCC26XX_HWAttrsV2 const *)(handle->hwAttrs))->baseAddr);
SemaphoreP_post(&(object->readSem));
}
/*
* ======== writeData ========
* Write and process data to the UART.
*/
static int32_t writeData(UART_Handle handle, int32_t size)
{
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 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;
}
DebugP_log2("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.
* @param(size) number of bytes to be read
*/
static int32_t readData(UART_Handle handle, int32_t size)
{
int32_t readIn;
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 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) {
DebugP_log2("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);
}
/*
* ======== readData2RingBuf ========
* Read and process data from the UART to RingBuf.
* @param(size) number of bytes to be read
*/
static int32_t readData2RingBuf(UART_Handle handle, int32_t size)
{
int32_t readIn;
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 const *hwAttrs;
/* Get the pointer to the object and hwAttrs */
object = handle->object;
hwAttrs = handle->hwAttrs;
/* Fill up RingBuf */
while (size && (readIn = (int32_t)UARTCharGetNonBlocking(hwAttrs->baseAddr)) != -1) {
DebugP_log2("UART:(%p) Read character 0x%x",
hwAttrs->baseAddr, (uint8_t)readIn);
size--;
RingBuf_put(&object->ringBuffer, (unsigned char)readIn);
}
return (size);
}
/*
* ======== 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 */
ClockP_stop((ClockP_Handle) &(object->txFifoEmptyClk));
/* No more to write, but data is not shifted 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)+(object->stopBits+1))*1000000)/object->baudRate + 100;
/* 2. Configure clock object to trigger when FIFO is empty
* - +1 in case clock module due to tick in less than one ClockP_tickPeriod
* - UNIT_DIV_ROUNDUP to avoid fractional part being truncated during division
*/
ClockP_setTimeout((ClockP_Handle) &(object->txFifoEmptyClk),
(1 + UNIT_DIV_ROUNDUP(writeTimeoutUs, ClockP_tickPeriod)));
ClockP_start((ClockP_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_HWAttrsV2 const *hwAttrs;
/* Get the pointer to the object and hwAttrs */
object = handle->object;
hwAttrs = handle->hwAttrs;
/* 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
* ClockP_tickPeriod is larger than 500 us.
*/
ClockP_setTimeout((ClockP_Handle) &(object->txFifoEmptyClk), MAX((500/ClockP_tickPeriod),1));
ClockP_start((ClockP_Handle) &(object->txFifoEmptyClk));
return;
}
SwiP_or(&(object->swi), WRITE_DONE);
}
/*
* ======== 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_HWAttrsV2 const *hwAttrs)
{
unsigned int key;
/*It is not possible to flush the TX FIFO with simple write to HW, doing workaround:
* 0. Disable TX interrupt
*/
key = HwiP_disable();
UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
HwiP_restore(key);
/* 1. Ensure TX IO will stay high when connected to GPIO */
PIN_setOutputEnable(object->hPin, hwAttrs->txPin, 1);
PIN_setOutputValue(object->hPin, hwAttrs->txPin, 1);
/* 2. Disconntect tx from IO, and set it as "GPIO" */
PINCC26XX_setMux(object->hPin, hwAttrs->txPin, IOC_PORT_GPIO);
/* 3. Disconnect cts */
PINCC26XX_setMux(object->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..
*/
SemaphoreP_pend(&(object->writeSem), SemaphoreP_WAIT_FOREVER);
}
/* 5. Revert to active pins before returning */
#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2)
PINCC26XX_setMux(object->hPin, hwAttrs->txPin, (hwAttrs->baseAddr == UART0_BASE ? IOC_PORT_MCU_UART0_TX : IOC_PORT_MCU_UART1_TX));
if(isFlowControlEnabled(hwAttrs)) {
PINCC26XX_setMux(object->hPin, hwAttrs->ctsPin, (hwAttrs->baseAddr == UART0_BASE ? IOC_PORT_MCU_UART0_CTS : IOC_PORT_MCU_UART1_CTS));
}
#else
PINCC26XX_setMux(object->hPin, hwAttrs->txPin, IOC_PORT_MCU_UART0_TX);
if(isFlowControlEnabled(hwAttrs)) {
PINCC26XX_setMux(object->hPin, hwAttrs->ctsPin, IOC_PORT_MCU_UART0_CTS);
}
#endif
}
/*
* ======== UARTCC26XX_hwiIntFxn ========
* Hwi function that processes UART interrupts.
*
* Six UART interrupts are enabled when configured for RX: Receive timeout,
* receive FIFO at configured threshold (4/8 full by default) and all four
* error interrupts.
*
* One interrupt is enabled when configured for TX: Transmit FIFO at configured
* threshold (7/8 empty by default).
*
* 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(uintptr_t arg)
{
unsigned long intStatus;
unsigned long errStatus = UART_OK;
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 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);
DebugP_log2("UART:(%p) Interrupt with mask 0x%x",
hwAttrs->baseAddr, intStatus);
/* Record readSize */
int32_t readSize = object->readSize;
int32_t readSize_ringBuf = object->ringBuffer.length - object->ringBuffer.count;
/* 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, readSize);
readData((UART_Handle)arg, bytesToRead);
/* read the rest into RingBuf */
bytesToRead = MIN((UARTCC26XX_FIFO_SIZE - bytesToRead), readSize_ringBuf);
readData2RingBuf((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)
*/
/* Only if UART_read is active */
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 */
break;
}
else {
/* current read was not the problem update readSize */
object->readSize--;
}
}
/* If we managed to read out all bytes when checking for errors, make sure to post the Swi
* and read remaining data into the ring buffer */
if (!object->readSize) {
/* Read succeeded. */
SwiP_or(&(object->swi), READ_DONE);
/* Read any remaining data in the FIFO into the ring buffer. */
readData2RingBuf((UART_Handle)arg, readSize_ringBuf);
}
}
/* Report current error status */
object->status = (UART_Status)errStatus;
/* Break and clean up any ongoing transaction */
UARTCC26XX_readCancel((UART_Handle)arg);
/* Notify application of error */
if (hwAttrs->errorFxn) {
hwAttrs->errorFxn((UART_Handle)arg, errStatus);
}
}
else {
/* Receive Timeout */
if(intStatus & UART_INT_RT) {
/* if UART_read is active */
if (readSize) {
/* Read data from FIFO. */
object->readSize = readData((UART_Handle)arg, 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 */
SwiP_or(&(object->swi), READ_DONE);
}
/* else - return when all bytes have arrived */
else {
/* If all bytes are read */
if(!object->readSize) {
/* Read succeeded */
SwiP_or(&(object->swi), READ_DONE);
}
}
}
else {
/* not during UART_read, put in RingBuf */
readData2RingBuf((UART_Handle)arg, readSize_ringBuf);
}
}
else {
/* RX interrupt, since CTS is handled by HW */
if (intStatus & UART_INT_RX) {
if (readSize) {
/* if UART_read is active */
/* 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.
*/
size_t readFifoThresholdBytes = rxFifoBytes[hwAttrs->rxIntFifoThr];
size_t bytesToRead = MIN(readFifoThresholdBytes - 1, object->readSize);
/* Do read, all bytes we request to read, are present in FIFO */
readData((UART_Handle)arg, bytesToRead);
/* Decrement object->readSize with the actual number of bytes read
* There will always be at least bytesToRead number of bytes in FIFO
*/
object->readSize -= bytesToRead;
/* If all bytes are read */
if (!object->readSize) {
/* Read succeeded. */
SwiP_or(&(object->swi), READ_DONE);
/* Read any remaining data in the FIFO into the ring buffer. */
readData2RingBuf((UART_Handle)arg, readSize_ringBuf);
}
}
else {
/* not during UART_read, put all in RingBuf */
readData2RingBuf((UART_Handle)arg, readSize_ringBuf);
}
}
}
}
/* 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 shifted out properly yet.
* Start TX FIFO Empty clock, which will trigger the txFifoEmptyClk
* function.
* The number of bytes left in the TX FIFO when the TX FIFO threshold
* interrupt occurs are added to writtenLast.
*/
startTxFifoEmptyClk((UART_Handle)arg, (writtenLast + txFifoBytes[hwAttrs->txIntFifoThr]));
}
}
}
/*
* ======== UARTCC26XX_swiIntFxn ========
* Swi function that processes UART interrupts.
* @param arg The UART_Handle for this Hwi.
*/
void UARTCC26XX_swiIntFxn(uintptr_t arg0, uintptr_t arg1)
{
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 const *hwAttrs;
uint32_t trigger = SwiP_getTrigger();
/* Get the pointer to the object and hwAttrs */
object = ((UART_Handle)arg0)->object;
hwAttrs = (UARTCC26XX_HWAttrsV2 const *)(((UART_Handle)arg0)->hwAttrs);
if (trigger & READ_DONE) {
/* Release power constraint. */
threadSafeStdbyDisRelease(&(object->uartRxPowerConstraint));
/* Reset the read buffer so we can pass it back */
object->readBuf = (unsigned char *)object->readBuf - object->readCount;
/* Do Callback */
object->readCallback((UART_Handle)arg0, object->readBuf,
object->readCount);
DebugP_log2("UART:(%p) Read finished, %d bytes read",
hwAttrs->baseAddr, object->readCount);
}
if (trigger & WRITE_DONE) {
/* Release constraint since transaction is done */
threadSafeStdbyDisRelease(&(object->uartTxPowerConstraint));
/* Disable TX interrupt */
UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
/* Disable TX */
HWREG(hwAttrs->baseAddr + 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((UART_Handle)arg0, (uint8_t*)object->writeBuf,
object->writeCount);
DebugP_log2("UART:(%p) Write finished, %d bytes written",
hwAttrs->baseAddr, object->writeCount);
}
}
/*!
* @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;
}
/*!
* @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 {
HwiP_Params hwiParams;
SwiP_Params swiParams;
ClockP_Params clkParams;
} paramsUnion;
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 const *hwAttrs;
/* Get the pointer to the object and hwAttrs */
object = handle->object;
hwAttrs = handle->hwAttrs;
/* Disable preemption while checking if the UART is open. */
key = HwiP_disable();
/* Check if the UART is open already with the base addr. */
if (object->opened == true) {
HwiP_restore(key);
DebugP_log1("UART:(%p) already in use.", hwAttrs->baseAddr);
return (NULL);
}
object->opened = true;
HwiP_restore(key);
/* Check that a callback is set */
DebugP_assert(params->readMode != UART_MODE_CALLBACK ||
params->readCallback != NULL);
DebugP_assert(params->writeMode != UART_MODE_CALLBACK ||
params->writeCallback != 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->uartRxPowerConstraint = false;
object->uartTxPowerConstraint = false;
/* 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!
*/
DebugP_log0("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 = HwiP_disable();
object->opened = false;
HwiP_restore(key);
/* Signal back to application that UART driver was not succesfully opened */
return (NULL);
}
/* Create Hwi object for this UART peripheral. */
HwiP_Params_init(&(paramsUnion.hwiParams));
paramsUnion.hwiParams.arg = (uintptr_t)handle;
paramsUnion.hwiParams.priority = hwAttrs->intPriority;
HwiP_construct(&(object->hwi), hwAttrs->intNum, UARTCC26XX_hwiIntFxn,
&(paramsUnion.hwiParams));
/* Create Swi object for this UART peripheral */
SwiP_Params_init(&(paramsUnion.swiParams));
paramsUnion.swiParams.arg0 = (uintptr_t)handle;
paramsUnion.swiParams.priority = hwAttrs->swiPriority;
SwiP_construct(&(object->swi), UARTCC26XX_swiIntFxn, &(paramsUnion.swiParams));
/* Initialize semaphore */
/* If write mode is blocking create a semaphore and set callback. */
if (object->writeMode == UART_MODE_BLOCKING) {
SemaphoreP_constructBinary(&(object->writeSem), 0);
object->writeCallback = &writeSemCallback;
}
/* If read mode is blocking create a semaphore and set callback. */
if (object->readMode == UART_MODE_BLOCKING) {
SemaphoreP_constructBinary(&(object->readSem), 0);
object->readCallback = &readSemCallback;
}
/* Create clock object to be used for write FIFO empty callback */
ClockP_Params_init(&paramsUnion.clkParams);
paramsUnion.clkParams.period = 0;
paramsUnion.clkParams.startFlag = false;
paramsUnion.clkParams.arg = (uintptr_t) handle;
ClockP_construct(&(object->txFifoEmptyClk),
(ClockP_Fxn) &writeFinishedDoCallback,
10, &(paramsUnion.clkParams));
/* Create circular buffer object to be used for read buffering */
RingBuf_construct(&object->ringBuffer, hwAttrs->ringBufPtr, hwAttrs->ringBufSize);
/* Register notification function */
Power_registerNotify(&object->uartPostObj, PowerCC26XX_AWAKE_STANDBY, (Power_NotifyFxn)uartPostNotify, (uint32_t)handle);
/* UART opened successfully */
DebugP_log1("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)
{
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 const *hwAttrs;
/* Get the pointer to the object and hwAttrs */
object = handle->object;
hwAttrs = handle->hwAttrs;
/* Deallocate pins */
PIN_close(object->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);
/* Mark the module as available */
object->opened = false;
/* Cancel any possible ongoing reads/writes */
UARTCC26XX_writeCancel(handle);
UARTCC26XX_readCancel(handle);
/* Disable UART FIFO */
HWREG(hwAttrs->baseAddr + UART_O_LCRH) &= ~(UART_LCRH_FEN);
/* Disable UART module */
HWREG(hwAttrs->baseAddr + UART_O_CTL) &= ~(UART_CTL_UARTEN | UART_CTL_TXE |
UART_CTL_RXE);
/* Release power dependency - i.e. potentially power down serial domain. */
Power_releaseDependency(hwAttrs->powerMngrId);
/* Destruct the SYS/BIOS objects. */
HwiP_destruct(&(object->hwi));
SwiP_destruct(&(object->swi));
if (object->writeMode == UART_MODE_BLOCKING) {
SemaphoreP_destruct(&(object->writeSem));
}
if (object->readMode == UART_MODE_BLOCKING) {
SemaphoreP_destruct(&(object->readSem));
}
ClockP_destruct(&(object->txFifoEmptyClk));
/* Unregister power notification objects */
Power_unregisterNotify(&object->uartPostObj);
DebugP_log1("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_fast16_t UARTCC26XX_control(UART_Handle handle, uint_fast16_t cmd,
void *arg)
{
/* Locals */
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 const *hwAttrs;
unsigned int key;
/* 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;
case UARTCC26XX_CMD_RX_FIFO_FLUSH:
/* Flush RX FIFO */
hwAttrs = handle->hwAttrs;
/* Disable interrupts to avoid reading data while changing state. */
key = HwiP_disable();
/* Read RX FIFO until empty */
while (((int32_t)UARTCharGetNonBlocking(hwAttrs->baseAddr)) != -1);
/* Reset RingBuf */
object->ringBuffer.count = 0;
object->ringBuffer.head = object->ringBuffer.length - 1;
object->ringBuffer.tail = 0;
/* Set size = 0 to prevent reading and restore interrupts. */
object->readSize = 0;
HwiP_restore(key);
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_fast32_t UARTCC26XX_write(UART_Handle handle, const void *buffer,
size_t size)
{
unsigned int key;
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 const *hwAttrs;
/* Get the pointer to the object */
object = handle->object;
hwAttrs = handle->hwAttrs;
/* Check that there is data to write */
DebugP_assert(size != 0);
/* Disable preemption while checking if the UART is in use. */
key = HwiP_disable();
/* The UART TX is disabled after a successful write, if it is
* still active another write is in progress, reject. */
uint32_t writeActive = HWREG(hwAttrs->baseAddr + UART_O_CTL) & (UART_CTL_TXE);
if (!object->opened || writeActive) {
HwiP_restore(key);
DebugP_log1("UART:(%p) Could not write data, uart closed or in use.",
((UARTCC26XX_HWAttrsV2 const *)(handle->hwAttrs))->baseAddr);
return (UART_ERROR);
}
/* Stop the txFifoEmpty clock in case it was running due to a previous write operation */
ClockP_stop((ClockP_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;
/* Enable TX */
HWREG(hwAttrs->baseAddr + UART_O_CTL) |= UART_CTL_TXE;
HwiP_restore(key);
/* Set constraints to guarantee transaction */
threadSafeStdbyDisSet(&(object->uartTxPowerConstraint));
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 (SemaphoreP_OK != SemaphoreP_pend(&(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(&(object->uartTxPowerConstraint));
DebugP_log2("UART:(%p) Write timed out, %d bytes written",
((UARTCC26XX_HWAttrsV2 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 {
key = HwiP_disable();
/* Enable TX interrupts */
UARTIntEnable(hwAttrs->baseAddr, UART_INT_TX);
HwiP_restore(key);
/* 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 (SemaphoreP_OK != SemaphoreP_pend(&(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(&(object->uartTxPowerConstraint));
DebugP_log2("UART:(%p) Write timed out, %d bytes written",
((UARTCC26XX_HWAttrsV2 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 buf 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_fast32_t 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_HWAttrsV2 const *hwAttrs;
/* Get the pointer to the object */
object = handle->object;
hwAttrs = handle->hwAttrs;
/* Disable interrupts to avoid writing data while changing state. */
key = HwiP_disable();
/* Return if there is nothing to write and TX FIFO is empty. */
if (!object->writeSize &&
!UARTBusy(hwAttrs->baseAddr) &&
!(HWREG(hwAttrs->baseAddr + UART_O_CTL) & (UART_CTL_TXE))) {
HwiP_restore(key);
return;
}
/* Stop the clock in case we have finished shifting out the
* tx bytes but the tx FIFO empty clock has not timed out yet.
* Otherwise the clock will timeout and behave as though the
* operation were not canceled resulting in two callbacks for
* the same operation.
*/
ClockP_stop((ClockP_Handle) &(object->txFifoEmptyClk));
/* Set size = 0 to prevent writing and restore interrupts. */
object->writeSize = 0;
HwiP_restore(key);
/* If flow control is enabled, a workaround for flushing the fifo is needed..*/
if (isFlowControlEnabled(hwAttrs)) {
writeTxFifoFlush(object, hwAttrs);
}
key = HwiP_disable();
/* Disable TX interrupt */
UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX);
/* Disable UART TX */
HWREG(hwAttrs->baseAddr + UART_O_CTL) &= ~(UART_CTL_TXE);
HwiP_restore(key);
/* Release constraint since transaction is done */
threadSafeStdbyDisRelease(&(object->uartTxPowerConstraint));
/* 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);
DebugP_log2("UART:(%p) Write canceled, "
"%d bytes written",
((UARTCC26XX_HWAttrsV2 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_fast32_t UARTCC26XX_read(UART_Handle handle, void *buffer, size_t size)
{
unsigned char readIn;
UARTCC26XX_Object *object;
UARTCC26XX_HWAttrsV2 const *hwAttrs;
size_t objectReadSize;
unsigned int key;
/* Get the pointer to the object */
object = handle->object;
hwAttrs = handle->hwAttrs;
if (!object->opened) {
DebugP_log1("UART:(%p) not opened.", hwAttrs->baseAddr);
return (UART_ERROR);
}
if (object->readSize) {
/* Previous read is not done, return */
DebugP_log1("UART:(%p) Could not read data, uart in use.",
((UARTCC26XX_HWAttrsV2 const *)(handle->hwAttrs))->baseAddr);
return (UART_ERROR);
}
/* Set readSize */
objectReadSize = 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;
/* Read from RingBuf as much as is available */
while (objectReadSize) {
int rdCount;
/* Disable interrupts while reading from the ring buffer */
key = HwiP_disable();
rdCount = RingBuf_get(&object->ringBuffer, &readIn);
if (rdCount < 0) {
/* RingBuf is empty, need to read from FIFO */
object->readSize = objectReadSize;
/* Enable RX */
HWREG(hwAttrs->baseAddr + 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);
HwiP_restore(key);
/* Set constraint for sleep to guarantee transaction */
threadSafeStdbyDisSet(&(object->uartRxPowerConstraint));
/* If readMode is blocking, block and get the status. */
if (object->readMode == UART_MODE_BLOCKING) {
/*
* Check for return partial case before waiting on the
* semaphore. It's possible that no more data will come
* in to post the semaphore or cause a read timeout.
*/
key = HwiP_disable();
if ((object->readRetPartial) && (object->readCount)
&& (object->readSize)) {
/* Return partial enabled and some data has been read */
/* Reset readSize to allow next UART_read() */
object->readSize = 0;
HwiP_restore(key);
/* Release the constraint */
threadSafeStdbyDisRelease(&(object->uartRxPowerConstraint));
/* return the number of data read */
return (object->readCount);
}
HwiP_restore(key);
/* Pend on semaphore and wait for Hwi to finish. */
if (SemaphoreP_OK != SemaphoreP_pend(&(object->readSem),
object->readTimeout)) {
/*
* If the ISR posts the semaphore here, the count will be
* wrong, so we'll pend again with 0 timeout after setting
* the read size to 0
*/
/* Semaphore timed out, make the read empty and log the read. */
object->readSize = 0;
if (SemaphoreP_OK != SemaphoreP_pend(&(object->readSem),
SemaphoreP_NO_WAIT)) {
/*
* Release constraint since transaction timed out,
* allowed to enter standby
*/
threadSafeStdbyDisRelease(&(object->uartRxPowerConstraint));
/* Reset the read buffer so we can pass it back */
object->readBuf = (unsigned char *)object->readBuf -
object->readCount;
/* Set status to TIMED_OUT */
object->status = UART_TIMED_OUT;
DebugP_log2("UART:(%p) Read timed out, %d bytes read",
((UARTCC26XX_HWAttrsV2 const *)(handle->hwAttrs))->baseAddr,
object->readCount);
}
}
/* return the number of data read */
return (object->readCount);
}
/*
* Post Swi for return partial case. Disable interrupts to
* ensure that the ISR does not finish the read and also post
* the Swi before we set object->readSize to 0. Check
* object->readSize in case the ISR already posted the Swi.
*/
key = HwiP_disable();
/* readMode is callback */
if ((object->readRetPartial) && (object->readCount)
&& (object->readSize)) {
/* Return partial enabled and some data has been read */
/* Reset readSize to allow next UART_read() */
object->readSize = 0;
HwiP_restore(key);
/* Read succeeded */
SwiP_or(&(object->swi), READ_DONE);
}
else {
HwiP_restore(key);
}
return (0);
}
HwiP_restore(key);
/* save data to receive buffer */
*((unsigned char *)object->readBuf) = (uint8_t)readIn;
object->readBuf = (unsigned char *)object->readBuf + 1;
object->readCount++;
objectReadSize--;
}
/* Read succeeded. */
/* Reset the read buffer so we can pass it back */
object->readBuf = (unsigned char *)object->readBuf - object->readCount;
/* Do Callback */
if (object->readMode == UART_MODE_CALLBACK) {
object->readCallback(handle, object->readBuf, object->readCount);
}
/* return the number of data read */
return (object->readCount);
}
/*
* ======== UARTCC26XX_readPolling ========
*/
int_fast32_t 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_HWAttrsV2 const *hwAttrs;
/* Get the pointer to the object */
object = handle->object;
hwAttrs = handle->hwAttrs;
/* Disable interrupts to avoid reading data while changing state. */
key = HwiP_disable();
/* Disable RX interrupts */
UARTIntDisable(hwAttrs->baseAddr, UART_INT_OE | UART_INT_BE | UART_INT_PE |
UART_INT_FE | UART_INT_RT | UART_INT_RX);
/* Release constraint since transaction is done */
threadSafeStdbyDisRelease(&(object->uartRxPowerConstraint));
/* Return if there is no read. */
if (!object->readSize) {
HwiP_restore(key);
return;
}
/* Set size = 0 to prevent reading. */
object->readSize = 0;
/* Reset the read buffer so we can pass it back */
object->readBuf = (unsigned char *)object->readBuf - object->readCount;
/* Restore interrupts */
HwiP_restore(key);
object->readCallback(handle, object->readBuf, object->readCount);
DebugP_log2("UART:(%p) Read canceled, "
"%d bytes read",
((UARTCC26XX_HWAttrsV2 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_HWAttrsV2 const *hwAttrs;
ClockP_FreqHz freq;
/* 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 TX interrupt FIFO level and RX interrupt FIFO level */
UARTFIFOLevelSet(hwAttrs->baseAddr, txFifoThreshold[hwAttrs->txIntFifoThr],
rxFifoThreshold[hwAttrs->rxIntFifoThr]);
/* Configure frame format and baudrate */
ClockP_getCpuFreq(&freq);
UARTConfigSetExpClk(hwAttrs->baseAddr,
freq.lo,
object->baudRate,
(dataLength[object->dataLength] |
stopBits[object->stopBits] |
parityType[object->parityType]));
DebugP_log3("UART:(%p) CPU freq: %d; UART baudrate to %d",
hwAttrs->baseAddr,
freq.lo,
object->baudRate);
/* Enable UART FIFOs */
HWREG(hwAttrs->baseAddr + UART_O_LCRH) |= UART_LCRH_FEN;
/* Enable the UART module */
HWREG(hwAttrs->baseAddr + UART_O_CTL) |= UART_CTL_UARTEN;
/* If Flow Control is enabled, configure hardware controlled flow control */
if(isFlowControlEnabled(hwAttrs)) {
HWREG(hwAttrs->baseAddr + 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_Object *object;
UARTCC26XX_HWAttrsV2 const *hwAttrs;
PIN_Config uartPinTable[5];
uint32_t i = 0;
/* Get the pointer to the object and hwAttrs */
object = handle->object;
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 */
object->hPin = PIN_open(&object->pinState, uartPinTable);
/* Are pins already allocated */
if (!object->hPin) {
return false;
}
/* Set IO muxing for the UART pins */
#if (DeviceFamily_PARENT == DeviceFamily_PARENT_CC13X2_CC26X2)
PINCC26XX_setMux(object->hPin, hwAttrs->rxPin, (hwAttrs->baseAddr == UART0_BASE ? IOC_PORT_MCU_UART0_RX : IOC_PORT_MCU_UART1_RX));
PINCC26XX_setMux(object->hPin, hwAttrs->txPin, (hwAttrs->baseAddr == UART0_BASE ? IOC_PORT_MCU_UART0_TX : IOC_PORT_MCU_UART1_TX));
if (isFlowControlEnabled(hwAttrs)) {
PINCC26XX_setMux(object->hPin, hwAttrs->ctsPin, (hwAttrs->baseAddr == UART0_BASE ? IOC_PORT_MCU_UART0_CTS : IOC_PORT_MCU_UART1_CTS));
PINCC26XX_setMux(object->hPin, hwAttrs->rtsPin, (hwAttrs->baseAddr == UART0_BASE ? IOC_PORT_MCU_UART0_RTS : IOC_PORT_MCU_UART1_RTS));
}
#else
PINCC26XX_setMux(object->hPin, hwAttrs->rxPin, IOC_PORT_MCU_UART0_RX);
PINCC26XX_setMux(object->hPin, hwAttrs->txPin, IOC_PORT_MCU_UART0_TX);
if (isFlowControlEnabled(hwAttrs)) {
PINCC26XX_setMux(object->hPin, hwAttrs->ctsPin, IOC_PORT_MCU_UART0_CTS);
PINCC26XX_setMux(object->hPin, hwAttrs->rtsPin, IOC_PORT_MCU_UART0_RTS);
}
#endif
/* 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.
*/
static int uartPostNotify(unsigned int eventType, uintptr_t eventArg, uintptr_t clientArg)
{
/* Reconfigure the hardware if returning from sleep */
if (eventType == PowerCC26XX_AWAKE_STANDBY) {
UARTCC26XX_initHw((UART_Handle) clientArg);
}
return Power_NOTIFYDONE;
}