/**************************************************************************//** * @file scuart.c * @version V3.00 * @brief Smartcard UART mode (SCUART) driver source file * * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of Nuvoton Technology Corp. 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 HOLDER 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 "NuMicro.h" static uint32_t SCUART_GetClock(SC_T *sc); /** @addtogroup Standard_Driver Standard Driver @{ */ /** @addtogroup SCUART_Driver SCUART Driver @{ */ /** @addtogroup SCUART_EXPORTED_FUNCTIONS SCUART Exported Functions @{ */ /** * @brief Disable smartcard interface * * @param sc The pointer of smartcard module. * * @return None * * @details The function is used to disable smartcard interface UART mode. */ void SCUART_Close(SC_T* sc) { sc->INTEN = 0UL; sc->UARTCTL = 0UL; sc->CTL = 0UL; } /** @cond HIDDEN_SYMBOLS */ /** * @brief Returns module clock of specified SC interface * * @param[in] sc The pointer of smartcard module. * * @return Module clock of specified SC interface. */ static uint32_t SCUART_GetClock(SC_T *sc) { uint32_t u32ClkSrc, u32Num, u32Clk = __HIRC, u32Div; /* Get smartcard module clock source and divider */ if(sc == SC0) { u32Num = 0UL; u32ClkSrc = CLK_GetModuleClockSource(SC0_MODULE); u32Div = CLK_GetModuleClockDivider(SC0_MODULE); } else if(sc == SC1) { u32Num = 1UL; u32ClkSrc = CLK_GetModuleClockSource(SC1_MODULE); u32Div = CLK_GetModuleClockDivider(SC1_MODULE); } else if(sc == SC2) { u32Num = 2UL; u32ClkSrc = CLK_GetModuleClockSource(SC2_MODULE); u32Div = CLK_GetModuleClockDivider(SC2_MODULE); } else { u32Clk = 0UL; } if(u32Clk == 0UL) { ; /* Invalid sc port */ } else { /* Get smartcard module clock */ if(u32ClkSrc == 0UL) { u32Clk = __HXT; } else if(u32ClkSrc == 1UL) { u32Clk = CLK_GetPLLClockFreq(); } else if(u32ClkSrc == 2UL) { if(u32Num == 1UL) { u32Clk = CLK_GetPCLK1Freq(); } else { u32Clk = CLK_GetPCLK0Freq(); } } else { u32Clk = __HIRC; } u32Clk /= (u32Div + 1UL); } return u32Clk; } /** @endcond HIDDEN_SYMBOLS */ /** * @brief Enable smartcard module UART mode and set baudrate * * @param[in] sc The pointer of smartcard module. * @param[in] u32Baudrate Target baudrate of smartcard UART module. * * @return Actual baudrate of smartcard UART mode * * @details This function use to enable smartcard module UART mode and set baudrate. * * @note This function configures character width to 8 bits, 1 stop bit, and no parity. * And can use \ref SCUART_SetLineConfig function to update these settings. * The baudrate clock source comes from SC_CLK/SC_DIV, where SC_CLK is controlled * by SCxSEL in CLKSEL3 register, SC_DIV is controlled by SCxDIV in CLKDIV1 * register. Since the baudrate divider is 12-bit wide and must be larger than 4, * (clock source / baudrate) must be larger or equal to 5 and smaller or equal to * 4096. Otherwise this function cannot configure SCUART to work with target baudrate. */ uint32_t SCUART_Open(SC_T* sc, uint32_t u32Baudrate) { uint32_t u32Clk = SCUART_GetClock(sc), u32Div; /* Calculate divider for target baudrate */ u32Div = (u32Clk + (u32Baudrate >> 1) - 1UL) / u32Baudrate - 1UL; sc->CTL = SC_CTL_SCEN_Msk | SC_CTL_NSB_Msk; /* Enable smartcard interface and stop bit = 1 */ sc->UARTCTL = SCUART_CHAR_LEN_8 | SCUART_PARITY_NONE | SC_UARTCTL_UARTEN_Msk; /* Enable UART mode, disable parity and 8 bit per character */ sc->ETUCTL = u32Div; return(u32Clk / (u32Div + 1UL)); } /** * @brief Read Rx data from Rx FIFO * * @param[in] sc The pointer of smartcard module. * @param[in] pu8RxBuf The buffer to store receive the data. * @param[in] u32ReadBytes Target number of characters to receive * * @return Actual character number reads to buffer * * @details The function is used to read data from Rx FIFO. * * @note This function does not block and return immediately if there's no data available. */ uint32_t SCUART_Read(SC_T* sc, uint8_t pu8RxBuf[], uint32_t u32ReadBytes) { uint32_t u32Count; for(u32Count = 0UL; u32Count < u32ReadBytes; u32Count++) { if(SCUART_GET_RX_EMPTY(sc)) /* no data available */ { break; } pu8RxBuf[u32Count] = (uint8_t)SCUART_READ(sc); /* get data from FIFO */ } return u32Count; } /** * @brief Configure smartcard UART mode line setting * * @param[in] sc The pointer of smartcard module. * @param[in] u32Baudrate Target baudrate of smartcard UART mode. If this value is 0, SC UART baudrate will not change. * @param[in] u32DataWidth The data length, could be: * - \ref SCUART_CHAR_LEN_5 * - \ref SCUART_CHAR_LEN_6 * - \ref SCUART_CHAR_LEN_7 * - \ref SCUART_CHAR_LEN_8 * @param[in] u32Parity The parity setting, could be: * - \ref SCUART_PARITY_NONE * - \ref SCUART_PARITY_ODD * - \ref SCUART_PARITY_EVEN * @param[in] u32StopBits The stop bit length, could be: * - \ref SCUART_STOP_BIT_1 * - \ref SCUART_STOP_BIT_2 * * @return Actual baudrate of smartcard UART mode * * @details The baudrate clock source comes from SC_CLK/SC_DIV, where SC_CLK is controlled * by SCxSEL in CLKSEL3 register, SC_DIV is controlled by SCxDIV in CLKDIV1 * register. Since the baudrate divider is 12-bit wide and must be larger than 4, * (clock source / baudrate) must be larger or equal to 5 and smaller or equal to * 4096. Otherwise this function cannot configure SCUART to work with target baudrate. */ uint32_t SCUART_SetLineConfig(SC_T* sc, uint32_t u32Baudrate, uint32_t u32DataWidth, uint32_t u32Parity, uint32_t u32StopBits) { uint32_t u32Clk = SCUART_GetClock(sc), u32Div; if(u32Baudrate == 0UL) { /* Keep original baudrate setting */ u32Div = sc->ETUCTL & SC_ETUCTL_ETURDIV_Msk; } else { /* Calculate divider for target baudrate */ u32Div = ((u32Clk + (u32Baudrate >> 1) - 1UL) / u32Baudrate) - 1UL; sc->ETUCTL = u32Div; } sc->CTL = u32StopBits | SC_CTL_SCEN_Msk; /* Set stop bit */ sc->UARTCTL = u32Parity | u32DataWidth | SC_UARTCTL_UARTEN_Msk; /* Set character width and parity */ return (u32Clk / (u32Div + 1UL)); } /** * @brief Set receive timeout count * * @param[in] sc The pointer of smartcard module. * @param[in] u32TOC Rx time-out counter, using baudrate as counter unit. Valid range are 0~0x1FF, * set this value to 0 will disable time-out counter. * * @return None * * @details The time-out counter resets and starts counting whenever the Rx buffer received a * new data word. Once the counter decrease to 1 and no new data is received or CPU * does not read any data from FIFO, a receiver time-out interrupt will be generated. */ void SCUART_SetTimeoutCnt(SC_T* sc, uint32_t u32TOC) { sc->RXTOUT = u32TOC; } /** * @brief Write data into transmit FIFO to send data out * * @param[in] sc The pointer of smartcard module. * @param[in] pu8TxBuf The buffer containing data to send to transmit FIFO. * @param[in] u32WriteBytes Number of data to send. * * @return None * * @details This function is used to write data into Tx FIFO to send data out. * * @note This function blocks until all data write into FIFO. */ void SCUART_Write(SC_T* sc, uint8_t pu8TxBuf[], uint32_t u32WriteBytes) { uint32_t u32Count; for(u32Count = 0UL; u32Count != u32WriteBytes; u32Count++) { /* Wait 'til FIFO not full */ while(SCUART_GET_TX_FULL(sc)) { ; } /* Write 1 byte to FIFO */ sc->DAT = pu8TxBuf[u32Count]; /* Write 1 byte to FIFO */ } } /*@}*/ /* end of group SCUART_EXPORTED_FUNCTIONS */ /*@}*/ /* end of group SCUART_Driver */ /*@}*/ /* end of group Standard_Driver */ /*** (C) COPYRIGHT 2019 Nuvoton Technology Corp. ***/