1 /**************************************************************************//**
2  * @file     scuart.c
3  * @version  V3.00
4  * @brief    M480 Smartcard UART mode (SCUART) driver source file
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9 #include "NuMicro.h"
10 
11 static uint32_t SCUART_GetClock(SC_T *sc);
12 
13 /** @addtogroup Standard_Driver Standard Driver
14   @{
15 */
16 
17 /** @addtogroup SCUART_Driver SCUART Driver
18   @{
19 */
20 
21 
22 /** @addtogroup SCUART_EXPORTED_FUNCTIONS SCUART Exported Functions
23   @{
24 */
25 
26 /**
27   * @brief The function is used to disable smartcard interface UART mode.
28   * @param sc The base address of smartcard module.
29   * @return None
30   */
SCUART_Close(SC_T * sc)31 void SCUART_Close(SC_T* sc)
32 {
33     sc->INTEN = 0UL;
34     sc->UARTCTL = 0UL;
35     sc->CTL = 0UL;
36 
37 }
38 /** @cond HIDDEN_SYMBOLS */
39 /**
40   * @brief This function returns module clock of specified SC interface
41   * @param[in] sc The base address of smartcard module.
42   * @return Module clock of specified SC interface
43   */
SCUART_GetClock(SC_T * sc)44 static uint32_t SCUART_GetClock(SC_T *sc)
45 {
46     uint32_t u32ClkSrc, u32Num, u32Clk;
47 
48     if(sc == SC0)
49     {
50         u32Num = 0UL;
51     }
52     else if(sc == SC1)
53     {
54         u32Num = 1UL;
55     }
56     else
57     {
58         u32Num = 2UL;
59     }
60 
61     u32ClkSrc = (CLK->CLKSEL3 >> (2UL * u32Num)) & CLK_CLKSEL3_SC0SEL_Msk;
62 
63     /* Get smartcard module clock */
64     if(u32ClkSrc == 0UL)
65     {
66         u32Clk = __HXT;
67     }
68     else if(u32ClkSrc == 1UL)
69     {
70         u32Clk = CLK_GetPLLClockFreq();
71     }
72     else if(u32ClkSrc == 2UL)
73     {
74         if(u32Num == 1UL)
75         {
76             u32Clk = CLK_GetPCLK1Freq();
77         }
78         else
79         {
80             u32Clk = CLK_GetPCLK0Freq();
81         }
82     }
83     else
84     {
85         u32Clk = __HIRC;
86     }
87 
88     u32Clk /= (((CLK->CLKDIV1 >> (8UL * u32Num)) & CLK_CLKDIV1_SC0DIV_Msk) + 1UL);
89 
90 
91     return u32Clk;
92 }
93 
94 /** @endcond HIDDEN_SYMBOLS */
95 
96 /**
97   * @brief This function use to enable smartcard module UART mode and set baudrate.
98   * @param[in] sc The base address of smartcard module.
99   * @param[in] u32baudrate Target baudrate of smartcard module.
100   * @return Actual baudrate of smartcard mode
101   * @details This function configures character width to 8 bits, 1 stop bit, and no parity.
102   *          And can use \ref SCUART_SetLineConfig function to update these settings
103   *          The baudrate clock source comes from SC_CLK/SC_DIV, where SC_CLK is controlled
104   *          by SCxSEL in CLKSEL3 register, SC_DIV is controlled by SCxDIV in CLKDIV1
105   *          register. Since the baudrate divider is 12-bit wide and must be larger than 4,
106   *          (clock source / baudrate) must be larger or equal to 5 and smaller or equal to
107   *          4096. Otherwise this function cannot configure SCUART to work with target baudrate.
108   */
SCUART_Open(SC_T * sc,uint32_t u32baudrate)109 uint32_t SCUART_Open(SC_T* sc, uint32_t u32baudrate)
110 {
111     uint32_t u32Clk = SCUART_GetClock(sc), u32Div;
112 
113     /* Calculate divider for target baudrate */
114     u32Div = (u32Clk + (u32baudrate >> 1) - 1UL) / u32baudrate - 1UL;
115 
116     /* Enable smartcard interface and stop bit = 1 */
117     sc->CTL = SC_CTL_SCEN_Msk | SC_CTL_NSB_Msk;
118     /* Enable UART mode, disable parity and 8 bit per character */
119     sc->UARTCTL = SCUART_CHAR_LEN_8 | SCUART_PARITY_NONE | SC_UARTCTL_UARTEN_Msk;
120     sc->ETUCTL = u32Div;
121 
122     return(u32Clk / (u32Div + 1UL));
123 }
124 
125 /**
126   * @brief The function is used to read Rx data from RX FIFO.
127   * @param[in] sc The base address of smartcard module.
128   * @param[in] pu8RxBuf The buffer to store receive the data
129   * @param[in] u32ReadBytes Target number of characters to receive
130   * @return Actual character number reads to buffer
131   * @note This function does not block and return immediately if there's no data available
132   */
SCUART_Read(SC_T * sc,uint8_t pu8RxBuf[],uint32_t u32ReadBytes)133 uint32_t SCUART_Read(SC_T* sc, uint8_t pu8RxBuf[], uint32_t u32ReadBytes)
134 {
135     uint32_t u32Count;
136 
137     for(u32Count = 0UL; u32Count < u32ReadBytes; u32Count++)
138     {
139         if(SCUART_GET_RX_EMPTY(sc))   /* no data available */
140         {
141             break;
142         }
143         pu8RxBuf[u32Count] = (uint8_t)SCUART_READ(sc);    /* get data from FIFO */
144     }
145 
146     return u32Count;
147 }
148 
149 /**
150   * @brief This function use to configure smartcard UART mode line setting.
151   * @param[in] sc The base address of smartcard module.
152   * @param[in] u32Baudrate Target baudrate of smartcard module. If this value is 0, UART baudrate will not change.
153   * @param[in] u32DataWidth The data length, could be
154   *                 - \ref SCUART_CHAR_LEN_5
155   *                 - \ref SCUART_CHAR_LEN_6
156   *                 - \ref SCUART_CHAR_LEN_7
157   *                 - \ref SCUART_CHAR_LEN_8
158   * @param[in] u32Parity The parity setting, could be
159   *                 - \ref SCUART_PARITY_NONE
160   *                 - \ref SCUART_PARITY_ODD
161   *                 - \ref SCUART_PARITY_EVEN
162   * @param[in] u32StopBits The stop bit length, could be
163   *                 - \ref SCUART_STOP_BIT_1
164   *                 - \ref SCUART_STOP_BIT_2
165   * @return Actual baudrate of smartcard
166   * @details The baudrate clock source comes from SC_CLK/SC_DIV, where SC_CLK is controlled
167   *          by SCxSEL in CLKSEL3 register, SC_DIV is controlled by SCxDIV in CLKDIV1
168   *          register. Since the baudrate divider is 12-bit wide and must be larger than 4,
169   *          (clock source / baudrate) must be larger or equal to 5 and smaller or equal to
170   *          4096. Otherwise this function cannot configure SCUART to work with target baudrate.
171   */
SCUART_SetLineConfig(SC_T * sc,uint32_t u32Baudrate,uint32_t u32DataWidth,uint32_t u32Parity,uint32_t u32StopBits)172 uint32_t SCUART_SetLineConfig(SC_T* sc, uint32_t u32Baudrate, uint32_t u32DataWidth, uint32_t u32Parity, uint32_t  u32StopBits)
173 {
174 
175     uint32_t u32Clk = SCUART_GetClock(sc), u32Div;
176 
177     if(u32Baudrate == 0UL)    /* keep original baudrate setting */
178     {
179         u32Div = sc->ETUCTL & SC_ETUCTL_ETURDIV_Msk;
180     }
181     else
182     {
183         /* Calculate divider for target baudrate */
184         u32Div = (u32Clk + (u32Baudrate >> 1) - 1UL)/ u32Baudrate - 1UL;
185         sc->ETUCTL = u32Div;
186     }
187     /* Set stop bit */
188     sc->CTL = u32StopBits | SC_CTL_SCEN_Msk;
189     /* Set character width and parity */
190     sc->UARTCTL = u32Parity | u32DataWidth | SC_UARTCTL_UARTEN_Msk;
191 
192     return(u32Clk / (u32Div + 1UL));
193 }
194 
195 /**
196   * @brief This function use to set receive timeout count.
197   * @param[in] sc The base address of smartcard module.
198   * @param[in] u32TOC Rx timeout counter, using baudrate as counter unit. Valid range are 0~0x1FF,
199   *                   set this value to 0 will disable timeout counter
200   * @return None
201   * @details The time-out counter resets and starts counting whenever the RX buffer received a
202   *          new data word. Once the counter decrease to 1 and no new data is received or CPU
203   *          does not read any data from FIFO, a receiver time-out interrupt will be generated.
204   */
SCUART_SetTimeoutCnt(SC_T * sc,uint32_t u32TOC)205 void SCUART_SetTimeoutCnt(SC_T* sc, uint32_t u32TOC)
206 {
207     sc->RXTOUT= u32TOC;
208 }
209 
210 
211 /**
212   * @brief This function is to write data into transmit FIFO to send data out.
213   * @param[in] sc The base address of smartcard module.
214   * @param[in] pu8TxBuf The buffer containing data to send to transmit FIFO.
215   * @param[in] u32WriteBytes Number of data to send.
216   * @return None
217   * @note This function blocks until all data write into FIFO
218   */
SCUART_Write(SC_T * sc,uint8_t pu8TxBuf[],uint32_t u32WriteBytes)219 void SCUART_Write(SC_T* sc,uint8_t pu8TxBuf[], uint32_t u32WriteBytes)
220 {
221     uint32_t u32Count;
222 
223     for(u32Count = 0UL; u32Count != u32WriteBytes; u32Count++)
224     {
225         /* Wait 'til FIFO not full */
226         while(SCUART_GET_TX_FULL(sc))
227         {
228             ;
229         }
230         /* Write 1 byte to FIFO */
231         sc->DAT = pu8TxBuf[u32Count];
232     }
233 }
234 
235 
236 /*@}*/ /* end of group SCUART_EXPORTED_FUNCTIONS */
237 
238 /*@}*/ /* end of group SCUART_Driver */
239 
240 /*@}*/ /* end of group Standard_Driver */
241 
242 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
243