/* * Copyright (c) 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 #if defined(__MSPM0_HAS_UART_MAIN__) || defined(__MSPM0_HAS_UART_EXTD__) void DL_UART_init(UART_Regs *uart, const DL_UART_Config *config) { DL_UART_disable(uart); DL_Common_updateReg(&uart->CTL0, (uint32_t) config->mode | (uint32_t) config->direction | (uint32_t) config->flowControl, UART_CTL0_RXE_MASK | UART_CTL0_TXE_MASK | UART_CTL0_MODE_MASK | UART_CTL0_RTSEN_MASK | UART_CTL0_CTSEN_MASK | UART_CTL0_FEN_MASK); DL_Common_updateReg(&uart->LCRH, (uint32_t) config->parity | (uint32_t) config->wordLength | (uint32_t) config->stopBits, UART_LCRH_PEN_ENABLE | UART_LCRH_EPS_MASK | UART_LCRH_SPS_MASK | UART_LCRH_WLEN_MASK | UART_LCRH_STP2_MASK); } void DL_UART_setClockConfig(UART_Regs *uart, const DL_UART_ClockConfig *config) { uart->CLKSEL = (uint32_t) config->clockSel; uart->CLKDIV = (uint32_t) config->divideRatio; } void DL_UART_getClockConfig(const UART_Regs *uart, DL_UART_ClockConfig *config) { config->clockSel = (DL_UART_CLOCK) uart->CLKSEL; config->divideRatio = (DL_UART_CLOCK_DIVIDE_RATIO) uart->CLKDIV; } void DL_UART_configBaudRate( UART_Regs *uart, uint32_t clockFreq, uint32_t baudRate) { uint32_t divisor; /* * The baud rate divisor, brd, is calculated with the following formula: * brd = ibrd.fbrd = clockOutput / (OVS * baudRate) * where ibrd is the integer part, fbrd is the fractional part. * Since fbrd is 6 bits, multiply brd by 64: * 64 * brd = (clockOutput * 64) / (16 * baudRate) * = (clockOutput * 4) / baudRate * add 1/2 to round the least significant bit of fbrd: * 64 * brd + 1/2 = (clockOutput * 8 / (2 * baudRate) + 1/2 * divisor = 64*brd+1/2 = [(clockOutput * 8)/ baudRate + 1] / 2 * * The lower 6 bits is fbrd, upper part is ibrd * Note: If ibrd is 0, FBRD will be ignored and no data will be * transferred. */ /* Calculate baud rate divisor based on OVS: */ if ((baudRate * (uint32_t) 8) > clockFreq) { DL_UART_setOversampling(uart, DL_UART_OVERSAMPLING_RATE_3X); divisor = ((clockFreq * (uint32_t) 64) / (baudRate * (uint32_t) 3)) + ((uint32_t) 1 / (uint32_t) 2); } else if ((baudRate * (uint32_t) 16) > clockFreq) { DL_UART_setOversampling(uart, DL_UART_OVERSAMPLING_RATE_8X); baudRate = baudRate / (uint32_t) 2; divisor = (((clockFreq * (uint32_t) 8) / baudRate) + (uint32_t) 1) / (uint32_t) 2; } else { DL_UART_setOversampling(uart, DL_UART_OVERSAMPLING_RATE_16X); divisor = (((clockFreq * (uint32_t) 8) / baudRate) + (uint32_t) 1) / (uint32_t) 2; } /* Set the integer and fractional parts of the baud rate divisor */ DL_UART_setBaudRateDivisor( uart, divisor >> (uint32_t) 6, divisor & (uint32_t) 0x3F); } // TODO: Verify parameters and units /** * @brief Set the IrDA configurations * * Calculates the baud rate divisor given the clock output of the UART clock * source and the target baud rate. This API also enables IrDA mode. * * @param[in] uart Pointer to the register overlay for the peripheral * @param[in] polarity The receive input polarity. * One of @DL_UART_IRDA_POLARITY. * @param[in] pulseLength The length of the IrDA transmit pulse. * @param[in] irdaClk The clock used for the transmit pulse. * One of @DL_UART_IRDA_CLOCK. */ void DL_UART_configIrDAMode(UART_Regs *uart, DL_UART_IRDA_POLARITY polarity, uint32_t pulseLength, DL_UART_IRDA_CLOCK irdaClk) { DL_Common_updateReg(&uart->IRCTL, (uint32_t) polarity | UART_IRCTL_IREN_ENABLE, UART_IRCTL_IRRXPL_MASK | UART_IRCTL_IREN_MASK); DL_UART_setIrDAPulseLength(uart, pulseLength, irdaClk); } void DL_UART_setIrDAPulseLength( UART_Regs *uart, uint32_t pulseLength, DL_UART_IRDA_CLOCK irdaClk) { uint32_t IRTXPL; if (pulseLength == DL_UART_PULSE_WIDTH_3_16_BIT_PERIOD) { // Set IRTXCLK = 0 = BITCLK16 and IRTXPL = 5 DL_Common_updateReg(&uart->IRCTL, 0x14, UART_IRCTL_IRTXCLK_MASK | UART_IRCTL_IRTXPL_MASK); } else { IRTXPL = pulseLength * (uint32_t) 2 * (uint32_t) irdaClk - (uint32_t) 1; DL_Common_updateReg(&uart->IRCTL, IRTXPL, UART_IRCTL_IRTXCLK_MASK | UART_IRCTL_IRTXPL_MASK); } } uint8_t DL_UART_receiveDataBlocking(const UART_Regs *uart) { while (DL_UART_isRXFIFOEmpty(uart)) { }; return DL_UART_receiveData(uart); } void DL_UART_transmitDataBlocking(UART_Regs *uart, uint8_t data) { while (DL_UART_isTXFIFOFull(uart)) { }; DL_UART_transmitData(uart, data); } bool DL_UART_receiveDataCheck(const UART_Regs *uart, uint8_t *buffer) { bool status; if (DL_UART_isRXFIFOEmpty(uart)) { status = false; } else { *buffer = DL_UART_receiveData(uart); status = true; } return status; } bool DL_UART_transmitDataCheck(UART_Regs *uart, uint8_t data) { bool status; if (DL_UART_isTXFIFOFull(uart)) { status = false; } else { DL_UART_transmitData(uart, data); status = true; } return status; } uint32_t DL_UART_drainRXFIFO( const UART_Regs *uart, uint8_t *buffer, uint32_t maxCount) { uint32_t i; for (i = 0; i < maxCount; i++) { if (!DL_UART_isRXFIFOEmpty(uart)) { buffer[i] = DL_UART_receiveData(uart); } else { break; } } return i; } uint32_t DL_UART_fillTXFIFO( UART_Regs *uart, const uint8_t *buffer, uint32_t count) { uint32_t i; for (i = 0; i < count; i++) { if (!DL_UART_isTXFIFOFull(uart)) { DL_UART_transmitData(uart, buffer[i]); } else { break; } } return i; } #ifdef __MSPM0_HAS_UART_MAIN__ bool DL_UART_Main_saveConfiguration( const UART_Regs *uart, DL_UART_Main_backupConfig *ptr) { bool stateSaved = !ptr->backupRdy; if (stateSaved) { ptr->controlWord = uart->CTL0; ptr->clockSel = uart->CLKSEL; ptr->divideRatio = uart->CLKDIV; ptr->interruptFifoLevelSelectWord = uart->IFLS; ptr->ibrd = uart->IBRD; ptr->fbrd = uart->FBRD; ptr->lineControlRegisterWord = uart->LCRH; ptr->glitchFilterControlWord = uart->GFCTL; ptr->interruptMask0 = uart->CPU_INT.IMASK; ptr->interruptMask1 = uart->DMA_TRIG_RX.IMASK; ptr->interruptMask2 = uart->DMA_TRIG_TX.IMASK; ptr->backupRdy = true; } return stateSaved; } bool DL_UART_Main_restoreConfiguration( UART_Regs *uart, DL_UART_Main_backupConfig *ptr) { bool stateRestored = ptr->backupRdy; if (stateRestored) { /* Set CTL0.ENABLE=0 during initialization */ uart->CTL0 = ptr->controlWord & ~(UART_CTL0_ENABLE_MASK); uart->CLKSEL = ptr->clockSel; uart->CLKDIV = ptr->divideRatio; uart->IFLS = ptr->interruptFifoLevelSelectWord; uart->IBRD = ptr->ibrd; uart->FBRD = ptr->fbrd; uart->LCRH = ptr->lineControlRegisterWord; uart->GFCTL = ptr->glitchFilterControlWord; uart->CPU_INT.IMASK = ptr->interruptMask0; uart->DMA_TRIG_RX.IMASK = ptr->interruptMask1; uart->DMA_TRIG_TX.IMASK = ptr->interruptMask2; /* Re-enable UART if it was originally enabled */ if ((ptr->controlWord & UART_CTL0_ENABLE_MASK) == UART_CTL0_ENABLE_MASK) { DL_UART_enable(uart); } ptr->backupRdy = false; } return stateRestored; } #endif /* __MSPM0_HAS_UART_MAIN__ */ #ifdef __MSPM0_HAS_UART_EXTD__ bool DL_UART_Extend_saveConfiguration( const UART_Regs *uart, DL_UART_Extend_backupConfig *ptr) { bool stateSaved = !ptr->backupRdy; if (stateSaved) { ptr->controlWord = uart->CTL0; ptr->clockSel = uart->CLKSEL; ptr->divideRatio = uart->CLKDIV; ptr->interruptFifoLevelSelectWord = uart->IFLS; ptr->ibrd = uart->IBRD; ptr->fbrd = uart->FBRD; ptr->lineControlRegisterWord = uart->LCRH; ptr->glitchFilterControlWord = uart->GFCTL; ptr->linControlWord = uart->LINCTL; ptr->irdaControlWord = uart->IRCTL; ptr->addressMask = uart->AMASK; ptr->address = uart->ADDR; ptr->interruptMask0 = uart->CPU_INT.IMASK; ptr->interruptMask1 = uart->DMA_TRIG_RX.IMASK; ptr->interruptMask2 = uart->DMA_TRIG_TX.IMASK; ptr->backupRdy = true; } return stateSaved; } bool DL_UART_Extend_restoreConfiguration( UART_Regs *uart, DL_UART_Extend_backupConfig *ptr) { bool stateRestored = ptr->backupRdy; if (stateRestored) { /* Set CTL0.ENABLE=0 during initialization */ uart->CTL0 = ptr->controlWord & ~(UART_CTL0_ENABLE_MASK); uart->CLKSEL = ptr->clockSel; uart->CLKDIV = ptr->divideRatio; uart->IFLS = ptr->interruptFifoLevelSelectWord; uart->IBRD = ptr->ibrd; uart->FBRD = ptr->fbrd; uart->LCRH = ptr->lineControlRegisterWord; uart->GFCTL = ptr->glitchFilterControlWord; uart->LCRH = ptr->lineControlRegisterWord; uart->IRCTL = ptr->irdaControlWord; uart->AMASK = ptr->addressMask; uart->ADDR = ptr->address; uart->CPU_INT.IMASK = ptr->interruptMask0; uart->DMA_TRIG_RX.IMASK = ptr->interruptMask1; uart->DMA_TRIG_TX.IMASK = ptr->interruptMask2; /* Re-enable UART if it was originally enabled */ if ((ptr->controlWord & UART_CTL0_ENABLE_MASK) == UART_CTL0_ENABLE_MASK) { DL_UART_enable(uart); } ptr->backupRdy = false; } return stateRestored; } #endif /* __MSPM0_HAS_UART_EXTD__ */ #endif /* __MSPM0_HAS_UART_MAIN__ || __MSPM0_HAS_UART_EXTD__ */