uart.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * File : uart.c
  3. * This file is part of Espressif's AT+ command set program.
  4. * Copyright (C) 2013 - 2016, Espressif Systems
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of version 3 of the GNU General Public License as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. * ----------------------------------------------------------------------------
  18. * Heavily modified and enhanced by Thorsten von Eicken in 2015
  19. */
  20. #include "esp8266.h"
  21. #include "task.h"
  22. #include "uart.h"
  23. #ifdef UART_DBG
  24. #define DBG_UART(format, ...) os_printf(format, ## __VA_ARGS__)
  25. #else
  26. #define DBG_UART(format, ...) do { } while(0)
  27. #endif
  28. LOCAL uint8_t uart_recvTaskNum;
  29. // UartDev is defined and initialized in rom code.
  30. extern UartDevice UartDev;
  31. #define MAX_CB 4
  32. static UartRecv_cb uart_recv_cb[4];
  33. static void uart0_rx_intr_handler(void *para);
  34. /******************************************************************************
  35. * FunctionName : uart_config
  36. * Description : Internal used function
  37. * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
  38. * UART1 just used for debug output
  39. * Parameters : uart_no, use UART0 or UART1 defined ahead
  40. * Returns : NONE
  41. *******************************************************************************/
  42. void ICACHE_FLASH_ATTR
  43. uart_config(uint8 uart_no, UartBautRate baudrate, uint32 conf0)
  44. {
  45. if (uart_no == UART1) {
  46. PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
  47. PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO2_U);
  48. } else {
  49. /* rcv_buff size is 0x100 */
  50. ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff));
  51. PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
  52. PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, 0); // FUNC_U0RXD==0
  53. //PIN_PULLUP_DIS (PERIPHS_IO_MUX_U0TXD_U); now done in serbridgeInitPins
  54. //PIN_PULLUP_DIS (PERIPHS_IO_MUX_U0RXD_U);
  55. }
  56. uart_div_modify(uart_no, UART_CLK_FREQ / baudrate);
  57. if (uart_no == UART1) //UART 1 always 8 N 1
  58. conf0 = CALC_UARTMODE(EIGHT_BITS, NONE_BITS, ONE_STOP_BIT);
  59. WRITE_PERI_REG(UART_CONF0(uart_no), conf0);
  60. //clear rx and tx fifo,not ready
  61. SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
  62. CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
  63. if (uart_no == UART0) {
  64. // Configure RX interrupt conditions as follows: trigger rx-full when there are 80 characters
  65. // in the buffer, trigger rx-timeout when the fifo is non-empty and nothing further has been
  66. // received for 4 character periods.
  67. // Set the hardware flow-control to trigger when the FIFO holds 100 characters, although
  68. // we don't really expect the signals to actually be wired up to anything. It doesn't hurt
  69. // to set the threshold here...
  70. // We do not enable framing error interrupts 'cause they tend to cause an interrupt avalanche
  71. // and instead just poll for them when we get a std RX interrupt.
  72. WRITE_PERI_REG(UART_CONF1(uart_no),
  73. ((80 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
  74. ((100 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
  75. UART_RX_FLOW_EN |
  76. (4 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
  77. UART_RX_TOUT_EN);
  78. SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
  79. } else {
  80. WRITE_PERI_REG(UART_CONF1(uart_no),
  81. ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
  82. }
  83. //clear all interrupt
  84. WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
  85. }
  86. /******************************************************************************
  87. * FunctionName : uart1_tx_one_char
  88. * Description : Internal used function
  89. * Use uart1 interface to transfer one char
  90. * Parameters : uint8 TxChar - character to tx
  91. * Returns : OK
  92. *******************************************************************************/
  93. STATUS
  94. uart_tx_one_char(uint8 uart, uint8 c)
  95. {
  96. //Wait until there is room in the FIFO
  97. while (((READ_PERI_REG(UART_STATUS(uart))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=100) ;
  98. //Send the character
  99. WRITE_PERI_REG(UART_FIFO(uart), c);
  100. return OK;
  101. }
  102. /******************************************************************************
  103. * FunctionName : uart1_write_char
  104. * Description : Internal used function
  105. * Do some special deal while tx char is '\r' or '\n'
  106. * Parameters : char c - character to tx
  107. * Returns : NONE
  108. *******************************************************************************/
  109. void ICACHE_FLASH_ATTR
  110. uart1_write_char(char c)
  111. {
  112. //if (c == '\n') uart_tx_one_char(UART1, '\r');
  113. uart_tx_one_char(UART1, c);
  114. }
  115. void ICACHE_FLASH_ATTR
  116. uart0_write_char(char c)
  117. {
  118. //if (c == '\n') uart_tx_one_char(UART0, '\r');
  119. uart_tx_one_char(UART0, c);
  120. }
  121. /******************************************************************************
  122. * FunctionName : uart0_tx_buffer
  123. * Description : use uart0 to transfer buffer
  124. * Parameters : uint8 *buf - point to send buffer
  125. * uint16 len - buffer len
  126. * Returns :
  127. *******************************************************************************/
  128. void ICACHE_FLASH_ATTR
  129. uart0_tx_buffer(char *buf, uint16 len)
  130. {
  131. uint16 i;
  132. for (i = 0; i < len; i++)
  133. {
  134. uart_tx_one_char(UART0, buf[i]);
  135. }
  136. }
  137. /******************************************************************************
  138. * FunctionName : uart0_sendStr
  139. * Description : use uart0 to transfer buffer
  140. * Parameters : uint8 *buf - point to send buffer
  141. * uint16 len - buffer len
  142. * Returns :
  143. *******************************************************************************/
  144. void ICACHE_FLASH_ATTR
  145. uart0_sendStr(const char *str)
  146. {
  147. while(*str)
  148. {
  149. uart_tx_one_char(UART0, *str++);
  150. }
  151. }
  152. static uint32 last_frm_err; // time in us when last framing error message was printed
  153. /******************************************************************************
  154. * FunctionName : uart0_rx_intr_handler
  155. * Description : Internal used function
  156. * UART0 interrupt handler, add self handle code inside
  157. * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
  158. * Returns : NONE
  159. *******************************************************************************/
  160. static void // must not use ICACHE_FLASH_ATTR !
  161. uart0_rx_intr_handler(void *para)
  162. {
  163. // we assume that uart1 has interrupts disabled (it uses the same interrupt vector)
  164. uint8 uart_no = UART0;
  165. const uint32 one_sec = 1000000; // one second in usecs
  166. // we end up largely ignoring framing errors and we just print a warning every second max
  167. if (READ_PERI_REG(UART_INT_RAW(uart_no)) & UART_FRM_ERR_INT_RAW) {
  168. uint32 now = system_get_time();
  169. if (last_frm_err == 0 || (now - last_frm_err) > one_sec) {
  170. os_printf("UART framing error (bad baud rate?)\n");
  171. last_frm_err = now;
  172. }
  173. // clear rx fifo (apparently this is not optional at this point)
  174. SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST);
  175. CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST);
  176. // reset framing error
  177. WRITE_PERI_REG(UART_INT_CLR(UART0), UART_FRM_ERR_INT_CLR);
  178. // once framing errors are gone for 10 secs we forget about having seen them
  179. } else if (last_frm_err != 0 && (system_get_time() - last_frm_err) > 10*one_sec) {
  180. last_frm_err = 0;
  181. }
  182. if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)
  183. || UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST))
  184. {
  185. //DBG_UART("stat:%02X",*(uint8 *)UART_INT_ENA(uart_no));
  186. ETS_UART_INTR_DISABLE();
  187. post_usr_task(uart_recvTaskNum, 0);
  188. }
  189. }
  190. /******************************************************************************
  191. * FunctionName : uart_recvTask
  192. * Description : system task triggered on receive interrupt, empties FIFO and calls callbacks
  193. *******************************************************************************/
  194. static void ICACHE_FLASH_ATTR
  195. uart_recvTask(os_event_t *events)
  196. {
  197. while (READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
  198. //WRITE_PERI_REG(0X60000914, 0x73); //WTD // commented out by TvE
  199. // read a buffer-full from the uart
  200. uint16 length = 0;
  201. char buf[128];
  202. while ((READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) &&
  203. (length < 128)) {
  204. buf[length++] = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
  205. }
  206. //DBG_UART("%d ix %d\n", system_get_time(), length);
  207. for (int i=0; i<MAX_CB; i++) {
  208. if (uart_recv_cb[i] != NULL) (uart_recv_cb[i])(buf, length);
  209. }
  210. }
  211. WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
  212. ETS_UART_INTR_ENABLE();
  213. }
  214. // Turn UART interrupts off and poll for nchars or until timeout hits
  215. uint16_t ICACHE_FLASH_ATTR
  216. uart0_rx_poll(char *buff, uint16_t nchars, uint32_t timeout_us) {
  217. ETS_UART_INTR_DISABLE();
  218. uint16_t got = 0;
  219. uint32_t start = system_get_time(); // time in us
  220. while (system_get_time()-start < timeout_us) {
  221. while (READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
  222. buff[got++] = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
  223. if (got == nchars) goto done;
  224. }
  225. }
  226. done:
  227. ETS_UART_INTR_ENABLE();
  228. return got;
  229. }
  230. void ICACHE_FLASH_ATTR
  231. uart0_baud(int rate) {
  232. os_printf("UART %d baud\n", rate);
  233. uart_div_modify(UART0, UART_CLK_FREQ / rate);
  234. }
  235. void ICACHE_FLASH_ATTR
  236. uart0_config(uint8_t data_bits, uint8_t parity, uint8_t stop_bits) {
  237. uint32_t conf0 = CALC_UARTMODE(data_bits, parity, stop_bits);
  238. WRITE_PERI_REG(UART_CONF0(0), conf0);
  239. }
  240. /******************************************************************************
  241. * FunctionName : uart_init
  242. * Description : user interface for init uart
  243. * Parameters : UartBautRate uart0_br - uart0 bautrate
  244. * UartBautRate uart1_br - uart1 bautrate
  245. * Returns : NONE
  246. *******************************************************************************/
  247. void ICACHE_FLASH_ATTR
  248. uart_init(uint32 conf0, UartBautRate uart0_br, UartBautRate uart1_br)
  249. {
  250. // rom use 74880 baut_rate, here reinitialize
  251. uart_config(UART0, uart0_br, conf0);
  252. uart_config(UART1, uart1_br, conf0);
  253. for (int i=0; i<4; i++) uart_tx_one_char(UART1, '\n');
  254. for (int i=0; i<4; i++) uart_tx_one_char(UART0, '\n');
  255. ETS_UART_INTR_ENABLE();
  256. // install uart1 putc callback
  257. os_install_putc1((void *)uart0_write_char);
  258. uart_recvTaskNum = register_usr_task(uart_recvTask);
  259. }
  260. void ICACHE_FLASH_ATTR
  261. uart_add_recv_cb(UartRecv_cb cb) {
  262. for (int i=0; i<MAX_CB; i++) {
  263. if (uart_recv_cb[i] == NULL) {
  264. uart_recv_cb[i] = cb;
  265. return;
  266. }
  267. }
  268. os_printf("UART: max cb count exceeded\n");
  269. }