direct_uart.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-07-15 JasonHu first version
  9. */
  10. #include <rtconfig.h>
  11. #ifdef BSP_USING_DIRECT_UART
  12. #include <rthw.h>
  13. #include <rtdevice.h>
  14. #include "board.h"
  15. /* I/O port base addr */
  16. #define COM1_BASE 0X3F8
  17. #define MAX_BAUD_VALUE 115200
  18. #define DEFAULT_BAUD_VALUE 19200
  19. #define DEFAULT_DIVISOR_VALUE (MAX_BAUD_VALUE / DEFAULT_BAUD_VALUE)
  20. #define UART_SEND_TIMEOUT
  21. enum uart_fifo_control_register_bits
  22. {
  23. FIFO_ENABLE = 1, /* Enable FIFOs */
  24. FIFO_CLEAR_RECEIVE = (1 << 1), /* Clear Receive FIFO */
  25. FIFO_CLEAR_TRANSMIT = (1 << 2), /* Clear Transmit FIFO */
  26. FIFO_DMA_MODE_SELECT = (1 << 3), /* DMA Mode Select */
  27. FIFO_RESERVED = (1 << 4), /* Reserved */
  28. FIFO_ENABLE_64 = (1 << 5), /* Enable 64 Byte FIFO(16750) */
  29. /* Interrupt Trigger Level/Trigger Level */
  30. FIFO_TRIGGER_1 = (0 << 6), /* 1 Byte */
  31. FIFO_TRIGGER_4 = (1 << 6), /* 4 Byte */
  32. FIFO_TRIGGER_8 = (1 << 7), /* 8 Byte */
  33. FIFO_TRIGGER_14 = (1 << 6) | (1 << 7), /* 14 Byte */
  34. };
  35. enum uart_line_control_register_bits
  36. {
  37. /* Word Length */
  38. LINE_WORD_LENGTH_5 = 0, /* 5 Bits */
  39. LINE_WORD_LENGTH_6 = 1, /* 6 Bits */
  40. LINE_WORD_LENGTH_7 = (1 << 1), /* 7 Bits */
  41. LINE_WORD_LENGTH_8 = ((1 << 1) | 1), /* 8 Bits */
  42. LINE_STOP_BIT_1 = (0 << 2), /* One Stop Bit */
  43. LINE_STOP_BIT_2 = (1 << 2), /* 1.5 Stop Bits or 2 Stop Bits */
  44. /* Parity Select */
  45. LINE_PARITY_NO = (0 << 3), /* No Parity */
  46. LINE_PARITY_ODD = (1 << 3), /* Odd Parity */
  47. LINE_PARITY_EVEN = (1 << 3) | (1 << 4), /* Even Parity */
  48. LINE_PARITY_MARK = (1 << 3) | (1 << 5), /* Mark */
  49. LINE_PARITY_SPACE = (1 << 3) | (1 << 4) | (1 << 5), /* Space */
  50. LINE_BREAK_ENABLE = (1 << 6), /* Set Break Enable */
  51. LINE_DLAB = (1 << 7), /* Divisor Latch Access Bit */
  52. };
  53. enum uart_interrupt_enable_register_bits
  54. {
  55. INTR_RECV_DATA_AVALIABLE = 1, /* Enable Received Data Available Interrupt */
  56. INTR_TRANSMIT_HOLDING = (1 << 1), /* Enable Transmitter Holding Register Empty Interrupt */
  57. INTR_STATUS_CHANGED = (1 << 2), /* Enable Receiver Line Status Interrupt */
  58. INTR_MODEM_STATUS = (1 << 3), /* Enable Modem Status Interrupt */
  59. INTR_SLEEP_MODE = (1 << 4), /* Enable Sleep Mode(16750) */
  60. INTR_LOW_POWER_MODE = (1 << 5), /* Enable Low Power Mode(16750) */
  61. INTR_RESERVED1 = (1 << 6), /* Reserved */
  62. INTR_RESERVED2 = (1 << 7), /* Reserved */
  63. };
  64. enum uart_line_status_register_bits {
  65. LINE_STATUS_DATA_READY = 1, /* Data Ready */
  66. LINE_STATUS_OVERRUN_ERROR = (1 << 1), /* Overrun Error */
  67. LINE_STATUS_PARITY_ERROR = (1 << 2), /* Parity Error */
  68. LINE_STATUS_FRAMING_ERROR = (1 << 3), /* Framing Error */
  69. LINE_STATUS_BREAK_INTERRUPT = (1 << 4), /* Break Interrupt */
  70. LINE_STATUS_EMPTY_TRANSMITTER_HOLDING = (1 << 5), /* Empty Transmitter Holding Register */
  71. LINE_STATUS_EMPTY_DATA_HOLDING = (1 << 6), /* Empty Data Holding Registers */
  72. LINE_STATUS_ERROR_RECEIVE_FIFO = (1 << 7), /* Error in Received FIFO */
  73. };
  74. enum uart_intr_indenty_reg_bits {
  75. INTR_STATUS_PENDING_FLAG = 1, /* Interrupt Pending Flag */
  76. /* 产生的什么中断 */
  77. INTR_STATUS_MODEM = (0 << 1), /* Transmitter Holding Register Empty Interrupt */
  78. INTR_STATUS_TRANSMITTER_HOLDING = (1 << 1), /* Received Data Available Interrupt */
  79. INTR_STATUS_RECEIVE_DATA = (1 << 2), /* Received Data Available Interrupt */
  80. INTR_STATUS_RECEIVE_LINE = (1 << 1) | (1 << 2), /* Receiver Line Status Interrupt */
  81. INTR_STATUS_TIME_OUT_PENDING = (1 << 2) | (1 << 3), /* Time-out Interrupt Pending (16550 & later) */
  82. INTR_STATUS_64BYTE_FIFO = (1 << 5), /* 64 Byte FIFO Enabled (16750 only) */
  83. INTR_STATUS_NO_FIFO = (0 << 6), /* No FIFO on chip */
  84. INTR_STATUS_RESERVED_CONDITION = (1 << 6), /* Reserved condition */
  85. INTR_STATUS_FIFO_NOT_FUNC = (1 << 7), /* FIFO enabled, but not functioning */
  86. INTR_STATUS_FIFO = (1 << 6) | (1 << 7), /* FIFO enabled */
  87. };
  88. struct hw_uart
  89. {
  90. rt_uint16_t iobase;
  91. rt_uint16_t data_reg;
  92. rt_uint16_t divisor_low_reg;
  93. rt_uint16_t intr_enable_reg;
  94. rt_uint16_t divisor_high_reg;
  95. rt_uint16_t intr_indenty_reg;
  96. rt_uint16_t fifo_reg;
  97. rt_uint16_t line_ctrl_reg;
  98. rt_uint16_t modem_ctrl_reg;
  99. rt_uint16_t line_status_reg;
  100. rt_uint16_t modem_status_reg;
  101. rt_uint16_t scratch_reg;
  102. };
  103. typedef struct hw_uart hw_uart_t;
  104. static hw_uart_t hw_uart;
  105. static int uart_send(hw_uart_t *uart, char data)
  106. {
  107. #ifdef UART_SEND_TIMEOUT
  108. int timeout = 0x100000;
  109. while (!(inb(uart->line_status_reg) & LINE_STATUS_EMPTY_TRANSMITTER_HOLDING) && timeout--)
  110. {
  111. }
  112. #else
  113. while (!(inb(uart->line_status_reg) & LINE_STATUS_EMPTY_TRANSMITTER_HOLDING))
  114. {
  115. }
  116. #endif
  117. outb(uart->data_reg, data);
  118. return 0;
  119. }
  120. void rt_hw_direct_uart_putchar(char ch)
  121. {
  122. if(ch == '\n') {
  123. uart_send(&hw_uart, '\r');
  124. }
  125. uart_send(&hw_uart, ch);
  126. }
  127. /**
  128. * This function is used by rt_kprintf to display a string on console.
  129. *
  130. * @param str the displayed string
  131. */
  132. void rt_hw_console_output(const char *str)
  133. {
  134. while (*str) {
  135. rt_hw_direct_uart_putchar(*str++);
  136. }
  137. }
  138. void rt_hw_direct_uart_init(void)
  139. {
  140. hw_uart_t *uart = &hw_uart;
  141. rt_uint16_t iobase;
  142. iobase = COM1_BASE;
  143. uart->iobase = iobase;
  144. uart->data_reg = iobase + 0;
  145. uart->divisor_low_reg = iobase + 0;
  146. uart->intr_enable_reg = iobase + 1;
  147. uart->divisor_high_reg = iobase + 1;
  148. uart->intr_indenty_reg = iobase + 2;
  149. uart->line_ctrl_reg = iobase + 3;
  150. uart->modem_ctrl_reg = iobase + 4;
  151. uart->line_status_reg = iobase + 5;
  152. uart->modem_status_reg = iobase + 6;
  153. uart->scratch_reg = iobase + 7;
  154. outb(uart->line_ctrl_reg, LINE_DLAB);
  155. outb(uart->divisor_low_reg, (DEFAULT_DIVISOR_VALUE) & 0xff);
  156. outb(uart->divisor_high_reg, ((DEFAULT_DIVISOR_VALUE) >> 8) & 0xff);
  157. outb(uart->line_ctrl_reg, LINE_WORD_LENGTH_8 |
  158. LINE_STOP_BIT_1 | LINE_PARITY_NO);
  159. /* close all intr */
  160. outb(uart->intr_enable_reg, 0);
  161. outb(uart->fifo_reg, FIFO_ENABLE | FIFO_CLEAR_TRANSMIT |
  162. FIFO_CLEAR_RECEIVE | FIFO_ENABLE_64 |
  163. FIFO_TRIGGER_14);
  164. outb(uart->modem_ctrl_reg, 0x00);
  165. outb(uart->scratch_reg, 0x00);
  166. }
  167. #endif /* BSP_USING_DIRECT_UART */