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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
|
/**************************************************************************//**
* @file scuart.c
* @version V3.00
* @brief Smartcard UART mode (SCUART) driver source file
*
* @copyright SPDX-License-Identifier: Apache-2.0
* @copyright Copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NuMicro.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup SCUART_Driver SCUART Driver
@{
*/
int32_t g_SCUART_i32ErrCode = 0; /*!< SCUART global error code */
/** @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)
{
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
{
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 Actual number of data put into SCUART Tx FIFO
*
* @details This function is used to write data into Tx FIFO to send data out.
*
* @note This function sets g_SCUART_i32ErrCode to SCUART_TIMEOUT_ERR if the Tx FIFO
* blocks longer than expected.
*/
uint32_t SCUART_Write(SC_T *sc, uint8_t pu8TxBuf[], uint32_t u32WriteBytes)
{
uint32_t u32Count;
/* Baudrate * (start bit + 8-bit data + 1-bit parity + 2-bit stop) */
uint32_t u32Delay = (SystemCoreClock / SCUART_GetClock(sc)) * sc->ETUCTL * 12, i;
g_SCUART_i32ErrCode = 0;
for (u32Count = 0UL; u32Count != u32WriteBytes; u32Count++)
{
i = 0;
/* Wait 'til FIFO not full */
while (SCUART_GET_TX_FULL(sc))
{
/* Block longer than expected. Maybe some interrupt disable SCUART clock? */
if (i++ > u32Delay)
{
g_SCUART_i32ErrCode = SCUART_TIMEOUT_ERR;
return u32Count;
}
}
/* Write 1 byte to FIFO */
sc->DAT = pu8TxBuf[u32Count];
}
return u32Count;
}
/**@}*/ /* end of group SCUART_EXPORTED_FUNCTIONS */
/**@}*/ /* end of group SCUART_Driver */
/**@}*/ /* end of group Standard_Driver */
|