blob: f371935399e1887b097a0eca2f59d36ab860bba8 [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
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +030022#define UART_REPL UART0
Damien George075d5972014-11-27 20:30:33 +000023
24// UartDev is defined and initialized in rom code.
25extern UartDevice UartDev;
26
Damien George96eca222016-04-06 00:12:58 +030027// the uart to which OS messages go; -1 to disable
28static int uart_os = UART_OS;
29
Damien Georgefb6cc962016-04-01 14:30:47 +030030/* unused
Damien George075d5972014-11-27 20:30:33 +000031// circular buffer for RX buffering
Damien Georgefb6cc962016-04-01 14:30:47 +030032#define RX_BUF_SIZE (256)
Damien George075d5972014-11-27 20:30:33 +000033static uint16_t rx_buf_in;
34static uint16_t rx_buf_out;
35static uint8_t rx_buf[RX_BUF_SIZE];
Damien Georgefb6cc962016-04-01 14:30:47 +030036*/
Damien George075d5972014-11-27 20:30:33 +000037
Damien Georgefb6cc962016-04-01 14:30:47 +030038#if MICROPY_REPL_EVENT_DRIVEN
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +020039static os_event_t uart_evt_queue[16];
Damien Georgefb6cc962016-04-01 14:30:47 +030040#endif
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +020041
Damien George075d5972014-11-27 20:30:33 +000042static void uart0_rx_intr_handler(void *para);
43
Damien George6a051a82016-04-01 14:53:01 +030044void soft_reset(void);
45void mp_keyboard_interrupt(void);
46
47int interrupt_char;
48
Damien George075d5972014-11-27 20:30:33 +000049/******************************************************************************
50 * FunctionName : uart_config
51 * Description : Internal used function
52 * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
53 * UART1 just used for debug output
54 * Parameters : uart_no, use UART0 or UART1 defined ahead
55 * Returns : NONE
56*******************************************************************************/
57static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) {
58 if (uart_no == UART1) {
59 PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
60 } else {
61 ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, NULL);
62 PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
63 PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
64 PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
65 }
66
67 uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
68
69 WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity
70 | UartDev.parity
71 | (UartDev.stop_bits << UART_STOP_BIT_NUM_S)
72 | (UartDev.data_bits << UART_BIT_NUM_S));
73
74 // clear rx and tx fifo,not ready
75 SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
76 CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
77
78 if (uart_no == UART0) {
79 // set rx fifo trigger
80 WRITE_PERI_REG(UART_CONF1(uart_no),
81 ((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
82 ((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
83 UART_RX_FLOW_EN |
84 (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
85 UART_RX_TOUT_EN);
86 SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |
87 UART_FRM_ERR_INT_ENA);
88 } else {
89 WRITE_PERI_REG(UART_CONF1(uart_no),
90 ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
91 }
92
93 // clear all interrupt
94 WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
95 // enable rx_interrupt
96 SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
97
Damien Georgefb6cc962016-04-01 14:30:47 +030098 /* unused
Damien George075d5972014-11-27 20:30:33 +000099 // init RX buffer
100 rx_buf_in = 0;
101 rx_buf_out = 0;
Damien Georgefb6cc962016-04-01 14:30:47 +0300102 */
Damien George075d5972014-11-27 20:30:33 +0000103}
104
105/******************************************************************************
106 * FunctionName : uart1_tx_one_char
107 * Description : Internal used function
108 * Use uart1 interface to transfer one char
109 * Parameters : uint8 TxChar - character to tx
110 * Returns : OK
111*******************************************************************************/
112void uart_tx_one_char(uint8 uart, uint8 TxChar) {
113 while (true) {
114 uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
115 if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
116 break;
117 }
118 }
119 WRITE_PERI_REG(UART_FIFO(uart), TxChar);
120}
121
Paul Sokolovskyd9d4a722016-01-03 07:33:42 +0200122void uart_flush(uint8 uart) {
123 while (true) {
124 uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
125 if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) == 0) {
126 break;
127 }
128 }
129}
130
Damien George075d5972014-11-27 20:30:33 +0000131/******************************************************************************
132 * FunctionName : uart1_write_char
133 * Description : Internal used function
134 * Do some special deal while tx char is '\r' or '\n'
135 * Parameters : char c - character to tx
136 * Returns : NONE
137*******************************************************************************/
138static void ICACHE_FLASH_ATTR
Josef Gajdusek1c132c82015-05-13 15:39:25 +0200139uart_os_write_char(char c) {
Damien George96eca222016-04-06 00:12:58 +0300140 if (uart_os == -1) {
141 return;
142 }
Damien George075d5972014-11-27 20:30:33 +0000143 if (c == '\n') {
Damien George96eca222016-04-06 00:12:58 +0300144 uart_tx_one_char(uart_os, '\r');
145 uart_tx_one_char(uart_os, '\n');
Damien George075d5972014-11-27 20:30:33 +0000146 } else if (c == '\r') {
147 } else {
Damien George96eca222016-04-06 00:12:58 +0300148 uart_tx_one_char(uart_os, c);
Damien George075d5972014-11-27 20:30:33 +0000149 }
150}
151
Damien George96eca222016-04-06 00:12:58 +0300152void ICACHE_FLASH_ATTR
153uart_os_config(int uart) {
154 uart_os = uart;
155}
156
Damien George075d5972014-11-27 20:30:33 +0000157/******************************************************************************
158 * FunctionName : uart0_rx_intr_handler
159 * Description : Internal used function
160 * UART0 interrupt handler, add self handle code inside
161 * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
162 * Returns : NONE
163*******************************************************************************/
164
165static void uart0_rx_intr_handler(void *para) {
166 /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
167 * uart1 and uart0 respectively
168 */
169
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300170 uint8 uart_no = UART_REPL;
Damien George075d5972014-11-27 20:30:33 +0000171
172 if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) {
173 // frame error
174 WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
175 }
176
177 if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) {
178 // fifo full
Damien George075d5972014-11-27 20:30:33 +0000179 goto read_chars;
180 } 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 +0000181 read_chars:
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200182#if 1 //MICROPY_REPL_EVENT_DRIVEN is not available here
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300183 ETS_UART_INTR_DISABLE();
Paul Sokolovsky61fa7c82016-03-30 18:50:38 +0300184
185 while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
186 uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
Damien George6a051a82016-04-01 14:53:01 +0300187 if (RcvChar == interrupt_char) {
188 mp_keyboard_interrupt();
189 } else {
190 ringbuf_put(&input_buf, RcvChar);
191 }
Paul Sokolovsky61fa7c82016-03-30 18:50:38 +0300192 }
193
194 mp_hal_signal_input();
195
196 // Clear pending FIFO interrupts
197 WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST);
198 ETS_UART_INTR_ENABLE();
199
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200200#else
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300201 while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
202 uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
Damien George075d5972014-11-27 20:30:33 +0000203 uint16_t rx_buf_in_next = (rx_buf_in + 1) % RX_BUF_SIZE;
204 if (rx_buf_in_next != rx_buf_out) {
205 rx_buf[rx_buf_in] = RcvChar;
206 rx_buf_in = rx_buf_in_next;
207 }
208 }
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300209#endif
Damien George075d5972014-11-27 20:30:33 +0000210 }
211}
212
Damien Georgefb6cc962016-04-01 14:30:47 +0300213/* unused
Damien George075d5972014-11-27 20:30:33 +0000214int uart0_rx(void) {
215 if (rx_buf_out != rx_buf_in) {
216 int chr = rx_buf[rx_buf_out];
217 rx_buf_out = (rx_buf_out + 1) % RX_BUF_SIZE;
218 return chr;
219 } else {
220 return -1;
221 }
222}
Damien Georgefb6cc962016-04-01 14:30:47 +0300223*/
Damien George075d5972014-11-27 20:30:33 +0000224
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300225int uart_rx_one_char(uint8 uart_no) {
226 if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
227 return READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
228 }
229 return -1;
230}
231
Damien George075d5972014-11-27 20:30:33 +0000232/******************************************************************************
233 * FunctionName : uart_init
234 * Description : user interface for init uart
235 * Parameters : UartBautRate uart0_br - uart0 bautrate
236 * UartBautRate uart1_br - uart1 bautrate
237 * Returns : NONE
238*******************************************************************************/
239void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) {
240 // rom use 74880 baut_rate, here reinitialize
241 UartDev.baut_rate = uart0_br;
242 uart_config(UART0);
243 UartDev.baut_rate = uart1_br;
244 uart_config(UART1);
245 ETS_UART_INTR_ENABLE();
246
Paul Sokolovskyc4506ed2016-03-29 21:10:10 +0300247 // install handler for "os" messages
Josef Gajdusek1c132c82015-05-13 15:39:25 +0200248 os_install_putc1((void *)uart_os_write_char);
Damien George075d5972014-11-27 20:30:33 +0000249}
250
251void ICACHE_FLASH_ATTR uart_reattach() {
252 uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880);
253}
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200254
255// Task-based UART interface
256
Damien Georgec98c1282015-05-06 00:02:58 +0100257#include "py/obj.h"
Damien George40274fe2015-11-09 13:13:09 +0000258#include "lib/utils/pyexec.h"
Damien Georgec98c1282015-05-06 00:02:58 +0100259
Paul Sokolovsky785cf9a2016-04-01 14:02:36 +0300260#if MICROPY_REPL_EVENT_DRIVEN
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200261void uart_task_handler(os_event_t *evt) {
Paul Sokolovsky777232c2016-04-01 12:53:50 +0300262 if (pyexec_repl_active) {
263 // TODO: Just returning here isn't exactly right.
264 // What really should be done is something like
265 // enquing delayed event to itself, for another
266 // chance to feed data to REPL. Otherwise, there
267 // can be situation when buffer has bunch of data,
268 // and sits unprocessed, because we consumed all
269 // processing signals like this.
270 return;
271 }
272
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300273 int c, ret = 0;
Paul Sokolovsky61fa7c82016-03-30 18:50:38 +0300274 while ((c = ringbuf_get(&input_buf)) >= 0) {
Paul Sokolovskyd3a4d392015-12-20 13:58:58 +0200275 if (c == interrupt_char) {
276 mp_keyboard_interrupt();
277 }
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300278 ret = pyexec_event_repl_process_char(c);
279 if (ret & PYEXEC_FORCED_EXIT) {
280 break;
281 }
282 }
283
Damien Georgec98c1282015-05-06 00:02:58 +0100284 if (ret & PYEXEC_FORCED_EXIT) {
285 soft_reset();
286 }
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200287}
288
289void uart_task_init() {
290 system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue));
291}
Paul Sokolovsky785cf9a2016-04-01 14:02:36 +0300292#endif