1 /**************************************************************************//**
2  * @file     lpuart.c
3  * @version  V3.00
4  * @brief    LPUART driver source file
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9 
10 #include <stdio.h>
11 #include "NuMicro.h"
12 
13 /** @addtogroup Standard_Driver Standard Driver
14   @{
15 */
16 
17 /** @addtogroup LPUART_Driver LPUART Driver
18   @{
19 */
20 
21 /** @addtogroup LPUART_EXPORTED_FUNCTIONS LPUART Exported Functions
22   @{
23 */
24 
25 /**
26  *    @brief        Clear LPUART specified interrupt flag
27  *
28  *    @param[in]    lpuart                The pointer of the specified LPUART module.
29  *    @param[in]    u32InterruptFlag    The specified interrupt of LPUART module.
30  *                                      - \ref LPUART_INTSTS_WKIF_Msk      : Wake-up interrupt
31  *                                      - \ref LPUART_INTSTS_BUFERRINT_Msk : Buffer Error interrupt
32  *                                      - \ref LPUART_INTSTS_MODEMINT_Msk  : Modem Status interrupt
33  *                                      - \ref LPUART_INTSTS_RLSINT_Msk    : Receive Line Status interrupt
34  *
35  *    @return       None
36  *
37  *    @details      The function is used to clear LPUART specified interrupt flag.
38  */
39 
LPUART_ClearIntFlag(LPUART_T * lpuart,uint32_t u32InterruptFlag)40 void LPUART_ClearIntFlag(LPUART_T* lpuart, uint32_t u32InterruptFlag)
41 {
42 
43     if(u32InterruptFlag & LPUART_INTSTS_RLSINT_Msk)   /* Clear Receive Line Status Interrupt */
44     {
45         lpuart->FIFOSTS = LPUART_FIFOSTS_BIF_Msk | LPUART_FIFOSTS_FEF_Msk | LPUART_FIFOSTS_PEF_Msk;
46         lpuart->FIFOSTS = LPUART_FIFOSTS_ADDRDETF_Msk;
47     }
48 
49     if(u32InterruptFlag & LPUART_INTSTS_MODEMINT_Msk)   /* Clear Modem Status Interrupt */
50     {
51         lpuart->MODEMSTS |= LPUART_MODEMSTS_CTSDETF_Msk;
52     }
53     else
54     {
55     }
56 
57     if(u32InterruptFlag & LPUART_INTSTS_BUFERRINT_Msk)   /* Clear Buffer Error Interrupt */
58     {
59         lpuart->FIFOSTS = LPUART_FIFOSTS_RXOVIF_Msk | LPUART_FIFOSTS_TXOVIF_Msk;
60     }
61 
62     if(u32InterruptFlag & LPUART_INTSTS_WKINT_Msk)   /* Clear Wake-up Interrupt */
63     {
64         lpuart->WKSTS = LPUART_WKSTS_CTSWKF_Msk  | LPUART_WKSTS_DATWKF_Msk  |
65                         LPUART_WKSTS_RFRTWKF_Msk |LPUART_WKSTS_RS485WKF_Msk |
66                         LPUART_WKSTS_TOUTWKF_Msk;
67     }
68 
69 }
70 
71 
72 /**
73  *  @brief      Disable LPUART interrupt
74  *
75  *  @param[in]  lpuart The pointer of the specified LPUART module.
76  *
77  *  @return     None
78  *
79  *  @details    The function is used to disable LPUART interrupt.
80  */
LPUART_Close(LPUART_T * lpuart)81 void LPUART_Close(LPUART_T* lpuart)
82 {
83     lpuart->INTEN = 0ul;
84 }
85 
86 
87 /**
88  *  @brief      Disable LPUART auto flow control function
89  *
90  *  @param[in]  lpuart The pointer of the specified LPUART module.
91  *
92  *  @return     None
93  *
94  *  @details    The function is used to disable LPUART auto flow control.
95  */
LPUART_DisableFlowCtrl(LPUART_T * lpuart)96 void LPUART_DisableFlowCtrl(LPUART_T* lpuart)
97 {
98     lpuart->INTEN &= ~(LPUART_INTEN_ATORTSEN_Msk | LPUART_INTEN_ATOCTSEN_Msk);
99 }
100 
101 
102 /**
103  *    @brief        Disable LPUART specified interrupt
104  *
105  *    @param[in]    lpuart                The pointer of the specified LPUART module.
106  *    @param[in]    u32InterruptFlag    The specified interrupt of LPUART module.
107  *                                      - \ref LPUART_INTEN_WKIEN_Msk      : Wake-up interrupt
108  *                                      - \ref LPUART_INTEN_BUFERRIEN_Msk  : Buffer Error interrupt
109  *                                      - \ref LPUART_INTEN_RXTOIEN_Msk    : Rx time-out interrupt
110  *                                      - \ref LPUART_INTEN_MODEMIEN_Msk   : Modem status interrupt
111  *                                      - \ref LPUART_INTEN_RLSIEN_Msk     : Receive Line status interrupt
112  *                                      - \ref LPUART_INTEN_THREIEN_Msk    : Tx empty interrupt
113  *                                      - \ref LPUART_INTEN_RDAIEN_Msk     : Rx ready interrupt *
114  *
115  *    @return       None
116  *
117  *    @details      The function is used to disable LPUART specified interrupt and disable NVIC LPUART IRQ.
118  */
LPUART_DisableInt(LPUART_T * lpuart,uint32_t u32InterruptFlag)119 void LPUART_DisableInt(LPUART_T*  lpuart, uint32_t u32InterruptFlag)
120 {
121     /* Disable LPUART specified interrupt */
122     LPUART_DISABLE_INT(lpuart, u32InterruptFlag);
123 }
124 
125 
126 /**
127  *    @brief        Enable LPUART auto flow control function
128  *
129  *    @param[in]    lpuart    The pointer of the specified LPUART module.
130  *
131  *    @return       None
132  *
133  *    @details      The function is used to Enable LPUART auto flow control.
134  */
LPUART_EnableFlowCtrl(LPUART_T * lpuart)135 void LPUART_EnableFlowCtrl(LPUART_T* lpuart)
136 {
137     /* Set RTS pin output is low level active */
138     lpuart->MODEM |= LPUART_MODEM_RTSACTLV_Msk;
139 
140     /* Set CTS pin input is low level active */
141     lpuart->MODEMSTS |= LPUART_MODEMSTS_CTSACTLV_Msk;
142 
143     /* Set RTS and CTS auto flow control enable */
144     lpuart->INTEN |= LPUART_INTEN_ATORTSEN_Msk | LPUART_INTEN_ATOCTSEN_Msk;
145 }
146 
147 
148 /**
149  *    @brief        The function is used to enable LPUART specified interrupt and enable NVIC LPUART IRQ.
150  *
151  *    @param[in]    lpuart                The pointer of the specified LPUART module.
152  *    @param[in]    u32InterruptFlag    The specified interrupt of LPUART module:
153  *                                      - \ref LPUART_INTEN_WKIEN_Msk      : Wake-up interrupt
154  *                                      - \ref LPUART_INTEN_BUFERRIEN_Msk  : Buffer Error interrupt
155  *                                      - \ref LPUART_INTEN_RXTOIEN_Msk    : Rx time-out interrupt
156  *                                      - \ref LPUART_INTEN_MODEMIEN_Msk   : Modem status interrupt
157  *                                      - \ref LPUART_INTEN_RLSIEN_Msk     : Receive Line status interrupt
158  *                                      - \ref LPUART_INTEN_THREIEN_Msk    : Tx empty interrupt
159  *                                      - \ref LPUART_INTEN_RDAIEN_Msk     : Rx ready interrupt *
160  *
161  *    @return       None
162  *
163  *    @details      The function is used to enable LPUART specified interrupt and enable NVIC LPUART IRQ.
164  */
LPUART_EnableInt(LPUART_T * lpuart,uint32_t u32InterruptFlag)165 void LPUART_EnableInt(LPUART_T*  lpuart, uint32_t u32InterruptFlag)
166 {
167     /* Enable LPUART specified interrupt */
168     LPUART_ENABLE_INT(lpuart, u32InterruptFlag);
169 }
170 
171 
172 /**
173  *    @brief        Open and set LPUART function
174  *
175  *    @param[in]    lpuart            The pointer of the specified LPUART module.
176  *    @param[in]    u32baudrate     The baudrate of LPUART module.
177  *
178  *    @return       None
179  *
180  *    @details      This function use to enable LPUART function and set baud-rate.
181  */
LPUART_Open(LPUART_T * lpuart,uint32_t u32baudrate)182 void LPUART_Open(LPUART_T* lpuart, uint32_t u32baudrate)
183 {
184     uint32_t u32UartClkSrcSel=0ul, u32UartClkDivNum=0ul;
185     uint32_t u32ClkTbl[4] = {__HIRC, __MIRC, __LXT};
186     uint32_t u32Baud_Div = 0ul;
187 
188 
189     if(lpuart==(LPUART_T*)LPUART0)
190     {
191         /* Get LPUART clock source selection */
192         u32UartClkSrcSel = ((uint32_t)(LPSCC->CLKSEL0 & LPSCC_CLKSEL0_LPUART0SEL_Msk)) >> LPSCC_CLKSEL0_LPUART0SEL_Pos;
193         /* Get LPUART clock divider number */
194         u32UartClkDivNum = (LPSCC->CLKDIV0 & LPSCC_CLKDIV0_LPUART0DIV_Msk) >> LPSCC_CLKDIV0_LPUART0DIV_Pos;
195     }
196 
197 
198     /* Select LPUART function */
199     lpuart->FUNCSEL = LPUART_FUNCSEL_LPUART;
200 
201     /* Set LPUART line configuration */
202     lpuart->LINE = LPUART_WORD_LEN_8 | LPUART_PARITY_NONE | LPUART_STOP_BIT_1;
203 
204     /* Set LPUART Rx and RTS trigger level */
205     lpuart->FIFO &= ~(LPUART_FIFO_RFITL_Msk | LPUART_FIFO_RTSTRGLV_Msk);
206 
207     /* Set LPUART baud rate */
208     if(u32baudrate != 0ul)
209     {
210         u32Baud_Div = LPUART_BAUD_MODE2_DIVIDER((u32ClkTbl[u32UartClkSrcSel]) / (u32UartClkDivNum + 1ul), u32baudrate);
211 
212         if(u32Baud_Div > 0xFFFFul)
213         {
214             lpuart->BAUD = (LPUART_BAUD_MODE0 | LPUART_BAUD_MODE0_DIVIDER((u32ClkTbl[u32UartClkSrcSel]) / (u32UartClkDivNum + 1ul), u32baudrate));
215         }
216         else
217         {
218             lpuart->BAUD = (LPUART_BAUD_MODE2 | u32Baud_Div);
219         }
220     }
221 }
222 
223 
224 /**
225  *    @brief        Read LPUART data
226  *
227  *    @param[in]    lpuart            The pointer of the specified LPUART module.
228  *    @param[in]    pu8RxBuf        The buffer to receive the data of receive FIFO.
229  *    @param[in]    u32ReadBytes    The the read bytes number of data.
230  *
231  *    @return       u32Count Receive byte count
232  *
233  *    @details      The function is used to read Rx data from RX FIFO and the data will be stored in pu8RxBuf.
234  */
LPUART_Read(LPUART_T * lpuart,uint8_t pu8RxBuf[],uint32_t u32ReadBytes)235 uint32_t LPUART_Read(LPUART_T* lpuart, uint8_t pu8RxBuf[], uint32_t u32ReadBytes)
236 {
237     uint32_t  u32Count, u32delayno;
238     uint32_t  u32Exit = 0ul;
239 
240     for(u32Count = 0ul; u32Count < u32ReadBytes; u32Count++)
241     {
242         u32delayno = 0ul;
243 
244         while(lpuart->FIFOSTS & LPUART_FIFOSTS_RXEMPTY_Msk)   /* Check RX empty => failed */
245         {
246             u32delayno++;
247             if(u32delayno >= 0x40000000ul)
248             {
249                 u32Exit = 1ul;
250                 break;
251             }
252             else
253             {
254             }
255         }
256 
257         if(u32Exit == 1ul)
258         {
259             break;
260         }
261         else
262         {
263             pu8RxBuf[u32Count] = (uint8_t)lpuart->DAT; /* Get Data from LPUART RX  */
264         }
265     }
266 
267     return u32Count;
268 
269 }
270 
271 
272 /**
273  *    @brief        Set LPUART line configuration
274  *
275  *    @param[in]    lpuart            The pointer of the specified LPUART module.
276  *    @param[in]    u32baudrate     The register value of baudrate of LPUART module.
277  *                                  If u32baudrate = 0, LPUART baudrate will not change.
278  *    @param[in]    u32data_width   The data length of LPUART module.
279  *                                  - \ref LPUART_WORD_LEN_5
280  *                                  - \ref LPUART_WORD_LEN_6
281  *                                  - \ref LPUART_WORD_LEN_7
282  *                                  - \ref LPUART_WORD_LEN_8
283  *    @param[in]    u32parity       The parity setting (none/odd/even/mark/space) of LPUART module.
284  *                                  - \ref LPUART_PARITY_NONE
285  *                                  - \ref LPUART_PARITY_ODD
286  *                                  - \ref LPUART_PARITY_EVEN
287  *                                  - \ref LPUART_PARITY_MARK
288  *                                  - \ref LPUART_PARITY_SPACE
289  *    @param[in]    u32stop_bits    The stop bit length (1/1.5/2 bit) of LPUART module.
290  *                                  - \ref LPUART_STOP_BIT_1
291  *                                  - \ref LPUART_STOP_BIT_1_5
292  *                                  - \ref LPUART_STOP_BIT_2
293  *
294  *    @return       None
295  *
296  *    @details      This function use to config LPUART line setting.
297  */
LPUART_SetLine_Config(LPUART_T * lpuart,uint32_t u32baudrate,uint32_t u32data_width,uint32_t u32parity,uint32_t u32stop_bits)298 void LPUART_SetLine_Config(LPUART_T* lpuart, uint32_t u32baudrate, uint32_t u32data_width, uint32_t u32parity, uint32_t  u32stop_bits)
299 {
300     uint32_t u32UartClkSrcSel=0ul, u32UartClkDivNum=0ul;
301     uint32_t u32ClkTbl[4] = {__HIRC, __MIRC, __LXT};
302     uint32_t u32Baud_Div = 0ul;
303 
304 
305     if(lpuart==(LPUART_T*)LPUART0)
306     {
307         /* Get LPUART clock source selection */
308         u32UartClkSrcSel = (LPSCC->CLKSEL0 & LPSCC_CLKSEL0_LPUART0SEL_Msk) >> LPSCC_CLKSEL0_LPUART0SEL_Pos;
309         /* Get LPUART clock divider number */
310         u32UartClkDivNum = (LPSCC->CLKDIV0 & LPSCC_CLKDIV0_LPUART0DIV_Msk) >> LPSCC_CLKDIV0_LPUART0DIV_Pos;
311     }
312 
313 
314     /* Set LPUART baud rate */
315     if(u32baudrate != 0ul)
316     {
317         u32Baud_Div = LPUART_BAUD_MODE2_DIVIDER((u32ClkTbl[u32UartClkSrcSel]) / (u32UartClkDivNum + 1ul), u32baudrate);
318 
319         if(u32Baud_Div > 0xFFFFul)
320         {
321             lpuart->BAUD = (LPUART_BAUD_MODE0 | LPUART_BAUD_MODE0_DIVIDER((u32ClkTbl[u32UartClkSrcSel]) / (u32UartClkDivNum + 1ul), u32baudrate));
322         }
323         else
324         {
325             lpuart->BAUD = (LPUART_BAUD_MODE2 | u32Baud_Div);
326         }
327     }
328 
329     /* Set LPUART line configuration */
330     lpuart->LINE = u32data_width | u32parity | u32stop_bits;
331 }
332 
333 
334 /**
335  *    @brief        Set Rx timeout count
336  *
337  *    @param[in]    lpuart    The pointer of the specified LPUART module.
338  *    @param[in]    u32TOC  Rx timeout counter.
339  *
340  *    @return       None
341  *
342  *    @details      This function use to set Rx timeout count.
343  */
LPUART_SetTimeoutCnt(LPUART_T * lpuart,uint32_t u32TOC)344 void LPUART_SetTimeoutCnt(LPUART_T* lpuart, uint32_t u32TOC)
345 {
346     /* Set time-out interrupt comparator */
347     lpuart->TOUT = (lpuart->TOUT & ~LPUART_TOUT_TOIC_Msk) | (u32TOC);
348 
349     /* Set time-out counter enable */
350     lpuart->INTEN |= LPUART_INTEN_TOCNTEN_Msk;
351 }
352 
353 
354 /**
355  *    @brief        Select and configure RS485 function
356  *
357  *    @param[in]    lpuart        The pointer of the specified LPUART module.
358  *    @param[in]    u32Mode     The operation mode(NMM/AUD/AAD).
359  *                              - \ref LPUART_ALTCTL_RS485NMM_Msk
360  *                              - \ref LPUART_ALTCTL_RS485AUD_Msk
361  *                              - \ref LPUART_ALTCTL_RS485AAD_Msk
362  *    @param[in]    u32Addr     The RS485 address.
363  *
364  *    @return       None
365  *
366  *    @details      The function is used to set RS485 relative setting.
367  */
LPUART_SelectRS485Mode(LPUART_T * lpuart,uint32_t u32Mode,uint32_t u32Addr)368 void LPUART_SelectRS485Mode(LPUART_T* lpuart, uint32_t u32Mode, uint32_t u32Addr)
369 {
370     /* Select LPUART RS485 function mode */
371     lpuart->FUNCSEL = LPUART_FUNCSEL_RS485;
372 
373     /* Set RS485 configuration */
374     lpuart->ALTCTL &= ~(LPUART_ALTCTL_RS485NMM_Msk | LPUART_ALTCTL_RS485AUD_Msk | LPUART_ALTCTL_RS485AAD_Msk | LPUART_ALTCTL_ADDRMV_Msk);
375     lpuart->ALTCTL |= (u32Mode | (u32Addr << LPUART_ALTCTL_ADDRMV_Pos));
376 }
377 
378 /**
379  *    @brief        Write LPUART data
380  *
381  *    @param[in]    lpuart            The pointer of the specified LPUART module.
382  *    @param[in]    pu8TxBuf        The buffer to send the data to LPUART transmission FIFO.
383  *    @param[out]   u32WriteBytes   The byte number of data.
384  *
385  *    @return       u32Count transfer byte count
386  *
387  *    @details      The function is to write data into TX buffer to transmit data by LPUART.
388  */
LPUART_Write(LPUART_T * lpuart,uint8_t pu8TxBuf[],uint32_t u32WriteBytes)389 uint32_t LPUART_Write(LPUART_T* lpuart, uint8_t pu8TxBuf[], uint32_t u32WriteBytes)
390 {
391     uint32_t  u32Count, u32delayno;
392     uint32_t  u32Exit = 0ul;
393 
394     for(u32Count = 0ul; u32Count != u32WriteBytes; u32Count++)
395     {
396         u32delayno = 0ul;
397         while(lpuart->FIFOSTS & LPUART_FIFOSTS_TXFULL_Msk)   /* Check Tx Full */
398         {
399             u32delayno++;
400             if(u32delayno >= 0x40000000ul)
401             {
402                 u32Exit = 1ul;
403                 break;
404             }
405             else
406             {
407             }
408         }
409 
410         if(u32Exit == 1ul)
411         {
412             break;
413         }
414         else
415         {
416             lpuart->DAT = pu8TxBuf[u32Count];    /* Send LPUART Data from buffer */
417         }
418     }
419 
420     return u32Count;
421 }
422 /**
423  *    @brief        Select Single Wire mode function
424  *
425  *    @param[in]    lpuart        The pointer of the specified LPUART module.
426  *
427  *    @return       None
428  *
429  *    @details      The function is used to select Single Wire mode.
430  */
LPUART_SelectSingleWireMode(LPUART_T * lpuart)431 void LPUART_SelectSingleWireMode(LPUART_T *lpuart)
432 {
433 
434     /* Select LPUART SingleWire function mode */
435     lpuart->FUNCSEL = ((lpuart->FUNCSEL & (~LPUART_FUNCSEL_FUNCSEL_Msk)) | LPUART_FUNCSEL_SINGLE_WIRE);
436 
437 }
438 /*@}*/ /* end of group LPUART_EXPORTED_FUNCTIONS */
439 
440 /*@}*/ /* end of group LPUART_Driver */
441 
442 /*@}*/ /* end of group Standard_Driver */
443 
444 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
445 
446 
447 
448