summaryrefslogtreecommitdiff
path: root/bsp/nuvoton/libraries/nuc980/Driver/Source/nu_scuart.c
blob: ca3e509e4b7bf1e4b4f552e8add05d385edbe6cc (plain)
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
/**************************************************************************//**
 * @file     scuart.c
 * @brief    NUC980 series Smartcard UART mode (SCUART) driver source file
 *
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "nu_scuart.h"

/** @addtogroup Standard_Driver Standard Driver
  @{
*/

/** @addtogroup SCUART_Driver SCUART Driver
  @{
*/


/** @addtogroup SCUART_EXPORTED_FUNCTIONS SCUART Exported Functions
  @{
*/

/**
  * @brief Disable smartcard uart interface.
  * @param sc Smartcard module number
  * @return None
  * @details The function is used to disable smartcard interface UART mode.
  */
void SCUART_Close(UINT sc)
{
    if (sc == 0)
    {
        outpw(REG_SC0_INTEN, 0);
        outpw(REG_SC0_UARTCTL, 0);
        outpw(REG_SC0_CTL, 0);
    }
    else
    {
        outpw(REG_SC1_INTEN, 0);
        outpw(REG_SC1_UARTCTL, 0);
        outpw(REG_SC1_CTL, 0);
    }
}

/// @cond HIDDEN_SYMBOLS
/**
  * @brief This function returns module clock of specified SC interface
  * @param[in] sc Smartcard module number
  * @return Module clock of specified SC interface
  */
static uint32_t SCUART_GetClock(UINT sc)
{
    uint32_t u32Div;

    if (sc == 0)
        u32Div = ((inpw(REG_CLK_DIVCTL6) >> 24) & 0xF) + 1;
    else
        u32Div = ((inpw(REG_CLK_DIVCTL6) >> 28) & 0xF) + 1;

    return 12000000 / u32Div;
}
/// @endcond HIDDEN_SYMBOLS

/**
  * @brief Enable smartcard uart interface.
  * @param[in] sc Smartcard module number
  * @param[in] u32baudrate Target baudrate of smartcard module.
  * @return Actual baudrate of smartcard 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.
  */
UINT SCUART_Open(UINT sc, UINT u32baudrate)
{
    uint32_t u32Clk = SCUART_GetClock(sc), u32Div;

    // Calculate divider for target baudrate
    u32Div = (u32Clk + (u32baudrate >> 1) - 1) / u32baudrate - 1;

    if (sc == 0)
    {
        outpw(REG_SC0_CTL, SC_CTL_SCEN_Msk | SC_CTL_NSB_Msk);   // Enable smartcard interface and stop bit = 1
        outpw(REG_SC0_UARTCTL, SCUART_CHAR_LEN_8 | SCUART_PARITY_NONE | SC_UARTCTL_UARTEN_Msk); // Enable UART mode, disable parity and 8 bit per character
        outpw(REG_SC0_ETUCTL, u32Div);
    }
    else
    {
        outpw(REG_SC1_CTL, SC_CTL_SCEN_Msk | SC_CTL_NSB_Msk);   // Enable smartcard interface and stop bit = 1
        outpw(REG_SC1_UARTCTL, SCUART_CHAR_LEN_8 | SCUART_PARITY_NONE | SC_UARTCTL_UARTEN_Msk); // Enable UART mode, disable parity and 8 bit per character
        outpw(REG_SC1_ETUCTL, u32Div);
    }

    return (u32Clk / (u32Div + 1));
}

/**
  * @brief Read data from smartcard UART interface.
  * @param[in] sc Smartcard module number
  * @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 Rx data from RX FIFO.
  * @note This function does not block and return immediately if there's no data available.
  */
UINT SCUART_Read(UINT sc, char *pu8RxBuf, UINT u32ReadBytes)
{
    uint32_t u32Count;

    if (sc == 0)
    {
        for (u32Count = 0; u32Count < u32ReadBytes; u32Count++)
        {
            if (inpw(REG_SC0_STATUS) & SC_STATUS_RXEMPTY_Msk)  // no data available
            {
                break;
            }
            pu8RxBuf[u32Count] = inpw(REG_SC0_DAT);    // get data from FIFO
        }
    }
    else
    {
        for (u32Count = 0; u32Count < u32ReadBytes; u32Count++)
        {
            if (inpw(REG_SC1_STATUS) & SC_STATUS_RXEMPTY_Msk)  // no data available
            {
                break;
            }
            pu8RxBuf[u32Count] = inpw(REG_SC1_DAT);    // get data from FIFO
        }

    }

    return u32Count;
}

/**
  * @brief This function use to config smartcard UART mode line setting.
  * @param[in] sc Smartcard module number
  * @param[in] u32Baudrate Target baudrate of smartcard module. If this value is 0, 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.
  * @details Smartcard UART mode is operated in LIN data frame.
  */
UINT SCUART_SetLineConfig(UINT sc, UINT u32Baudrate, UINT u32DataWidth, UINT u32Parity, UINT  u32StopBits)
{

    uint32_t u32Clk = SCUART_GetClock(sc), u32Div;

    if (u32Baudrate == 0)   // keep original baudrate setting
    {
        u32Div = (sc == 0) ? inpw(REG_SC0_ETUCTL) & 0xFFF : inpw(REG_SC1_ETUCTL) & 0xFFF;
    }
    else
    {
        // Calculate divider for target baudrate
        u32Div = (u32Clk + (u32Baudrate >> 1) - 1) / u32Baudrate - 1;
        if (sc == 0)
            outpw(REG_SC0_ETUCTL, u32Div);
        else
            outpw(REG_SC1_ETUCTL, u32Div);
    }

    if (sc == 0)
    {
        outpw(REG_SC0_CTL, u32StopBits | SC_CTL_SCEN_Msk);  // Set stop bit
        outpw(REG_SC0_UARTCTL, u32Parity | u32DataWidth | SC_UARTCTL_UARTEN_Msk);   // Set character width and parity
    }
    else
    {
        outpw(REG_SC1_CTL, u32StopBits | SC_CTL_SCEN_Msk);  // Set stop bit
        outpw(REG_SC1_UARTCTL, u32Parity | u32DataWidth | SC_UARTCTL_UARTEN_Msk);   // Set character width and parity
    }
    return (u32Clk / (u32Div + 1));
}

/**
  * @brief This function use to set receive timeout count.
  * @param[in] sc Smartcard module number
  * @param[in] u32TOC Rx timeout counter, using baudrate as counter unit. Valid range are 0~0x1FF,
  *                   set this value to 0 will disable timeout 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(UINT sc, UINT u32TOC)
{
    if (sc == 0)
        outpw(REG_SC0_RXTOUT, u32TOC);
    else
        outpw(REG_SC1_RXTOUT, u32TOC);
}


/**
  * @brief Write data to smartcard UART interface.
  * @param[in] sc Smartcard module number
  * @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 to write data into transmit FIFO to send data out.
  * @note This function blocks until all data write into FIFO.
  */
void SCUART_Write(UINT sc, char *pu8TxBuf, UINT u32WriteBytes)
{
    uint32_t u32Count;

    if (sc == 0)
    {
        for (u32Count = 0; u32Count != u32WriteBytes; u32Count++)
        {
            while (inpw(REG_SC0_STATUS) & SC_STATUS_TXFULL_Msk); // Wait 'til FIFO not full
            outpw(REG_SC0_DAT, pu8TxBuf[u32Count]);    // Write 1 byte to FIFO
        }
    }
    else
    {
        for (u32Count = 0; u32Count != u32WriteBytes; u32Count++)
        {
            while (inpw(REG_SC0_STATUS) & SC_STATUS_TXFULL_Msk); // Wait 'til FIFO not full
            outpw(REG_SC1_DAT, pu8TxBuf[u32Count]);    // Write 1 byte to FIFO
        }
    }
}


/*@}*/ /* end of group SCUART_EXPORTED_FUNCTIONS */

/*@}*/ /* end of group SCUART_Driver */

/*@}*/ /* end of group Standard_Driver */