nu_scuart.c 8.8 KB
Newer Older
W
Wayne Lin 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
/**************************************************************************//**
 * @file     scuart.c
 * @version  V3.00
 * @brief    Smartcard UART mode (SCUART) driver source file
 *
 * @copyright SPDX-License-Identifier: Apache-2.0
 * @copyright Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
 *****************************************************************************/
#include "NuMicro.h"


/** @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 = 0, u32Num = 0, u32ClkFreq = __HIRC, u32Div = 0;

    /* Get smartcard module clock source and divider */
    if((sc == SC0) || (sc == SC0_NS))
    {
        u32Num = 0UL;
        u32ClkSrc = CLK_GetModuleClockSource(SC0_MODULE);
        u32Div = CLK_GetModuleClockDivider(SC0_MODULE);
    }
    else if((sc == SC1) || (sc == SC1_NS))
    {
        u32Num = 1UL;
        u32ClkSrc = CLK_GetModuleClockSource(SC1_MODULE);
        u32Div = CLK_GetModuleClockDivider(SC1_MODULE);
    }
    else if((sc == SC2) || (sc == SC2_NS))
    {
        u32Num = 2UL;
        u32ClkSrc = CLK_GetModuleClockSource(SC2_MODULE);
        u32Div = CLK_GetModuleClockDivider(SC2_MODULE);
    }
    else
    {
        u32ClkFreq = 0UL;
    }

    if(u32ClkFreq != 0UL)
    {
        /* Get smartcard module clock */
        if(u32ClkSrc == 0UL)
        {
            u32ClkFreq = __HXT;
        }
        else if(u32ClkSrc == 1UL)
        {
            u32ClkFreq = CLK_GetPLLClockFreq();
        }
        else if(u32ClkSrc == 2UL)
        {
            if(u32Num == 1UL)
            {
                u32ClkFreq = CLK_GetPCLK1Freq();
            }
            else
            {
                u32ClkFreq = CLK_GetPCLK0Freq();
            }
        }
        else
        {
            u32ClkFreq = __HIRC;
        }

        u32ClkFreq /= (u32Div + 1UL);
    }

    return u32ClkFreq;
}
/** @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 u32ClkFreq = SCUART_GetClock(sc), u32Div;

    /* Calculate divider for target baudrate */
    u32Div = (u32ClkFreq + (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 (u32ClkFreq / (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) == SC_STATUS_RXEMPTY_Msk)
        {
            /* No data available */
            break;
        }
        /* Get data from FIFO */
        pu8RxBuf[u32Count] = (uint8_t)SCUART_READ(sc);
    }

    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 u32ClkFreq = 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 = ((u32ClkFreq + (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 (u32ClkFreq / (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) == SC_STATUS_TXFULL_Msk) {}

        /* 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 */