/*
 *  ======== UARTMSP432_writeCancel ========
 */
void UARTMSP432_writeCancel(UART_Handle handle)
{
    uintptr_t                 key;
    UARTMSP432_Object        *object = handle->object;
    UARTMSP432_HWAttrs const *hwAttrs = handle->hwAttrs;
    unsigned int              written;

    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. */
    MAP_UART_disableInterrupt(hwAttrs->baseAddr, EUSCI_A_UART_TRANSMIT_INTERRUPT);
    written = object->writeCount;
    object->writeCount = 0;

    HwiP_restore(key);

    /* Remove constraints set during write */
    Power_releaseConstraint(PowerMSP432_DISALLOW_DEEPSLEEP_0);
    Power_releaseConstraint(PowerMSP432_DISALLOW_PERF_CHANGES);

    /* 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);
}
Ejemplo n.º 2
0
void vUART_Handler( void )
{
uint8_t ucChar;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint_fast8_t xInterruptStatus;

	xInterruptStatus = MAP_UART_getEnabledInterruptStatus( EUSCI_A0_MODULE );

	if( ( xInterruptStatus & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG ) != 0x00 )
	{
		/* Obtain the character. */
		ucChar = MAP_UART_receiveData( EUSCI_A0_MODULE );

		/* Send the character to the queue.  Note the comments at the top of this
		file with regards to the inefficiency of this method for anything other than
		very low bandwidth communications.

		If writing to the queue unblocks a task, and the unblocked task	has a
		priority above the currently running task (the task that this interrupt
		interrupted), then xHigherPriorityTaskWoken will be set	to pdTRUE inside the
		xQueueSendFromISR() function.  xHigherPriorityTaskWoken is then passed to
		portYIELD_FROM_ISR() at	the end of this interrupt handler to request a
		context switch so the interrupt returns directly to the (higher priority)
		unblocked task. */
		xQueueSendFromISR( xRxQueue, &ucChar, &xHigherPriorityTaskWoken );
	}

	if( ( xInterruptStatus & EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG ) != 0x00 )
	{
		/* Are there more characters to transmit? */
		pcStringStart++;
		if( ( uint32_t ) pcStringStart < ( uint32_t ) pcStringEnd )
		{
			/* This is probably quite a heavy wait function just for writing to
			the Tx register.  An optimised design would probably replace this
			with a simple register write. */
			pxUARTA0->rTXBUF.r = ( uint_fast8_t ) *pcStringStart;
		}
		else
		{
			/* No more characters to send.  Disable the interrupt and notify the
			task, if the task is waiting. */
			MAP_UART_disableInterrupt( EUSCI_A0_MODULE, EUSCI_A_UART_TRANSMIT_INTERRUPT );
			if( xTransmittingTask != NULL )
			{
				vTaskNotifyGiveFromISR( xTransmittingTask, &xHigherPriorityTaskWoken );
				xTransmittingTask = NULL;
			}
		}
	}


	/* portYIELD_FROM_ISR() will request a context switch if executing this
	interrupt handler caused a task to leave the blocked state, and the task
	that left the blocked state has a higher priority than the currently running
	task (the task this interrupt interrupted).  See the comment above the calls
	to xSemaphoreGiveFromISR() and xQueueSendFromISR() within this function. */
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
/*
 *  ======== UARTMSP432_readPolling ========
 */
int UARTMSP432_readPolling(UART_Handle handle, void *buf, size_t size)
{
    int32_t                   count = 0;
    unsigned char            *buffer = (unsigned char *)buf;
    UARTMSP432_Object        *object = handle->object;
    UARTMSP432_HWAttrs const *hwAttrs = handle->hwAttrs;

    /* Read characters. */
    while (size) {
        /* Grab data from the RingBuf before getting it from the RX data reg */
        MAP_UART_disableInterrupt(hwAttrs->baseAddr,
            EUSCI_A_UART_RECEIVE_INTERRUPT);
        if (RingBuf_get(&object->ringBuffer, buffer) == -1) {
            /* RX interrupts are disabled; driverlib will poll for us */
            *buffer = MAP_UART_receiveData(hwAttrs->baseAddr);
        }
        if (object->state.rxEnabled) {
            MAP_UART_enableInterrupt(hwAttrs->baseAddr,
                EUSCI_A_UART_RECEIVE_INTERRUPT);
        }

        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) {
                while (!MAP_UART_getInterruptStatus(hwAttrs->baseAddr,
                    EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG));
                MAP_UART_transmitData(hwAttrs->baseAddr,  '\r');
            }
            *buffer = '\n';
        }

        /* Echo character if enabled. */
        if (object->state.readDataMode == UART_DATA_TEXT &&
                object->state.readEcho) {
            while (!MAP_UART_getInterruptStatus(hwAttrs->baseAddr,
                EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG));
            MAP_UART_transmitData(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);
}
/*
 *  ======== UARTMSP432_write ========
 */
int UARTMSP432_write(UART_Handle handle, const void *buffer, size_t size)
{
    uintptr_t                 key;
    UARTMSP432_Object        *object = handle->object;
    UARTMSP432_HWAttrs const *hwAttrs = handle->hwAttrs;

    if (!size) {
        return 0;
    }

    key = HwiP_disable();

    if (object->writeCount) {
        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;

    HwiP_restore(key);

    /*
     * Set power constraint to keep peripheral active during transfer and
     * to prevent a performance level change
     */
    Power_setConstraint(PowerMSP432_DISALLOW_DEEPSLEEP_0);
    Power_setConstraint(PowerMSP432_DISALLOW_PERF_CHANGES);

    /* Enabling TX interrupt will trigger the Hwi which will handle the write */
    MAP_UART_enableInterrupt(hwAttrs->baseAddr, EUSCI_A_UART_TRANSMIT_INTERRUPT);

    /* 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_pend(object->writeSem, object->writeTimeout) !=
                SemaphoreP_OK) {
            /* Semaphore timed out, make the write empty and log the write. */
            MAP_UART_disableInterrupt(hwAttrs->baseAddr,
                EUSCI_A_UART_TRANSMIT_INTERRUPT);
            object->writeCount = 0;

            DebugP_log2("UART:(%p) Write timed out, %d bytes written",
                hwAttrs->baseAddr, object->writeCount);
        }
        return (object->writeSize - object->writeCount);
    }

    return (0);
}
/*
 *  ======== UARTMSP432_close ========
 */
void UARTMSP432_close(UART_Handle handle)
{
    unsigned int              i;
    UARTMSP432_Object        *object = handle->object;
    UARTMSP432_HWAttrs const *hwAttrs = handle->hwAttrs;

    MAP_UART_disableInterrupt(hwAttrs->baseAddr,
        EUSCI_A_UART_RECEIVE_INTERRUPT | EUSCI_A_UART_TRANSMIT_INTERRUPT);
    MAP_UART_disableInterrupt(hwAttrs->baseAddr,
        EUSCI_A_UART_RECEIVE_ERRONEOUSCHAR_INTERRUPT |
        EUSCI_A_UART_BREAKCHAR_INTERRUPT);
    MAP_UART_disableModule(hwAttrs->baseAddr);

    if (object->hwiHandle) {
        HwiP_delete(object->hwiHandle);
    }
    if (object->writeSem) {
        SemaphoreP_delete(object->writeSem);
    }
    if (object->readSem) {
        SemaphoreP_delete(object->readSem);
    }

    /* Remove power constraints */
    for (i = 0; object->perfConstraintMask; i++) {
        if (object->perfConstraintMask & 0x01) {
            Power_releaseConstraint(PowerMSP432_DISALLOW_PERFLEVEL_0 + i);
        }
        object->perfConstraintMask >>= 1;
    }
    if (object->state.rxEnabled) {
        Power_releaseConstraint(PowerMSP432_DISALLOW_DEEPSLEEP_0);
        Power_releaseConstraint(PowerMSP432_DISALLOW_PERF_CHANGES);
    }
    Power_releaseConstraint(PowerMSP432_DISALLOW_SHUTDOWN_0);
    Power_releaseConstraint(PowerMSP432_DISALLOW_SHUTDOWN_1);
    Power_unregisterNotify(&object->perfChangeNotify);

    object->state.opened = false;

    DebugP_log1("UART:(%p) closed", hwAttrs->baseAddr);
}
/*
 *  ======== writeData ========
 */
static void writeData(UART_Handle handle)
{
    unsigned char            *writePtr;
    UARTMSP432_Object        *object = handle->object;
    UARTMSP432_HWAttrs const *hwAttrs = handle->hwAttrs;

    if (object->writeCount) {
        writePtr = (unsigned char*) object->writeBuf + object->writeSize -
            object->writeCount;

        /* If mode is TEXT process the characters */
        if (object->state.writeDataMode == UART_DATA_TEXT) {
            if (object->state.writeCR) {
                MAP_UART_transmitData(hwAttrs->baseAddr, '\r');
                object->writeCount--;
                object->state.writeCR = false;
                DebugP_log2("UART:(%p) Wrote 0x%x", hwAttrs->baseAddr, '\r');
            }
            else {
                /* Add a return if next character is a newline. */
                MAP_UART_transmitData(hwAttrs->baseAddr, *writePtr);
                if (*writePtr != '\n') {
                    object->writeCount--;
                }
                else {
                    object->state.writeCR = true;
                }
                DebugP_log2("UART:(%p) Wrote 0x%x", hwAttrs->baseAddr, *writePtr);
            }
        }
        else {
            MAP_UART_transmitData(hwAttrs->baseAddr, *writePtr);
            object->writeCount--;
            DebugP_log2("UART:(%p) Wrote 0x%x", hwAttrs->baseAddr, *writePtr);
        }

        if (!object->writeCount) {
            MAP_UART_disableInterrupt(hwAttrs->baseAddr,
                EUSCI_A_UART_TRANSMIT_INTERRUPT);
            Power_releaseConstraint(PowerMSP432_DISALLOW_DEEPSLEEP_0);
            Power_releaseConstraint(PowerMSP432_DISALLOW_PERF_CHANGES);
            object->writeCallback(handle, (void *) object->writeBuf,
                object->writeSize);
        }
    }
}
/*
 *  ======== initHW ========
 *
 *  Configures UART peripheral
 */
static void initHw(UARTMSP432_Object *object,
    UARTMSP432_HWAttrs const *hwAttrs, uint32_t inputClkFreq)
{
    int32_t           baudrateIndex;
    eUSCI_UART_Config uartConfig;

    /*
     * This will never return -1, constarints prevent unsupported performance
     * levels
     */
    baudrateIndex = findBaudDividerIndex(hwAttrs->baudrateLUT,
        hwAttrs->numBaudrateEntries, object->baudRate, inputClkFreq);

    uartConfig.selectClockSource = hwAttrs->clockSource;
    uartConfig.clockPrescalar = hwAttrs->baudrateLUT[baudrateIndex].prescalar;
    uartConfig.firstModReg = hwAttrs->baudrateLUT[baudrateIndex].hwRegUCBRFx;
    uartConfig.secondModReg = hwAttrs->baudrateLUT[baudrateIndex].hwRegUCBRSx;
    uartConfig.parity = parityTypes[object->parityType];
    uartConfig.msborLsbFirst = hwAttrs->bitOrder;
    uartConfig.numberofStopBits = stopBits[object->stopBits];
    uartConfig.uartMode = EUSCI_A_UART_MODE;
    uartConfig.overSampling = hwAttrs->baudrateLUT[baudrateIndex].sampling;

    MAP_UART_initModule(hwAttrs->baseAddr, &uartConfig);

    /* Enable UART and disable its interrupts. */
    MAP_UART_enableInterrupt(hwAttrs->baseAddr,
        EUSCI_A_UART_BREAKCHAR_INTERRUPT |
        EUSCI_A_UART_RECEIVE_ERRONEOUSCHAR_INTERRUPT);
    MAP_UART_disableInterrupt(hwAttrs->baseAddr, EUSCI_A_UART_TRANSMIT_INTERRUPT);

    MAP_UART_enableModule(hwAttrs->baseAddr);
    MAP_UART_enableInterrupt(hwAttrs->baseAddr, EUSCI_A_UART_RECEIVE_INTERRUPT);

    DebugP_log3("UART:(%p) CPU freq: %d; UART baudRate to %d", hwAttrs->baseAddr,
        inputClkFreq, object->baudRate);
}
/*
 *  ======== UARTMSP432_control ========
 *  @pre    Function assumes that the handle is not NULL
 */
int UARTMSP432_control(UART_Handle handle, unsigned int cmd, void *arg)
{
    int                       bufferCount;
    unsigned char             data;
    UARTMSP432_Object        *object = handle->object;
    UARTMSP432_HWAttrs const *hwAttrs = handle->hwAttrs;

    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) {
                /*
                 * Set power constraints to keep peripheral active receiving
                 * RX interrupts and prevent a performance level change.
                 */
                Power_setConstraint(PowerMSP432_DISALLOW_DEEPSLEEP_0);
                Power_setConstraint(PowerMSP432_DISALLOW_PERF_CHANGES);
                MAP_UART_enableInterrupt(hwAttrs->baseAddr,
                    EUSCI_A_UART_RECEIVE_INTERRUPT);
                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_UART_disableInterrupt(hwAttrs->baseAddr,
                    EUSCI_A_UART_RECEIVE_INTERRUPT);
                /*
                 * Remove constraints, this will allow the device to enter
                 * LPM3 and higher as well as allow performance level changes
                 * by the application.
                 */
                Power_releaseConstraint(PowerMSP432_DISALLOW_DEEPSLEEP_0);
                Power_releaseConstraint(PowerMSP432_DISALLOW_PERF_CHANGES);
                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);
                return (UART_STATUS_SUCCESS);
            }
            DebugP_log1("UART:(%p) UART_CMD_RXDISABLE: Already disabled",
                hwAttrs->baseAddr);
            return (UART_STATUS_ERROR);

        default:
            DebugP_log2("UART:(%p) UART CMD undefined: %d",
                hwAttrs->baseAddr, cmd);
            return (UART_STATUS_UNDEFINEDCMD);
    }
}