/* * Copyright (c) 2014-2020, 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 #include #include #include /* * By default disable both asserts and log for this module. * This must be done before DebugP.h is included. */ #ifndef DebugP_ASSERT_ENABLED #define DebugP_ASSERT_ENABLED 0 #endif #ifndef DebugP_LOG_ENABLED #define DebugP_LOG_ENABLED 0 #endif #include #include #include #include #include /* driverlib header files */ #include #include #include #include #include #include #include #include /* Pad configuration defines */ #define PAD_CONFIG_BASE (OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_0) #define PAD_RESET_STATE 0xC61 /* UARTCC32XX functions */ void UARTCC32XX_close(UART_Handle handle); int_fast16_t UARTCC32XX_control(UART_Handle handle, uint_fast16_t cmd, void *arg); void UARTCC32XX_init(UART_Handle handle); UART_Handle UARTCC32XX_open(UART_Handle handle, UART_Params *params); int_fast32_t UARTCC32XX_read(UART_Handle handle, void *buffer, size_t size); void UARTCC32XX_readCancel(UART_Handle handle); int_fast32_t UARTCC32XX_readPolling(UART_Handle handle, void *buffer, size_t size); int_fast32_t UARTCC32XX_write(UART_Handle handle, const void *buffer, size_t size); void UARTCC32XX_writeCancel(UART_Handle handle); int_fast32_t UARTCC32XX_writePolling(UART_Handle handle, const void *buffer, size_t size); /* Static functions */ static unsigned int getPowerMgrId(unsigned int baseAddr); static void initHw(UART_Handle handle); static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg, uintptr_t clientArg); static void readBlockingTimeout(uintptr_t arg); static bool readIsrBinaryBlocking(UART_Handle handle); static bool readIsrBinaryCallback(UART_Handle handle); static bool readIsrTextBlocking(UART_Handle handle); static bool readIsrTextCallback(UART_Handle handle); static void readSemCallback(UART_Handle handle, void *buffer, size_t count); static int readTaskBlocking(UART_Handle handle); static int readTaskCallback(UART_Handle handle); static void releasePowerConstraint(UART_Handle handle); static int ringBufGet(UART_Handle object, unsigned char *data); static void writeData(UART_Handle handle, bool inISR); static void writeSemCallback(UART_Handle handle, void *buffer, size_t count); /* * Function for checking whether flow control is enabled. */ static inline bool isFlowControlEnabled(UARTCC32XX_HWAttrsV1 const *hwAttrs) { return ((hwAttrs->flowControl == UARTCC32XX_FLOWCTRL_HARDWARE) && (hwAttrs->ctsPin != UARTCC32XX_PIN_UNASSIGNED) && (hwAttrs->rtsPin != UARTCC32XX_PIN_UNASSIGNED)); } /* UART function table for UARTCC32XX implementation */ const UART_FxnTable UARTCC32XX_fxnTable = { UARTCC32XX_close, UARTCC32XX_control, UARTCC32XX_init, UARTCC32XX_open, UARTCC32XX_read, UARTCC32XX_readPolling, UARTCC32XX_readCancel, UARTCC32XX_write, UARTCC32XX_writePolling, UARTCC32XX_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 */ }; /* * ======== staticFxnTable ======== * This is a function lookup table to simplify the UART driver modes. */ static const UARTCC32XX_FxnSet staticFxnTable[2][2] = { {/* UART_MODE_BLOCKING */ {/* UART_DATA_BINARY */ .readIsrFxn = readIsrBinaryBlocking, .readTaskFxn = readTaskBlocking }, {/* UART_DATA_TEXT */ .readIsrFxn = readIsrTextBlocking, .readTaskFxn = readTaskBlocking } }, {/* UART_MODE_CALLBACK */ {/* UART_DATA_BINARY */ .readIsrFxn = readIsrBinaryCallback, .readTaskFxn = readTaskCallback }, {/* UART_DATA_TEXT */ .readIsrFxn = readIsrTextCallback, .readTaskFxn = readTaskCallback, } } }; /* * ======== UARTCC32XX_close ======== */ void UARTCC32XX_close(UART_Handle handle) { UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; uint_fast16_t retVal; uint32_t padRegister; /* Disable UART and interrupts. */ MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX | UART_INT_RX | UART_INT_RT | UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE); MAP_UARTDisable(hwAttrs->baseAddr); if (object->hwiHandle) { HwiP_delete(object->hwiHandle); } if (object->writeSem) { SemaphoreP_delete(object->writeSem); } if (object->readSem) { SemaphoreP_delete(object->readSem); } if (object->timeoutClk) { ClockP_delete(object->timeoutClk); } if (object->state.txEnabled) { retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); DebugP_assert(retVal == Power_SOK); object->state.txEnabled = false; } Power_unregisterNotify(&object->postNotify); if (object->state.rxEnabled) { retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); DebugP_assert(retVal == Power_SOK); object->state.rxEnabled = false; DebugP_log1("UART:(%p) UART_close released read power constraint", hwAttrs->baseAddr); } Power_releaseDependency(object->powerMgrId); if (object->txPin != (uint16_t)-1) { PowerCC32XX_restoreParkState((PowerCC32XX_Pin)object->txPin, object->prevParkTX); object->txPin = (uint16_t)-1; } if (object->rtsPin != (uint16_t)-1) { PowerCC32XX_restoreParkState((PowerCC32XX_Pin)object->rtsPin, object->prevParkRTS); object->rtsPin = (uint16_t)-1; } /* Restore pin pads to their reset states */ padRegister = (PinToPadGet((hwAttrs->rxPin) & 0xff)<<2) + PAD_CONFIG_BASE; HWREG(padRegister) = PAD_RESET_STATE; padRegister = (PinToPadGet((hwAttrs->txPin) & 0xff)<<2) + PAD_CONFIG_BASE; HWREG(padRegister) = PAD_RESET_STATE; if (isFlowControlEnabled(hwAttrs)) { padRegister = (PinToPadGet((hwAttrs->ctsPin) & 0xff)<<2) + PAD_CONFIG_BASE; HWREG(padRegister) = PAD_RESET_STATE; padRegister = (PinToPadGet((hwAttrs->rtsPin) & 0xff)<<2) + PAD_CONFIG_BASE; HWREG(padRegister) = PAD_RESET_STATE; } object->state.opened = false; DebugP_log1("UART:(%p) closed", hwAttrs->baseAddr); (void)retVal; } /* * ======== UARTCC32XX_control ======== * @pre Function assumes that the handle is not NULL */ int_fast16_t UARTCC32XX_control(UART_Handle handle, uint_fast16_t cmd, void *arg) { UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; unsigned char data; int bufferCount; uint_fast16_t retVal; bufferCount = RingBuf_peek(&object->ringBuffer, &data); switch (cmd) { /* Common UART CMDs */ case (UART_CMD_PEEK): *(int *)arg = (bufferCount) ? data : UART_ERROR; DebugP_log2("UART:(%p) UART_CMD_PEEK: %d", hwAttrs->baseAddr, *(uintptr_t*)arg); return (UART_STATUS_SUCCESS); case (UART_CMD_ISAVAILABLE): *(bool *)arg = (bufferCount != 0); DebugP_log2("UART:(%p) UART_CMD_ISAVAILABLE: %d", hwAttrs->baseAddr, *(uintptr_t*)arg); return (UART_STATUS_SUCCESS); case (UART_CMD_GETRXCOUNT): *(int *)arg = bufferCount; DebugP_log2("UART:(%p) UART_CMD_GETRXCOUNT: %d", hwAttrs->baseAddr, *(uintptr_t*)arg); return (UART_STATUS_SUCCESS); case (UART_CMD_RXENABLE): if (!object->state.rxEnabled) { Power_setConstraint(PowerCC32XX_DISALLOW_LPDS); MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT | UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE); object->state.rxEnabled = true; DebugP_log1("UART:(%p) UART_CMD_RXENABLE: Enabled", hwAttrs->baseAddr); DebugP_log1("UART:(%p) UART_control set read power constraint", hwAttrs->baseAddr); return (UART_STATUS_SUCCESS); } DebugP_log1("UART:(%p) UART_CMD_RXENABLE: Already enabled", hwAttrs->baseAddr); return (UART_STATUS_ERROR); case (UART_CMD_RXDISABLE): if (object->state.rxEnabled) { MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT | UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE); retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); DebugP_assert(retVal == Power_SOK); object->state.rxEnabled = false; DebugP_log1("UART:(%p) UART_CMD_RXDISABLE: Disabled", hwAttrs->baseAddr); DebugP_log1("UART:(%p) UART_control released read power " "constraint", hwAttrs->baseAddr); (void)retVal; return (UART_STATUS_SUCCESS); } DebugP_log1("UART:(%p) UART_CMD_RXDISABLE: Already disabled", hwAttrs->baseAddr); return (UART_STATUS_ERROR); /* Specific UART CMDs */ case (UARTCC32XX_CMD_IS_BUSY): *(bool *)arg = MAP_UARTBusy(hwAttrs->baseAddr); return (UART_STATUS_SUCCESS); case (UARTCC32XX_CMD_IS_RX_DATA_AVAILABLE): *(bool *)arg = MAP_UARTCharsAvail(hwAttrs->baseAddr); return (UART_STATUS_SUCCESS); case (UARTCC32XX_CMD_IS_TX_SPACE_AVAILABLE): *(bool *)arg = MAP_UARTSpaceAvail(hwAttrs->baseAddr); return (UART_STATUS_SUCCESS); default: DebugP_log2("UART:(%p) UART CMD undefined: %d", hwAttrs->baseAddr, cmd); return (UART_STATUS_UNDEFINEDCMD); } } /* * ======== UARTCC32XX_hwiIntFxn ======== * Hwi function that processes UART interrupts. * * @param(arg) The UART_Handle for this Hwi. */ static void UARTCC32XX_hwiIntFxn(uintptr_t arg) { uint32_t status; UARTCC32XX_Object *object = ((UART_Handle)arg)->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = ((UART_Handle)arg)->hwAttrs; uint32_t rxErrors; /* Clear interrupts */ status = MAP_UARTIntStatus(hwAttrs->baseAddr, true); MAP_UARTIntClear(hwAttrs->baseAddr, status); if (status & (UART_INT_RX | UART_INT_RT | UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE)) { object->readFxns.readIsrFxn((UART_Handle)arg); } /* Reading the data from the FIFO doesn't mean we caught an overrrun! */ rxErrors = MAP_UARTRxErrorGet(hwAttrs->baseAddr); if (rxErrors) { MAP_UARTRxErrorClear(hwAttrs->baseAddr); if (hwAttrs->errorFxn) { hwAttrs->errorFxn((UART_Handle)arg, rxErrors); } } if (status & UART_INT_TX) { writeData((UART_Handle)arg, true); } } /* * ======== UARTCC32XX_init ======== */ void UARTCC32XX_init(UART_Handle handle) { } /* * ======== UARTCC32XX_open ======== */ UART_Handle UARTCC32XX_open(UART_Handle handle, UART_Params *params) { uintptr_t key; UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; SemaphoreP_Params semParams; HwiP_Params hwiParams; ClockP_Params clockParams; uint16_t pin; uint16_t mode; /* Check for callback when in UART_MODE_CALLBACK */ DebugP_assert((params->readMode != UART_MODE_CALLBACK) || (params->readCallback != NULL)); DebugP_assert((params->writeMode != UART_MODE_CALLBACK) || (params->writeCallback != NULL)); key = HwiP_disable(); if (object->state.opened == true) { HwiP_restore(key); DebugP_log1("UART:(%p) already in use.", hwAttrs->baseAddr); return (NULL); } object->state.opened = true; HwiP_restore(key); object->state.readMode = params->readMode; object->state.writeMode = params->writeMode; object->state.readReturnMode = params->readReturnMode; object->state.readDataMode = params->readDataMode; object->state.writeDataMode = params->writeDataMode; object->state.readEcho = params->readEcho; object->readTimeout = params->readTimeout; object->writeTimeout = params->writeTimeout; object->readCallback = params->readCallback; object->writeCallback = params->writeCallback; object->baudRate = params->baudRate; object->stopBits = params->stopBits; object->dataLength = params->dataLength; object->parityType = params->parityType; object->readFxns = staticFxnTable[object->state.readMode][object->state.readDataMode]; /* Set UART variables to defaults. */ object->writeBuf = NULL; object->readBuf = NULL; object->writeCount = 0; object->readCount = 0; object->writeSize = 0; object->readSize = 0; object->state.txEnabled = false; object->txPin = (uint16_t)-1; object->rtsPin = (uint16_t)-1; RingBuf_construct(&object->ringBuffer, hwAttrs->ringBufPtr, hwAttrs->ringBufSize); /* Get the Power resource Id from the base address */ object->powerMgrId = getPowerMgrId(hwAttrs->baseAddr); if (object->powerMgrId == (unsigned int)-1) { DebugP_log1("UART:(%p) Failed to determine Power resource id", hwAttrs->baseAddr); return (NULL); } /* * Register power dependency. Keeps the clock running in SLP * and DSLP modes. */ Power_setDependency(object->powerMgrId); /* Do a software reset of the peripheral */ PowerCC32XX_reset(object->powerMgrId); pin = (hwAttrs->rxPin) & 0xff; mode = (hwAttrs->rxPin >> 8) & 0xff; MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode); pin = (hwAttrs->txPin) & 0xff; mode = (hwAttrs->txPin >> 8) & 0xff; MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode); /* * Read and save TX pin park state; set to "don't park" while UART is * open as device default is logic '1' during LPDS */ object->prevParkTX = (PowerCC32XX_ParkState) PowerCC32XX_getParkState((PowerCC32XX_Pin)pin); PowerCC32XX_setParkState((PowerCC32XX_Pin)pin, ~1); object->txPin = pin; if (isFlowControlEnabled(hwAttrs)) { pin = (hwAttrs->ctsPin) & 0xff; mode = (hwAttrs->ctsPin >> 8) & 0xff; MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode); pin = (hwAttrs->rtsPin) & 0xff; mode = (hwAttrs->rtsPin >> 8) & 0xff; MAP_PinTypeUART((unsigned long)pin, (unsigned long)mode); /* * Read and save RTS pin park state; set to "don't park" while UART is * open as device default is logic '1' during LPDS */ object->prevParkRTS = (PowerCC32XX_ParkState)PowerCC32XX_getParkState( (PowerCC32XX_Pin)pin); PowerCC32XX_setParkState((PowerCC32XX_Pin)pin, ~1); object->rtsPin = pin; /* Flow control will be enabled in initHw() */ } Power_registerNotify(&object->postNotify, PowerCC32XX_AWAKE_LPDS, postNotifyFxn, (uintptr_t)handle); Power_setConstraint(PowerCC32XX_DISALLOW_LPDS); object->state.rxEnabled = true; DebugP_log1("UART:(%p) UART_open set read power constraint", hwAttrs->baseAddr); HwiP_Params_init(&hwiParams); hwiParams.arg = (uintptr_t)handle; hwiParams.priority = hwAttrs->intPriority; object->hwiHandle = HwiP_create(hwAttrs->intNum, UARTCC32XX_hwiIntFxn, &hwiParams); if (object->hwiHandle == NULL) { DebugP_log1("UART:(%p) HwiP_create() failed", hwAttrs->baseAddr); UARTCC32XX_close(handle); return (NULL); } SemaphoreP_Params_init(&semParams); semParams.mode = SemaphoreP_Mode_BINARY; /* If write mode is blocking create a semaphore and set callback. */ if (object->state.writeMode == UART_MODE_BLOCKING) { if ((object->writeSem = SemaphoreP_create(0, &semParams)) == NULL) { DebugP_log1("UART:(%p) SemaphoreP_create() failed.", hwAttrs->baseAddr); UARTCC32XX_close(handle); return (NULL); } object->writeCallback = &writeSemCallback; } ClockP_Params_init(&clockParams); clockParams.arg = (uintptr_t)handle; /* If read mode is blocking create a semaphore and set callback. */ if (object->state.readMode == UART_MODE_BLOCKING) { object->readSem = SemaphoreP_create(0, &semParams); if (object->readSem == NULL) { DebugP_log1("UART:(%p) SemaphoreP_create() failed.", hwAttrs->baseAddr); UARTCC32XX_close(handle); return (NULL); } object->readCallback = &readSemCallback; object->timeoutClk = ClockP_create((ClockP_Fxn)&readBlockingTimeout, 0 /* timeout */, &(clockParams)); if (object->timeoutClk == NULL) { DebugP_log1("UART:(%p) ClockP_create() failed.", hwAttrs->baseAddr); UARTCC32XX_close(handle); return (NULL); } } else { object->state.drainByISR = false; } /* Initialize the hardware */ initHw(handle); DebugP_log1("UART:(%p) opened", hwAttrs->baseAddr); /* Return the handle */ return (handle); } /* * ======== UARTCC32XX_read ======== */ int_fast32_t UARTCC32XX_read(UART_Handle handle, void *buffer, size_t size) { uintptr_t key; UARTCC32XX_Object *object = handle->object; key = HwiP_disable(); if ((object->state.readMode == UART_MODE_CALLBACK) && object->readSize) { HwiP_restore(key); DebugP_log1("UART:(%p) Could not read data, uart in use.", ((UARTCC32XX_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr); return (UART_ERROR); } /* Save the data to be read and restore interrupts. */ object->readBuf = buffer; object->readSize = size; object->readCount = size; HwiP_restore(key); return (object->readFxns.readTaskFxn(handle)); } /* * ======== UARTCC32XX_readCancel ======== */ void UARTCC32XX_readCancel(UART_Handle handle) { uintptr_t key; UARTCC32XX_Object *object = handle->object; if ((object->state.readMode != UART_MODE_CALLBACK) || (object->readSize == 0)) { return; } key = HwiP_disable(); object->state.drainByISR = false; /* * Indicate that what we've currently received is what we asked for so that * the existing logic handles the completion. */ object->readSize -= object->readCount; object->readCount = 0; HwiP_restore(key); object->readFxns.readTaskFxn(handle); } /* * ======== UARTCC32XX_readPolling ======== */ int_fast32_t UARTCC32XX_readPolling(UART_Handle handle, void *buf, size_t size) { int32_t count = 0; UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; unsigned char *buffer = (unsigned char *)buf; /* Read characters. */ while (size) { /* Grab data from the RingBuf before getting it from the RX data reg */ MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT); if (RingBuf_get(&object->ringBuffer, buffer) == -1) { *buffer = MAP_UARTCharGet(hwAttrs->baseAddr); } if (object->state.rxEnabled) { MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT); } DebugP_log2("UART:(%p) Read character 0x%x", hwAttrs->baseAddr, *buffer); count++; size--; if (object->state.readDataMode == UART_DATA_TEXT && *buffer == '\r') { /* Echo character if enabled. */ if (object->state.readEcho) { MAP_UARTCharPut(hwAttrs->baseAddr, '\r'); } *buffer = '\n'; } /* Echo character if enabled. */ if (object->state.readDataMode == UART_DATA_TEXT && object->state.readEcho) { MAP_UARTCharPut(hwAttrs->baseAddr, *buffer); } /* If read return mode is newline, finish if a newline was received. */ if (object->state.readDataMode == UART_DATA_TEXT && object->state.readReturnMode == UART_RETURN_NEWLINE && *buffer == '\n') { return (count); } buffer++; } DebugP_log2("UART:(%p) Read polling finished, %d bytes read", hwAttrs->baseAddr, count); return (count); } /* * ======== UARTCC32XX_write ======== */ int_fast32_t UARTCC32XX_write(UART_Handle handle, const void *buffer, size_t size) { unsigned int key; UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; if (!size) { return 0; } key = HwiP_disable(); if (object->writeCount || UARTBusy(hwAttrs->baseAddr)) { HwiP_restore(key); DebugP_log1("UART:(%p) Could not write data, uart in use.", hwAttrs->baseAddr); return (UART_ERROR); } /* Save the data to be written and restore interrupts. */ object->writeBuf = buffer; object->writeSize = size; object->writeCount = size; if (object->state.txEnabled == false){ object->state.txEnabled = true; Power_setConstraint(PowerCC32XX_DISALLOW_LPDS); DebugP_log1("UART:(%p) UART_write set write power constraint", hwAttrs->baseAddr); } HwiP_restore(key); if (!(MAP_UARTIntStatus(hwAttrs->baseAddr, false) & UART_INT_TX)) { /* * Start the transfer going if the raw interrupt status TX bit * is 0. This will cause the ISR to fire when we enable * UART_INT_TX. If the RIS TX bit is not cleared, we don't * need to call writeData(), since the ISR will fire once we * enable the interrupt, causing the transfer to start. */ writeData(handle, false); } if (object->writeCount) { MAP_UARTTxIntModeSet(hwAttrs->baseAddr, UART_TXINT_MODE_FIFO); MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_TX); } /* If writeMode is blocking, block and get the state. */ if (object->state.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. */ MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX); MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_TX); object->writeCount = 0; DebugP_log2("UART:(%p) Write timed out, %d bytes written", hwAttrs->baseAddr, object->writeCount); } return (object->writeSize - object->writeCount); } return (0); } /* * ======== UARTCC32XX_writeCancel ======== */ void UARTCC32XX_writeCancel(UART_Handle handle) { uintptr_t key; UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; unsigned int written; uint_fast16_t retVal; key = HwiP_disable(); /* Return if there is no write. */ if (!object->writeCount) { HwiP_restore(key); return; } /* Set size = 0 to prevent writing and restore interrupts. */ written = object->writeCount; object->writeCount = 0; MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX); MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_TX); retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); DebugP_assert(retVal == Power_SOK); object->state.txEnabled = false; HwiP_restore(key); /* Reset the write buffer so we can pass it back */ object->writeCallback(handle, (void *)object->writeBuf, object->writeSize - written); DebugP_log2("UART:(%p) Write canceled, %d bytes written", hwAttrs->baseAddr, object->writeSize - written); (void)retVal; } /* * ======== UARTCC32XX_writePolling ======== */ int_fast32_t UARTCC32XX_writePolling(UART_Handle handle, const void *buf, size_t size) { int32_t count = 0; UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; unsigned char *buffer = (unsigned char *)buf; /* Write characters. */ while (size) { if (object->state.writeDataMode == UART_DATA_TEXT && *buffer == '\n') { MAP_UARTCharPut(hwAttrs->baseAddr, '\r'); count++; } MAP_UARTCharPut(hwAttrs->baseAddr, *buffer); DebugP_log2("UART:(%p) Wrote character 0x%x", hwAttrs->baseAddr, *buffer); buffer++; count++; size--; } while (MAP_UARTBusy(hwAttrs->baseAddr)) { ; } DebugP_log2("UART:(%p) Write polling finished, %d bytes written", hwAttrs->baseAddr, count); return (count); } /* * ======== getPowerMgrId ======== */ static unsigned int getPowerMgrId(unsigned int baseAddr) { switch (baseAddr) { case UARTA0_BASE: return (PowerCC32XX_PERIPH_UARTA0); case UARTA1_BASE: return (PowerCC32XX_PERIPH_UARTA1); default: return ((unsigned int)-1); } } /* * ======== initHw ======== */ static void initHw(UART_Handle handle) { ClockP_FreqHz freq; UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; /* Enable UART and its interrupt. */ MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_TX | UART_INT_RX | UART_INT_RT); MAP_UARTEnable(hwAttrs->baseAddr); /* Set the FIFO level to 7/8 empty and 4/8 full. */ MAP_UARTFIFOLevelSet(hwAttrs->baseAddr, UART_FIFO_TX1_8, UART_FIFO_RX1_8); if (isFlowControlEnabled(hwAttrs)) { /* Set flow control */ MAP_UARTFlowControlSet(hwAttrs->baseAddr, UART_FLOWCONTROL_TX | UART_FLOWCONTROL_RX); } else { MAP_UARTFlowControlSet(hwAttrs->baseAddr, UART_FLOWCONTROL_NONE); } ClockP_getCpuFreq(&freq); MAP_UARTConfigSetExpClk(hwAttrs->baseAddr, freq.lo, object->baudRate, dataLength[object->dataLength] | stopBits[object->stopBits] | parityType[object->parityType]); MAP_UARTIntEnable(hwAttrs->baseAddr, UART_INT_RX | UART_INT_RT | UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE); } /* * ======== postNotifyFxn ======== * Called by Power module when waking up from LPDS. */ static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg, uintptr_t clientArg) { initHw((UART_Handle)clientArg); return (Power_NOTIFYDONE); } /* * ======== readBlockingTimeout ======== */ static void readBlockingTimeout(uintptr_t arg) { UARTCC32XX_Object *object = ((UART_Handle)arg)->object; object->state.bufTimeout = true; SemaphoreP_post(object->readSem); } /* * ======== readIsrBinaryBlocking ======== * Function that is called by the ISR */ static bool readIsrBinaryBlocking(UART_Handle handle) { UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; int readIn; while (MAP_UARTCharsAvail(hwAttrs->baseAddr)) { /* * If the Ring buffer is full, leave the data in the FIFO. * This will allow flow control to work, if it is enabled. */ if (RingBuf_isFull(&object->ringBuffer)) { return (false); } readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr); /* * Bits 0-7 contain the data, bits 8-11 are used for error codes. * (Bits 12-31 are reserved and read as 0) If readIn > 0xFF, an * error has occurred. */ if (readIn > 0xFF) { if (hwAttrs->errorFxn) { hwAttrs->errorFxn(handle, (uint32_t)((readIn >> 8) & 0xF)); } MAP_UARTRxErrorClear(hwAttrs->baseAddr); return (false); } RingBuf_put(&object->ringBuffer, (unsigned char)readIn); if (object->state.callCallback) { object->state.callCallback = false; object->readCallback(handle, NULL, 0); } } return (true); } /* * ======== readIsrBinaryCallback ======== */ static bool readIsrBinaryCallback(UART_Handle handle) { UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; int readIn; bool ret = true; while (MAP_UARTCharsAvail(hwAttrs->baseAddr)) { if (RingBuf_isFull(&object->ringBuffer)) { ret = false; break; } readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr); if (readIn > 0xFF) { if (hwAttrs->errorFxn) { hwAttrs->errorFxn(handle, (uint32_t)((readIn >> 8) & 0xF)); } MAP_UARTRxErrorClear(hwAttrs->baseAddr); ret = false; break; } RingBuf_put(&object->ringBuffer, (unsigned char)readIn); } /* * Check and see if a UART_read in callback mode told use to continue * servicing the user buffer... */ if (object->state.drainByISR) { readTaskCallback(handle); } return (ret); } /* * ======== readIsrTextBlocking ======== */ static bool readIsrTextBlocking(UART_Handle handle) { UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; int readIn; while (MAP_UARTCharsAvail(hwAttrs->baseAddr)) { /* * If the Ring buffer is full, leave the data in the FIFO. * This will allow flow control to work, if it is enabled. */ if (RingBuf_isFull(&object->ringBuffer)) { return (false); } readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr); if (readIn > 0xFF) { if (hwAttrs->errorFxn) { hwAttrs->errorFxn(handle, (uint32_t)((readIn >> 8) & 0xF)); } MAP_UARTRxErrorClear(hwAttrs->baseAddr); return (false); } if (readIn == '\r') { /* Echo character if enabled. */ if (object->state.readEcho) { MAP_UARTCharPut(hwAttrs->baseAddr, '\r'); } readIn = '\n'; } RingBuf_put(&object->ringBuffer, (unsigned char)readIn); if (object->state.readEcho) { MAP_UARTCharPut(hwAttrs->baseAddr, (unsigned char)readIn); } if (object->state.callCallback) { object->state.callCallback = false; object->readCallback(handle, NULL, 0); } } return (true); } /* * ======== readIsrTextCallback ======== */ static bool readIsrTextCallback(UART_Handle handle) { UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; int readIn; bool ret = true; while (MAP_UARTCharsAvail(hwAttrs->baseAddr)) { /* * If the Ring buffer is full, leave the data in the FIFO. * This will allow flow control to work, if it is enabled. */ if (RingBuf_isFull(&object->ringBuffer)) { ret = false; break; } readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr); if (readIn > 0xFF) { if (hwAttrs->errorFxn) { hwAttrs->errorFxn(handle, (uint32_t)((readIn >> 8) & 0xF)); } MAP_UARTRxErrorClear(hwAttrs->baseAddr); ret = false; break; } if (readIn == '\r') { /* Echo character if enabled. */ if (object->state.readEcho) { MAP_UARTCharPut(hwAttrs->baseAddr, '\r'); } readIn = '\n'; } RingBuf_put(&object->ringBuffer, (unsigned char)readIn); if (object->state.readEcho) { MAP_UARTCharPut(hwAttrs->baseAddr, (unsigned char)readIn); } } /* * Check and see if a UART_read in callback mode told use to continue * servicing the user buffer... */ if (object->state.drainByISR) { readTaskCallback(handle); } return (ret); } /* * ======== readSemCallback ======== * Simple callback to post a semaphore for the blocking mode. */ static void readSemCallback(UART_Handle handle, void *buffer, size_t count) { UARTCC32XX_Object *object = handle->object; SemaphoreP_post(object->readSem); } /* * ======== readTaskBlocking ======== */ static int readTaskBlocking(UART_Handle handle) { unsigned char readIn; uintptr_t key; UARTCC32XX_Object *object = handle->object; unsigned char *buffer = object->readBuf; object->state.bufTimeout = false; object->state.callCallback = false; /* * It is possible for the object->timeoutClk and the callback function to * have posted the object->readSem Semaphore from the previous UART_read * call (if the code below didn't get to stop the clock object in time). * To clear this, we simply do a NO_WAIT pend on (binary) object->readSem * so that it resets the Semaphore count. */ SemaphoreP_pend(object->readSem, SemaphoreP_NO_WAIT); if ((object->readTimeout != 0) && (object->readTimeout != UART_WAIT_FOREVER)) { ClockP_setTimeout(object->timeoutClk, object->readTimeout); ClockP_start(object->timeoutClk); } while (object->readCount) { key = HwiP_disable(); if (ringBufGet(handle, &readIn) < 0) { object->state.callCallback = true; HwiP_restore(key); if (object->readTimeout == 0) { break; } SemaphoreP_pend(object->readSem, SemaphoreP_WAIT_FOREVER); if (object->state.bufTimeout == true) { break; } ringBufGet(handle, &readIn); } else { HwiP_restore(key); } *buffer = readIn; buffer++; /* In blocking mode, readCount doesn't not need a lock */ object->readCount--; if (object->state.readDataMode == UART_DATA_TEXT && object->state.readReturnMode == UART_RETURN_NEWLINE && readIn == '\n') { break; } } ClockP_stop(object->timeoutClk); return (object->readSize - object->readCount); } /* * ======== readTaskCallback ======== * This function is called the first time by the UART_read task and tries to * get all the data it can get from the ringBuffer. If it finished, it will * perform the user supplied callback. If it didn't finish, the ISR must handle * the remaining data. By setting the drainByISR flag, the UART_read function * handed over the responsibility to get the remaining data to the ISR. */ static int readTaskCallback(UART_Handle handle) { unsigned int key; UARTCC32XX_Object *object = handle->object; unsigned char readIn; unsigned char *bufferEnd; bool makeCallback = false; size_t tempCount; object->state.drainByISR = false; bufferEnd = (unsigned char*) object->readBuf + object->readSize; while (object->readCount) { key = HwiP_disable(); if (ringBufGet(handle, &readIn) < 0) { /* Not all data has been read */ object->state.drainByISR = true; HwiP_restore(key); break; } HwiP_restore(key); *(unsigned char *) (bufferEnd - object->readCount * sizeof(unsigned char)) = readIn; object->readCount--; if ((object->state.readDataMode == UART_DATA_TEXT) && (object->state.readReturnMode == UART_RETURN_NEWLINE) && (readIn == '\n')) { makeCallback = true; break; } } if (!object->readCount || makeCallback) { object->state.readCallbackPending = true; if (object->state.inReadCallback == false) { while (object->state.readCallbackPending) { object->state.readCallbackPending = false; tempCount = object->readSize; object->readSize = 0; object->state.inReadCallback = true; object->readCallback(handle, object->readBuf, tempCount - object->readCount); object->state.inReadCallback = false; } } } return (0); } /* * ======== releasePowerConstraint ======== */ static void releasePowerConstraint(UART_Handle handle) { UARTCC32XX_Object *object = handle->object; uint_fast16_t retVal; retVal = Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS); DebugP_assert(retVal == Power_SOK); object->state.txEnabled = false; DebugP_log1("UART:(%p) UART released write power constraint", ((UARTCC32XX_HWAttrsV1 const *)(handle->hwAttrs))->baseAddr); (void)retVal; } /* * ======== ringBufGet ======== */ static int ringBufGet(UART_Handle handle, unsigned char *data) { UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; uintptr_t key; int32_t readIn; int count; key = HwiP_disable(); if (RingBuf_isFull(&object->ringBuffer)) { count = RingBuf_get(&object->ringBuffer, data); readIn = MAP_UARTCharGetNonBlocking(hwAttrs->baseAddr); if (readIn != -1) { RingBuf_put(&object->ringBuffer, (unsigned char)readIn); count++; } HwiP_restore(key); } else { count = RingBuf_get(&object->ringBuffer, data); HwiP_restore(key); } return (count); } /* * ======== writeData ======== */ static void writeData(UART_Handle handle, bool inISR) { UARTCC32XX_Object *object = handle->object; UARTCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs; unsigned char *writeOffset; writeOffset = (unsigned char *)object->writeBuf + object->writeSize * sizeof(unsigned char); while (object->writeCount) { if (!MAP_UARTCharPutNonBlocking(hwAttrs->baseAddr, *(writeOffset - object->writeCount))) { /* TX FIFO is FULL */ break; } if ((object->state.writeDataMode == UART_DATA_TEXT) && (*(writeOffset - object->writeCount) == '\n')) { MAP_UARTCharPut(hwAttrs->baseAddr, '\r'); } object->writeCount--; } if (!object->writeCount) { MAP_UARTIntDisable(hwAttrs->baseAddr, UART_INT_TX); MAP_UARTIntClear(hwAttrs->baseAddr, UART_INT_TX); /* * Set TX interrupt for end of transmission mode. * The TXRIS bit will be set only when all the data * (including stop bits) have left the serializer. */ MAP_UARTTxIntModeSet(hwAttrs->baseAddr, UART_TXINT_MODE_EOT); if (!UARTBusy(hwAttrs->baseAddr)) { object->writeCallback(handle, (void *)object->writeBuf, object->writeSize); releasePowerConstraint(handle); } else { UARTIntEnable(hwAttrs->baseAddr, UART_INT_TX); } DebugP_log2("UART:(%p) Write finished, %d bytes written", hwAttrs->baseAddr, object->writeSize - object->writeCount); } } /* * ======== writeSemCallback ======== * Simple callback to post a semaphore for the blocking mode. */ static void writeSemCallback(UART_Handle handle, void *buffer, size_t count) { UARTCC32XX_Object *object = handle->object; SemaphoreP_post(object->writeSem); }