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