/* * ======== 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); }
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); } }