drv_scuart.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2020-7-31 Egbert First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_SCUART)
  14. #include "NuMicro.h"
  15. #include <rtdevice.h>
  16. #include <rthw.h>
  17. /* Private definition ---------------------------------------------------------------*/
  18. #define LOG_TAG "drv.scuart"
  19. #define DBG_ENABLE
  20. #define DBG_SECTION_NAME "drv.scuart"
  21. #define DBG_LEVEL DBG_ERROR
  22. #define DBG_COLOR
  23. #include <rtdbg.h>
  24. enum
  25. {
  26. SCUART_START = -1,
  27. #if defined(BSP_USING_SCUART0)
  28. SCUART0_IDX,
  29. #endif
  30. #if defined(BSP_USING_SCUART1)
  31. SCUART1_IDX,
  32. #endif
  33. #if defined(BSP_USING_SCUART2)
  34. SCUART2_IDX,
  35. #endif
  36. SCUART_CNT
  37. };
  38. /* Private typedef --------------------------------------------------------------*/
  39. struct nu_scuart
  40. {
  41. rt_serial_t dev;
  42. char *name;
  43. SC_T *scuart_base;
  44. uint32_t scuart_rst;
  45. IRQn_Type scuart_irq_n;
  46. };
  47. typedef struct nu_scuart *nu_scuart_t;
  48. /* Private functions ------------------------------------------------------------*/
  49. static rt_err_t nu_scuart_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
  50. static rt_err_t nu_scuart_control(struct rt_serial_device *serial, int cmd, void *arg);
  51. static int nu_scuart_send(struct rt_serial_device *serial, char c);
  52. static int nu_scuart_receive(struct rt_serial_device *serial);
  53. static void nu_scuart_isr(nu_scuart_t serial);
  54. /* Public functions ------------------------------------------------------------*/
  55. /* Private variables ------------------------------------------------------------*/
  56. static const struct rt_uart_ops nu_scuart_ops =
  57. {
  58. .configure = nu_scuart_configure,
  59. .control = nu_scuart_control,
  60. .putc = nu_scuart_send,
  61. .getc = nu_scuart_receive,
  62. .dma_transmit = RT_NULL /* not support DMA mode */
  63. };
  64. static const struct serial_configure nu_scuart_default_config =
  65. RT_SERIAL_CONFIG_DEFAULT;
  66. static struct nu_scuart nu_scuart_arr [] =
  67. {
  68. #if defined(BSP_USING_SCUART0)
  69. {
  70. .name = "scuart0",
  71. .scuart_base = SC0,
  72. .scuart_rst = SC0_RST,
  73. .scuart_irq_n = SC0_IRQn,
  74. },
  75. #endif
  76. #if defined(BSP_USING_SCUART1)
  77. {
  78. .name = "scuart1",
  79. .scuart_base = SC1,
  80. .scuart_rst = SC1_RST,
  81. .scuart_irq_n = SC1_IRQn,
  82. },
  83. #endif
  84. #if defined(BSP_USING_SCUART2)
  85. {
  86. .name = "scuart2",
  87. .scuart_base = SC2,
  88. .scuart_rst = SC2_RST,
  89. .scuart_irq_n = SC2_IRQn,
  90. },
  91. #endif
  92. {0}
  93. }; /* scuart nu_scuart */
  94. /* Interrupt Handle Function ----------------------------------------------------*/
  95. #if defined(BSP_USING_SCUART0)
  96. /* SCUART0 interrupt entry */
  97. void SC0_IRQHandler(void)
  98. {
  99. /* enter interrupt */
  100. rt_interrupt_enter();
  101. nu_scuart_isr(&nu_scuart_arr[SCUART0_IDX]);
  102. /* leave interrupt */
  103. rt_interrupt_leave();
  104. }
  105. #endif
  106. #if defined(BSP_USING_SCUART1)
  107. /* SCUART1 interrupt entry */
  108. void SC1_IRQHandler(void)
  109. {
  110. /* enter interrupt */
  111. rt_interrupt_enter();
  112. nu_scuart_isr(&nu_scuart_arr[SCUART1_IDX]);
  113. /* leave interrupt */
  114. rt_interrupt_leave();
  115. }
  116. #endif
  117. #if defined(BSP_USING_SCUART2)
  118. /* SCUART2 interrupt entry */
  119. void SC2_IRQHandler(void)
  120. {
  121. /* enter interrupt */
  122. rt_interrupt_enter();
  123. nu_scuart_isr(&nu_scuart_arr[SCUART2_IDX]);
  124. /* leave interrupt */
  125. rt_interrupt_leave();
  126. }
  127. #endif
  128. /**
  129. * All SCUART interrupt service routine
  130. */
  131. static void nu_scuart_isr(nu_scuart_t serial)
  132. {
  133. /* Get base address of scuart register */
  134. SC_T *scuart_base = ((nu_scuart_t)serial)->scuart_base;
  135. /* Get interrupt event */
  136. uint32_t u32IntSts = scuart_base->INTSTS;
  137. /* Handle RX event */
  138. if (u32IntSts & (SC_INTSTS_RDAIF_Msk | SC_INTSTS_RXTOIF_Msk))
  139. {
  140. rt_hw_serial_isr(&serial->dev, RT_SERIAL_EVENT_RX_IND);
  141. // RDA is the only interrupt enabled in this driver, this status bit
  142. // automatically cleared after Rx FIFO empty. So no need to clear interrupt
  143. // status here.
  144. scuart_base->INTSTS = SC_INTSTS_RXTOIF_Msk;
  145. }
  146. }
  147. /**
  148. * Configure scuart port
  149. */
  150. static rt_err_t nu_scuart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
  151. {
  152. rt_err_t ret = RT_EOK;
  153. uint32_t scuart_word_len = 0;
  154. uint32_t scuart_stop_bit = 0;
  155. uint32_t scuart_parity = 0;
  156. /* Get base address of scuart register */
  157. SC_T *scuart_base = ((nu_scuart_t)serial)->scuart_base;
  158. /* Check baudrate */
  159. RT_ASSERT(cfg->baud_rate != 0);
  160. /* Check word len */
  161. switch (cfg->data_bits)
  162. {
  163. case DATA_BITS_5:
  164. scuart_word_len = SCUART_CHAR_LEN_5;
  165. break;
  166. case DATA_BITS_6:
  167. scuart_word_len = SCUART_CHAR_LEN_6;
  168. break;
  169. case DATA_BITS_7:
  170. scuart_word_len = SCUART_CHAR_LEN_7;
  171. break;
  172. case DATA_BITS_8:
  173. scuart_word_len = SCUART_CHAR_LEN_8;
  174. break;
  175. default:
  176. LOG_E("Unsupported data length");
  177. ret = RT_EINVAL;
  178. goto exit_nu_scuart_configure;
  179. }
  180. /* Check stop bit */
  181. switch (cfg->stop_bits)
  182. {
  183. case STOP_BITS_1:
  184. scuart_stop_bit = SCUART_STOP_BIT_1;
  185. break;
  186. case STOP_BITS_2:
  187. scuart_stop_bit = SCUART_STOP_BIT_2;
  188. break;
  189. default:
  190. LOG_E("Unsupported stop bit");
  191. ret = RT_EINVAL;
  192. goto exit_nu_scuart_configure;
  193. }
  194. /* Check parity */
  195. switch (cfg->parity)
  196. {
  197. case PARITY_NONE:
  198. scuart_parity = SCUART_PARITY_NONE;
  199. break;
  200. case PARITY_ODD:
  201. scuart_parity = SCUART_PARITY_ODD;
  202. break;
  203. case PARITY_EVEN:
  204. scuart_parity = SCUART_PARITY_EVEN;
  205. break;
  206. default:
  207. LOG_E("Unsupported parity");
  208. ret = RT_EINVAL;
  209. goto exit_nu_scuart_configure;
  210. }
  211. /* Reset this module */
  212. SYS_ResetModule(((nu_scuart_t)serial)->scuart_rst);
  213. /* Open SCUART and set SCUART Baudrate */
  214. SCUART_Open(scuart_base, cfg->baud_rate);
  215. /* Set line configuration. */
  216. SCUART_SetLineConfig(scuart_base, 0, scuart_word_len, scuart_parity, scuart_stop_bit);
  217. /* Enable NVIC interrupt. */
  218. NVIC_EnableIRQ(((nu_scuart_t)serial)->scuart_irq_n);
  219. exit_nu_scuart_configure:
  220. if (ret != RT_EOK)
  221. SCUART_Close(scuart_base);
  222. return -(ret);
  223. }
  224. /**
  225. * SCUART interrupt control
  226. */
  227. static rt_err_t nu_scuart_control(struct rt_serial_device *serial, int cmd, void *arg)
  228. {
  229. rt_err_t result = RT_EOK;
  230. rt_uint32_t flag;
  231. rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
  232. RT_ASSERT(serial != RT_NULL);
  233. /* Get base address of scuart register */
  234. SC_T *scuart_base = ((nu_scuart_t)serial)->scuart_base;
  235. switch (cmd)
  236. {
  237. case RT_DEVICE_CTRL_CLR_INT:
  238. if (ctrl_arg == RT_DEVICE_FLAG_INT_RX) /* Disable INT-RX */
  239. {
  240. flag = SC_INTEN_RDAIEN_Msk | SC_INTEN_RXTOIEN_Msk;
  241. SCUART_DISABLE_INT(scuart_base, flag);
  242. }
  243. break;
  244. case RT_DEVICE_CTRL_SET_INT:
  245. if (ctrl_arg == RT_DEVICE_FLAG_INT_RX) /* Enable INT-RX */
  246. {
  247. flag = SC_INTEN_RDAIEN_Msk | SC_INTEN_RXTOIEN_Msk;
  248. SCUART_ENABLE_INT(scuart_base, flag);
  249. }
  250. break;
  251. case RT_DEVICE_CTRL_CLOSE:
  252. /* Disable NVIC interrupt. */
  253. NVIC_DisableIRQ(((nu_scuart_t)serial)->scuart_irq_n);
  254. /* Reset this module */
  255. SYS_ResetModule(((nu_scuart_t)serial)->scuart_rst);
  256. /* Close SCUART port */
  257. SCUART_Close(scuart_base);
  258. break;
  259. default:
  260. result = -RT_EINVAL;
  261. break;
  262. }
  263. return result;
  264. }
  265. /**
  266. * SCUART put char
  267. */
  268. static int nu_scuart_send(struct rt_serial_device *serial, char c)
  269. {
  270. RT_ASSERT(serial != RT_NULL);
  271. /* Get base address of scuart register */
  272. SC_T *scuart_base = ((nu_scuart_t)serial)->scuart_base;
  273. /* Waiting if TX-FIFO is full. */
  274. while (SCUART_IS_TX_FULL(scuart_base));
  275. /* Put char into TX-FIFO */
  276. SCUART_WRITE(scuart_base, c);
  277. return 1;
  278. }
  279. /**
  280. * SCUART get char
  281. */
  282. static int nu_scuart_receive(struct rt_serial_device *serial)
  283. {
  284. RT_ASSERT(serial != RT_NULL);
  285. /* Get base address of scuart register */
  286. SC_T *scuart_base = ((nu_scuart_t)serial)->scuart_base;
  287. /* Return failure if RX-FIFO is empty. */
  288. if (SCUART_GET_RX_EMPTY(scuart_base))
  289. {
  290. return -1;
  291. }
  292. /* Get char from RX-FIFO */
  293. return SCUART_READ(scuart_base);
  294. }
  295. /**
  296. * Hardware SCUART Initialization
  297. */
  298. static int rt_hw_scuart_init(void)
  299. {
  300. int i;
  301. rt_uint32_t flag;
  302. rt_err_t ret = RT_EOK;
  303. for (i = (SCUART_START + 1); i < SCUART_CNT; i++)
  304. {
  305. flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX;
  306. nu_scuart_arr[i].dev.ops = &nu_scuart_ops;
  307. nu_scuart_arr[i].dev.config = nu_scuart_default_config;
  308. ret = rt_hw_serial_register(&nu_scuart_arr[i].dev, nu_scuart_arr[i].name, flag, NULL);
  309. RT_ASSERT(ret == RT_EOK);
  310. }
  311. return ret;
  312. }
  313. INIT_DEVICE_EXPORT(rt_hw_scuart_init);
  314. #endif //#if defined(BSP_USING_SCUART)