nu_uart.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /**************************************************************************//**
  2. * @file uart.c
  3. * @brief UART driver source file
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  7. *****************************************************************************/
  8. #include <stdio.h>
  9. #include "NuMicro.h"
  10. /** @addtogroup Standard_Driver Standard Driver
  11. @{
  12. */
  13. /** @addtogroup UART_Driver UART Driver
  14. @{
  15. */
  16. /** @addtogroup UART_EXPORTED_FUNCTIONS UART Exported Functions
  17. @{
  18. */
  19. static void UART_GetSrcClkSetting(UART_T *uart, uint32_t *pu32ClkSrcFreq, uint32_t *pu32ClkDivNum);
  20. /**
  21. * @brief This function make UART module be ready to transfer.
  22. * @param[in] pu32ClkSrcFreq will return UART source clock frequency(In HZ).
  23. * @param[in] pu32ClkSrcFreq will return UART source clock frequency(In HZ).
  24. * @param[in] pu32ClkDivNum will return UART source clock divider.
  25. * @return None.
  26. * @details
  27. * 0: HXT
  28. * 1: SYSCLK1
  29. * 2: LXT
  30. * 3: HIRC
  31. * @note If u32BusClock = 0, DIVIDER setting will be set to the maximum value.
  32. */
  33. static void UART_GetSrcClkSetting(UART_T *uart, uint32_t *pu32ClkSrcFreq, uint32_t *pu32ClkDivNum)
  34. {
  35. uint32_t u32UartClkSrcSel = 0u, u32UartClkDivNum = 0u;
  36. uint32_t u32SrcClkFreq = 0u;
  37. uint32_t u32UartPort;
  38. if (uart == (UART_T *)UART16)
  39. {
  40. u32UartPort = 16;
  41. }
  42. else
  43. {
  44. u32UartPort = ((uint32_t)uart & 0xf0000) >> 16;
  45. }
  46. if (u32UartPort < 8)
  47. {
  48. u32UartClkSrcSel = ((CLK->CLKSEL2 >> (16 + u32UartPort * 2)) & 0x3ul);
  49. if (u32UartPort < 4)
  50. {
  51. u32UartClkDivNum = ((CLK->CLKDIV1 >> ((u32UartPort + 4) * 4)) & 0xful);
  52. }
  53. else
  54. {
  55. u32UartClkDivNum = ((CLK->CLKDIV2 >> ((u32UartPort - 4) * 4)) & 0xful);
  56. }
  57. }
  58. else if (u32UartPort <= 16)
  59. {
  60. u32UartClkSrcSel = ((CLK->CLKSEL3 >> ((u32UartPort - 8) * 2)) & 0x3ul);
  61. if (u32UartPort < 12)
  62. {
  63. u32UartClkDivNum = ((CLK->CLKDIV2 >> ((u32UartPort - 4) * 4)) & 0xful);
  64. }
  65. else
  66. {
  67. u32UartClkDivNum = ((CLK->CLKDIV3 >> ((u32UartPort - 12) * 4)) & 0xful);
  68. }
  69. }
  70. /* Get PLL clock frequency if UART clock source selection is PLL */
  71. switch (u32UartClkSrcSel)
  72. {
  73. case 0u:
  74. u32SrcClkFreq = __HXT;
  75. break;
  76. case 1u:
  77. u32SrcClkFreq = CLK_GetSYSCLK1Freq(); //TODO
  78. break;
  79. default:
  80. u32SrcClkFreq = 0;
  81. break;
  82. }
  83. if (pu32ClkSrcFreq)
  84. *pu32ClkSrcFreq = u32SrcClkFreq;
  85. if (pu32ClkDivNum)
  86. *pu32ClkDivNum = u32UartClkDivNum;
  87. }
  88. /**
  89. * @brief Clear UART specified interrupt flag
  90. *
  91. * @param[in] uart The pointer of the specified UART module.
  92. * @param[in] u32InterruptFlag The specified interrupt of UART module.
  93. * - \ref UART_INTSTS_WKIF_Msk : Wake-up interrupt
  94. * - \ref UART_INTSTS_BUFEINT_Msk : Buffer Error interrupt
  95. * - \ref UART_INTSTS_MODEMINT_Msk : Modem Status interrupt
  96. * - \ref UART_INTSTS_RLSINT_Msk : Receive Line Status interrupt
  97. *
  98. * @return None
  99. *
  100. * @details The function is used to clear UART specified interrupt flag.
  101. */
  102. void UART_ClearIntFlag(UART_T *uart, uint32_t u32InterruptFlag)
  103. {
  104. if (u32InterruptFlag & UART_INTSTS_RLSINT_Msk) /* Clear Receive Line Status Interrupt */
  105. {
  106. uart->FIFOSTS = UART_FIFOSTS_BIF_Msk | UART_FIFOSTS_FEF_Msk | UART_FIFOSTS_PEF_Msk;
  107. uart->FIFOSTS = UART_FIFOSTS_ADDRDETF_Msk;
  108. }
  109. if (u32InterruptFlag & UART_INTSTS_MODEMINT_Msk) /* Clear Modem Status Interrupt */
  110. {
  111. uart->MODEMSTS |= UART_MODEMSTS_CTSDETF_Msk;
  112. }
  113. else
  114. {
  115. }
  116. if (u32InterruptFlag & UART_INTSTS_BUFEINT_Msk) /* Clear Buffer Error Interrupt */
  117. {
  118. uart->FIFOSTS = UART_FIFOSTS_RXOVIF_Msk | UART_FIFOSTS_TXOVIF_Msk;
  119. }
  120. if (u32InterruptFlag & UART_INTSTS_WKINT_Msk) /* Clear Wake-up Interrupt */
  121. {
  122. uart->WKSTS = UART_WKSTS_CTSWKF_Msk | UART_WKSTS_DATWKF_Msk |
  123. UART_WKSTS_RFRTWKF_Msk | UART_WKSTS_RS485WKF_Msk |
  124. UART_WKSTS_TOUTWKF_Msk;
  125. }
  126. }
  127. /**
  128. * @brief Disable UART interrupt
  129. *
  130. * @param[in] uart The pointer of the specified UART module.
  131. *
  132. * @return None
  133. *
  134. * @details The function is used to disable UART interrupt.
  135. */
  136. void UART_Close(UART_T *uart)
  137. {
  138. uart->INTEN = 0ul;
  139. }
  140. /**
  141. * @brief Disable UART auto flow control function
  142. *
  143. * @param[in] uart The pointer of the specified UART module.
  144. *
  145. * @return None
  146. *
  147. * @details The function is used to disable UART auto flow control.
  148. */
  149. void UART_DisableFlowCtrl(UART_T *uart)
  150. {
  151. uart->INTEN &= ~(UART_INTEN_ATORTSEN_Msk | UART_INTEN_ATOCTSEN_Msk);
  152. }
  153. /**
  154. * @brief Disable UART specified interrupt
  155. *
  156. * @param[in] uart The pointer of the specified UART module.
  157. * @param[in] u32InterruptFlag The specified interrupt of UART module.
  158. * - \ref UART_INTEN_WKIEN_Msk : Wake-up interrupt
  159. * - \ref UART_INTEN_BUFEIEN_Msk : Buffer Error interrupt
  160. * - \ref UART_INTEN_RXTOIEN_Msk : Rx time-out interrupt
  161. * - \ref UART_INTEN_MODEMIEN_Msk : Modem status interrupt
  162. * - \ref UART_INTEN_RLSIEN_Msk : Receive Line status interrupt
  163. * - \ref UART_INTEN_THREIEN_Msk : Tx empty interrupt
  164. * - \ref UART_INTEN_RDAIEN_Msk : Rx ready interrupt *
  165. *
  166. * @return None
  167. *
  168. * @details The function is used to disable UART specified interrupt and disable NVIC UART IRQ.
  169. */
  170. void UART_DisableInt(UART_T *uart, uint32_t u32InterruptFlag)
  171. {
  172. /* Disable UART specified interrupt */
  173. UART_DISABLE_INT(uart, u32InterruptFlag);
  174. }
  175. /**
  176. * @brief Enable UART auto flow control function
  177. *
  178. * @param[in] uart The pointer of the specified UART module.
  179. *
  180. * @return None
  181. *
  182. * @details The function is used to Enable UART auto flow control.
  183. */
  184. void UART_EnableFlowCtrl(UART_T *uart)
  185. {
  186. /* Set RTS pin output is low level active */
  187. uart->MODEM |= UART_MODEM_RTSACTLV_Msk;
  188. /* Set CTS pin input is low level active */
  189. uart->MODEMSTS |= UART_MODEMSTS_CTSACTLV_Msk;
  190. /* Set RTS and CTS auto flow control enable */
  191. uart->INTEN |= UART_INTEN_ATORTSEN_Msk | UART_INTEN_ATOCTSEN_Msk;
  192. }
  193. /**
  194. * @brief The function is used to enable UART specified interrupt and enable NVIC UART IRQ.
  195. *
  196. * @param[in] uart The pointer of the specified UART module.
  197. * @param[in] u32InterruptFlag The specified interrupt of UART module:
  198. * - \ref UART_INTEN_WKIEN_Msk : Wake-up interrupt
  199. * - \ref UART_INTEN_BUFEIEN_Msk : Buffer Error interrupt
  200. * - \ref UART_INTEN_RXTOIEN_Msk : Rx time-out interrupt
  201. * - \ref UART_INTEN_MODEMIEN_Msk : Modem status interrupt
  202. * - \ref UART_INTEN_RLSIEN_Msk : Receive Line status interrupt
  203. * - \ref UART_INTEN_THREIEN_Msk : Tx empty interrupt
  204. * - \ref UART_INTEN_RDAIEN_Msk : Rx ready interrupt *
  205. *
  206. * @return None
  207. *
  208. * @details The function is used to enable UART specified interrupt and enable NVIC UART IRQ.
  209. */
  210. void UART_EnableInt(UART_T *uart, uint32_t u32InterruptFlag)
  211. {
  212. /* Enable UART specified interrupt */
  213. UART_ENABLE_INT(uart, u32InterruptFlag);
  214. }
  215. /**
  216. * @brief Open and set UART function
  217. *
  218. * @param[in] uart The pointer of the specified UART module.
  219. * @param[in] u32baudrate The baudrate of UART module.
  220. *
  221. * @return None
  222. *
  223. * @details This function use to enable UART function and set baud-rate.
  224. */
  225. void UART_Open(UART_T *uart, uint32_t u32baudrate)
  226. {
  227. uint32_t u32UartSrcClkFreq = 0ul, u32UartClkDivNum = 0ul;
  228. uint32_t u32Baud_Div = 0ul;
  229. /* Select UART function */
  230. uart->FUNCSEL = UART_FUNCSEL_UART;
  231. /* Set UART line configuration */
  232. uart->LINE = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1;
  233. /* Set UART Rx and RTS trigger level */
  234. uart->FIFO &= ~(UART_FIFO_RFITL_Msk | UART_FIFO_RTSTRGLV_Msk);
  235. /* Get Source clock frequency and its divider of curret setting */
  236. UART_GetSrcClkSetting(uart, &u32UartSrcClkFreq, &u32UartClkDivNum);
  237. /* Set UART baud rate */
  238. if (u32baudrate != 0ul)
  239. {
  240. u32Baud_Div = UART_BAUD_MODE2_DIVIDER(u32UartSrcClkFreq / (u32UartClkDivNum + 1ul), u32baudrate);
  241. if (u32Baud_Div > 0xFFFFul)
  242. {
  243. uart->BAUD = (UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER(u32UartSrcClkFreq / (u32UartClkDivNum + 1ul), u32baudrate));
  244. }
  245. else
  246. {
  247. uart->BAUD = (UART_BAUD_MODE2 | u32Baud_Div);
  248. }
  249. }
  250. }
  251. /**
  252. * @brief Read UART data
  253. *
  254. * @param[in] uart The pointer of the specified UART module.
  255. * @param[in] pu8RxBuf The buffer to receive the data of receive FIFO.
  256. * @param[in] u32ReadBytes The the read bytes number of data.
  257. *
  258. * @return u32Count Receive byte count
  259. *
  260. * @details The function is used to read Rx data from RX FIFO and the data will be stored in pu8RxBuf.
  261. */
  262. uint32_t UART_Read(UART_T *uart, uint8_t pu8RxBuf[], uint32_t u32ReadBytes)
  263. {
  264. uint32_t u32Count, u32delayno;
  265. uint32_t u32Exit = 0ul;
  266. for (u32Count = 0ul; u32Count < u32ReadBytes; u32Count++)
  267. {
  268. u32delayno = 0ul;
  269. while (uart->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) /* Check RX empty => failed */
  270. {
  271. u32delayno++;
  272. if (u32delayno >= 0x40000000ul)
  273. {
  274. u32Exit = 1ul;
  275. break;
  276. }
  277. else
  278. {
  279. }
  280. }
  281. if (u32Exit == 1ul)
  282. {
  283. break;
  284. }
  285. else
  286. {
  287. pu8RxBuf[u32Count] = (uint8_t)uart->DAT; /* Get Data from UART RX */
  288. }
  289. }
  290. return u32Count;
  291. }
  292. /**
  293. * @brief Set UART line configuration
  294. *
  295. * @param[in] uart The pointer of the specified UART module.
  296. * @param[in] u32baudrate The register value of baudrate of UART module.
  297. * If u32baudrate = 0, UART baudrate will not change.
  298. * @param[in] u32data_width The data length of UART module.
  299. * - \ref UART_WORD_LEN_5
  300. * - \ref UART_WORD_LEN_6
  301. * - \ref UART_WORD_LEN_7
  302. * - \ref UART_WORD_LEN_8
  303. * @param[in] u32parity The parity setting (none/odd/even/mark/space) of UART module.
  304. * - \ref UART_PARITY_NONE
  305. * - \ref UART_PARITY_ODD
  306. * - \ref UART_PARITY_EVEN
  307. * - \ref UART_PARITY_MARK
  308. * - \ref UART_PARITY_SPACE
  309. * @param[in] u32stop_bits The stop bit length (1/1.5/2 bit) of UART module.
  310. * - \ref UART_STOP_BIT_1
  311. * - \ref UART_STOP_BIT_1_5
  312. * - \ref UART_STOP_BIT_2
  313. *
  314. * @return None
  315. *
  316. * @details This function use to config UART line setting.
  317. */
  318. void UART_SetLineConfig(UART_T *uart, uint32_t u32baudrate, uint32_t u32data_width, uint32_t u32parity, uint32_t u32stop_bits)
  319. {
  320. uint32_t u32UartSrcClkFreq = 0ul, u32UartClkDivNum = 0ul;
  321. uint32_t u32Baud_Div = 0ul;
  322. /* Get Source clock frequency and its divider of curret setting */
  323. UART_GetSrcClkSetting(uart, &u32UartSrcClkFreq, &u32UartClkDivNum);
  324. /* Set UART baud rate */
  325. if (u32baudrate != 0ul)
  326. {
  327. u32Baud_Div = UART_BAUD_MODE2_DIVIDER(u32UartSrcClkFreq / (u32UartClkDivNum + 1ul), u32baudrate);
  328. if (u32Baud_Div > 0xFFFFul)
  329. {
  330. uart->BAUD = (UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER(u32UartSrcClkFreq / (u32UartClkDivNum + 1ul), u32baudrate));
  331. }
  332. else
  333. {
  334. uart->BAUD = (UART_BAUD_MODE2 | u32Baud_Div);
  335. }
  336. }
  337. /* Set UART line configuration */
  338. uart->LINE = u32data_width | u32parity | u32stop_bits;
  339. }
  340. /**
  341. * @brief Set Rx timeout count
  342. *
  343. * @param[in] uart The pointer of the specified UART module.
  344. * @param[in] u32TOC Rx timeout counter.
  345. *
  346. * @return None
  347. *
  348. * @details This function use to set Rx timeout count.
  349. */
  350. void UART_SetTimeoutCnt(UART_T *uart, uint32_t u32TOC)
  351. {
  352. /* Set time-out interrupt comparator */
  353. uart->TOUT = (uart->TOUT & ~UART_TOUT_TOIC_Msk) | (u32TOC);
  354. /* Set time-out counter enable */
  355. uart->INTEN |= UART_INTEN_TOCNTEN_Msk;
  356. }
  357. /**
  358. * @brief Select and configure IrDA function
  359. *
  360. * @param[in] uart The pointer of the specified UART module.
  361. * @param[in] u32Buadrate The baudrate of UART module.
  362. * @param[in] u32Direction The direction of UART module in IrDA mode:
  363. * - \ref UART_IRDA_TXEN
  364. * - \ref UART_IRDA_RXEN
  365. *
  366. * @return None
  367. *
  368. * @details The function is used to configure IrDA relative settings. It consists of TX or RX mode and baudrate.
  369. */
  370. void UART_SelectIrDAMode(UART_T *uart, uint32_t u32Buadrate, uint32_t u32Direction)
  371. {
  372. uint32_t u32UartSrcClkFreq = 0ul, u32UartClkDivNum = 0ul;
  373. uint32_t u32Baud_Div;
  374. /* Select IrDA function mode */
  375. uart->FUNCSEL = UART_FUNCSEL_IrDA;
  376. /* Get Source clock frequency and its divider of curret setting */
  377. UART_GetSrcClkSetting(uart, &u32UartSrcClkFreq, &u32UartClkDivNum);
  378. /* Set UART IrDA baud rate in mode 0 */
  379. if (u32Buadrate != 0ul)
  380. {
  381. u32Baud_Div = UART_BAUD_MODE0_DIVIDER(u32UartSrcClkFreq / (u32UartClkDivNum + 1ul), u32Buadrate);
  382. if (u32Baud_Div < 0xFFFFul)
  383. {
  384. uart->BAUD = (UART_BAUD_MODE0 | u32Baud_Div);
  385. }
  386. else
  387. {
  388. }
  389. }
  390. /* Configure IrDA relative settings */
  391. if (u32Direction == UART_IRDA_RXEN)
  392. {
  393. uart->IRDA |= UART_IRDA_RXINV_Msk; /*Rx signal is inverse*/
  394. uart->IRDA &= ~UART_IRDA_TXEN_Msk;
  395. }
  396. else
  397. {
  398. uart->IRDA &= ~UART_IRDA_TXINV_Msk; /*Tx signal is not inverse*/
  399. uart->IRDA |= UART_IRDA_TXEN_Msk;
  400. }
  401. }
  402. /**
  403. * @brief Select and configure RS485 function
  404. *
  405. * @param[in] uart The pointer of the specified UART module.
  406. * @param[in] u32Mode The operation mode(NMM/AUD/AAD).
  407. * - \ref UART_ALTCTL_RS485NMM_Msk
  408. * - \ref UART_ALTCTL_RS485AUD_Msk
  409. * - \ref UART_ALTCTL_RS485AAD_Msk
  410. * @param[in] u32Addr The RS485 address.
  411. *
  412. * @return None
  413. *
  414. * @details The function is used to set RS485 relative setting.
  415. */
  416. void UART_SelectRS485Mode(UART_T *uart, uint32_t u32Mode, uint32_t u32Addr)
  417. {
  418. /* Select UART RS485 function mode */
  419. uart->FUNCSEL = UART_FUNCSEL_RS485;
  420. /* Set RS585 configuration */
  421. uart->ALTCTL &= ~(UART_ALTCTL_RS485NMM_Msk | UART_ALTCTL_RS485AUD_Msk | UART_ALTCTL_RS485AAD_Msk | UART_ALTCTL_ADDRMV_Msk);
  422. uart->ALTCTL |= (u32Mode | (u32Addr << UART_ALTCTL_ADDRMV_Pos));
  423. }
  424. /**
  425. * @brief Write UART data
  426. *
  427. * @param[in] uart The pointer of the specified UART module.
  428. * @param[in] pu8TxBuf The buffer to send the data to UART transmission FIFO.
  429. * @param[out] u32WriteBytes The byte number of data.
  430. *
  431. * @return u32Count transfer byte count
  432. *
  433. * @details The function is to write data into TX buffer to transmit data by UART.
  434. */
  435. uint32_t UART_Write(UART_T *uart, uint8_t pu8TxBuf[], uint32_t u32WriteBytes)
  436. {
  437. uint32_t u32Count, u32delayno;
  438. uint32_t u32Exit = 0ul;
  439. for (u32Count = 0ul; u32Count != u32WriteBytes; u32Count++)
  440. {
  441. u32delayno = 0ul;
  442. while (uart->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) /* Check Tx Full */
  443. {
  444. u32delayno++;
  445. if (u32delayno >= 0x40000000ul)
  446. {
  447. u32Exit = 1ul;
  448. break;
  449. }
  450. else
  451. {
  452. }
  453. }
  454. if (u32Exit == 1ul)
  455. {
  456. break;
  457. }
  458. else
  459. {
  460. uart->DAT = pu8TxBuf[u32Count]; /* Send UART Data from buffer */
  461. }
  462. }
  463. return u32Count;
  464. }
  465. /*@}*/ /* end of group UART_EXPORTED_FUNCTIONS */
  466. /*@}*/ /* end of group UART_Driver */
  467. /*@}*/ /* end of group Standard_Driver */