blob: 6c1f9e095d6c8944553bad8ee5a85969b8d48c48 [file] [log] [blame]
Damien George075d5972014-11-27 20:30:33 +00001/******************************************************************************
2 * Copyright 2013-2014 Espressif Systems (Wuxi)
3 *
4 * FileName: uart.c
5 *
6 * Description: Two UART mode configration and interrupt handler.
7 * Check your hardware connection while use this mode.
8 *
9 * Modification history:
10 * 2014/3/12, v1.0 create this file.
11*******************************************************************************/
12#include "ets_sys.h"
13#include "osapi.h"
14#include "uart.h"
15#include "osapi.h"
16#include "uart_register.h"
17#include "etshal.h"
18#include "c_types.h"
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +020019#include "user_interface.h"
20#include "esp_mphal.h"
Damien George075d5972014-11-27 20:30:33 +000021
Damien George602305b2016-05-29 10:30:27 +010022// seems that this is missing in the Espressif SDK
23#define FUNC_U0RXD 0
24
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +030025#define UART_REPL UART0
Damien George075d5972014-11-27 20:30:33 +000026
27// UartDev is defined and initialized in rom code.
28extern UartDevice UartDev;
29
Damien George96eca222016-04-06 00:12:58 +030030// the uart to which OS messages go; -1 to disable
31static int uart_os = UART_OS;
32
Damien Georgefb6cc962016-04-01 14:30:47 +030033#if MICROPY_REPL_EVENT_DRIVEN
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +020034static os_event_t uart_evt_queue[16];
Damien Georgefb6cc962016-04-01 14:30:47 +030035#endif
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +020036
Damien George075d5972014-11-27 20:30:33 +000037static void uart0_rx_intr_handler(void *para);
38
Damien George6a051a82016-04-01 14:53:01 +030039void soft_reset(void);
40void mp_keyboard_interrupt(void);
41
Damien George075d5972014-11-27 20:30:33 +000042/******************************************************************************
43 * FunctionName : uart_config
44 * Description : Internal used function
45 * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
46 * UART1 just used for debug output
47 * Parameters : uart_no, use UART0 or UART1 defined ahead
48 * Returns : NONE
49*******************************************************************************/
50static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) {
51 if (uart_no == UART1) {
52 PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
53 } else {
54 ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, NULL);
55 PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
56 PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
Damien George602305b2016-05-29 10:30:27 +010057 PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);
Damien George075d5972014-11-27 20:30:33 +000058 }
59
60 uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
61
62 WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity
63 | UartDev.parity
64 | (UartDev.stop_bits << UART_STOP_BIT_NUM_S)
65 | (UartDev.data_bits << UART_BIT_NUM_S));
66
67 // clear rx and tx fifo,not ready
68 SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
69 CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
70
71 if (uart_no == UART0) {
72 // set rx fifo trigger
73 WRITE_PERI_REG(UART_CONF1(uart_no),
74 ((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
75 ((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
76 UART_RX_FLOW_EN |
77 (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
78 UART_RX_TOUT_EN);
79 SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |
80 UART_FRM_ERR_INT_ENA);
81 } else {
82 WRITE_PERI_REG(UART_CONF1(uart_no),
83 ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
84 }
85
86 // clear all interrupt
87 WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
88 // enable rx_interrupt
89 SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
Damien George075d5972014-11-27 20:30:33 +000090}
91
92/******************************************************************************
93 * FunctionName : uart1_tx_one_char
94 * Description : Internal used function
95 * Use uart1 interface to transfer one char
96 * Parameters : uint8 TxChar - character to tx
97 * Returns : OK
98*******************************************************************************/
99void uart_tx_one_char(uint8 uart, uint8 TxChar) {
100 while (true) {
101 uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
102 if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
103 break;
104 }
105 }
106 WRITE_PERI_REG(UART_FIFO(uart), TxChar);
107}
108
Paul Sokolovskyd9d4a722016-01-03 07:33:42 +0200109void uart_flush(uint8 uart) {
110 while (true) {
111 uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
112 if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) == 0) {
113 break;
114 }
115 }
116}
117
Damien George075d5972014-11-27 20:30:33 +0000118/******************************************************************************
119 * FunctionName : uart1_write_char
120 * Description : Internal used function
121 * Do some special deal while tx char is '\r' or '\n'
122 * Parameters : char c - character to tx
123 * Returns : NONE
124*******************************************************************************/
125static void ICACHE_FLASH_ATTR
Josef Gajdusek1c132c82015-05-13 15:39:25 +0200126uart_os_write_char(char c) {
Damien George96eca222016-04-06 00:12:58 +0300127 if (uart_os == -1) {
128 return;
129 }
Damien George075d5972014-11-27 20:30:33 +0000130 if (c == '\n') {
Damien George96eca222016-04-06 00:12:58 +0300131 uart_tx_one_char(uart_os, '\r');
132 uart_tx_one_char(uart_os, '\n');
Damien George075d5972014-11-27 20:30:33 +0000133 } else if (c == '\r') {
134 } else {
Damien George96eca222016-04-06 00:12:58 +0300135 uart_tx_one_char(uart_os, c);
Damien George075d5972014-11-27 20:30:33 +0000136 }
137}
138
Damien George96eca222016-04-06 00:12:58 +0300139void ICACHE_FLASH_ATTR
140uart_os_config(int uart) {
141 uart_os = uart;
142}
143
Damien George075d5972014-11-27 20:30:33 +0000144/******************************************************************************
145 * FunctionName : uart0_rx_intr_handler
146 * Description : Internal used function
147 * UART0 interrupt handler, add self handle code inside
148 * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
149 * Returns : NONE
150*******************************************************************************/
151
152static void uart0_rx_intr_handler(void *para) {
153 /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
154 * uart1 and uart0 respectively
155 */
156
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300157 uint8 uart_no = UART_REPL;
Damien George075d5972014-11-27 20:30:33 +0000158
159 if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) {
160 // frame error
161 WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
162 }
163
164 if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) {
165 // fifo full
Damien George075d5972014-11-27 20:30:33 +0000166 goto read_chars;
167 } else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) {
Damien George075d5972014-11-27 20:30:33 +0000168 read_chars:
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300169 ETS_UART_INTR_DISABLE();
Paul Sokolovsky61fa7c82016-03-30 18:50:38 +0300170
171 while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
172 uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
Paul Sokolovsky6ab2c5e2016-09-29 10:13:17 -0700173 if (RcvChar == mp_interrupt_char) {
Damien George6a051a82016-04-01 14:53:01 +0300174 mp_keyboard_interrupt();
175 } else {
176 ringbuf_put(&input_buf, RcvChar);
177 }
Paul Sokolovsky61fa7c82016-03-30 18:50:38 +0300178 }
179
180 mp_hal_signal_input();
181
182 // Clear pending FIFO interrupts
183 WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST);
184 ETS_UART_INTR_ENABLE();
Damien George075d5972014-11-27 20:30:33 +0000185 }
186}
187
Damien George7652ab72016-04-21 15:19:00 +0100188// Waits at most timeout microseconds for at least 1 char to become ready for reading.
189// Returns true if something available, false if not.
190bool uart_rx_wait(uint32_t timeout_us) {
191 uint32_t start = system_get_time();
192 for (;;) {
193 if (input_buf.iget != input_buf.iput) {
194 return true; // have at least 1 char ready for reading
195 }
196 if (system_get_time() - start >= timeout_us) {
197 return false; // timeout
198 }
199 ets_event_poll();
200 }
201}
202
marc hoffman91eb0152017-01-29 21:48:55 -0500203int uart_rx_any(uint8 uart) {
204 if (input_buf.iget != input_buf.iput) {
205 return true; // have at least 1 char ready for reading
206 }
207 return false;
208}
209
210int uart_tx_any_room(uint8 uart) {
211 uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S);
212 if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) >= 126) {
213 return false;
214 }
215 return true;
216}
217
Damien George7652ab72016-04-21 15:19:00 +0100218// Returns char from the input buffer, else -1 if buffer is empty.
219int uart_rx_char(void) {
220 return ringbuf_get(&input_buf);
221}
222
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300223int uart_rx_one_char(uint8 uart_no) {
224 if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
225 return READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
226 }
227 return -1;
228}
229
Damien George075d5972014-11-27 20:30:33 +0000230/******************************************************************************
231 * FunctionName : uart_init
232 * Description : user interface for init uart
233 * Parameters : UartBautRate uart0_br - uart0 bautrate
234 * UartBautRate uart1_br - uart1 bautrate
235 * Returns : NONE
236*******************************************************************************/
237void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) {
238 // rom use 74880 baut_rate, here reinitialize
239 UartDev.baut_rate = uart0_br;
240 uart_config(UART0);
241 UartDev.baut_rate = uart1_br;
242 uart_config(UART1);
243 ETS_UART_INTR_ENABLE();
244
Paul Sokolovskyc4506ed2016-03-29 21:10:10 +0300245 // install handler for "os" messages
Josef Gajdusek1c132c82015-05-13 15:39:25 +0200246 os_install_putc1((void *)uart_os_write_char);
Damien George075d5972014-11-27 20:30:33 +0000247}
248
249void ICACHE_FLASH_ATTR uart_reattach() {
250 uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880);
251}
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200252
Radomir Dopieralski35962ea2016-06-29 14:18:48 +0200253void ICACHE_FLASH_ATTR uart_setup(uint8 uart) {
254 ETS_UART_INTR_DISABLE();
255 uart_config(uart);
256 ETS_UART_INTR_ENABLE();
257}
258
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200259// Task-based UART interface
260
Damien Georgec98c1282015-05-06 00:02:58 +0100261#include "py/obj.h"
Damien George40274fe2015-11-09 13:13:09 +0000262#include "lib/utils/pyexec.h"
Damien Georgec98c1282015-05-06 00:02:58 +0100263
Paul Sokolovsky785cf9a2016-04-01 14:02:36 +0300264#if MICROPY_REPL_EVENT_DRIVEN
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200265void uart_task_handler(os_event_t *evt) {
Paul Sokolovsky777232c2016-04-01 12:53:50 +0300266 if (pyexec_repl_active) {
267 // TODO: Just returning here isn't exactly right.
268 // What really should be done is something like
269 // enquing delayed event to itself, for another
270 // chance to feed data to REPL. Otherwise, there
271 // can be situation when buffer has bunch of data,
272 // and sits unprocessed, because we consumed all
273 // processing signals like this.
274 return;
275 }
276
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300277 int c, ret = 0;
Paul Sokolovsky61fa7c82016-03-30 18:50:38 +0300278 while ((c = ringbuf_get(&input_buf)) >= 0) {
Paul Sokolovskyd3a4d392015-12-20 13:58:58 +0200279 if (c == interrupt_char) {
280 mp_keyboard_interrupt();
281 }
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300282 ret = pyexec_event_repl_process_char(c);
283 if (ret & PYEXEC_FORCED_EXIT) {
284 break;
285 }
286 }
287
Damien Georgec98c1282015-05-06 00:02:58 +0100288 if (ret & PYEXEC_FORCED_EXIT) {
289 soft_reset();
290 }
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200291}
292
293void uart_task_init() {
294 system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue));
295}
Paul Sokolovsky785cf9a2016-04-01 14:02:36 +0300296#endif