blob: ed5e1d9979dcc53e76439156f1da9bf5fff79c72 [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 Georgefb6cc962016-04-01 14:30:47 +030027/* unused
Damien George075d5972014-11-27 20:30:33 +000028// circular buffer for RX buffering
Damien Georgefb6cc962016-04-01 14:30:47 +030029#define RX_BUF_SIZE (256)
Damien George075d5972014-11-27 20:30:33 +000030static uint16_t rx_buf_in;
31static uint16_t rx_buf_out;
32static uint8_t rx_buf[RX_BUF_SIZE];
Damien Georgefb6cc962016-04-01 14:30:47 +030033*/
Damien George075d5972014-11-27 20:30:33 +000034
Damien Georgefb6cc962016-04-01 14:30:47 +030035#if MICROPY_REPL_EVENT_DRIVEN
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +020036static os_event_t uart_evt_queue[16];
Damien Georgefb6cc962016-04-01 14:30:47 +030037#endif
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +020038
Damien George075d5972014-11-27 20:30:33 +000039static void uart0_rx_intr_handler(void *para);
40
41/******************************************************************************
42 * FunctionName : uart_config
43 * Description : Internal used function
44 * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
45 * UART1 just used for debug output
46 * Parameters : uart_no, use UART0 or UART1 defined ahead
47 * Returns : NONE
48*******************************************************************************/
49static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) {
50 if (uart_no == UART1) {
51 PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
52 } else {
53 ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, NULL);
54 PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
55 PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
56 PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
57 }
58
59 uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
60
61 WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity
62 | UartDev.parity
63 | (UartDev.stop_bits << UART_STOP_BIT_NUM_S)
64 | (UartDev.data_bits << UART_BIT_NUM_S));
65
66 // clear rx and tx fifo,not ready
67 SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
68 CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
69
70 if (uart_no == UART0) {
71 // set rx fifo trigger
72 WRITE_PERI_REG(UART_CONF1(uart_no),
73 ((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
74 ((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
75 UART_RX_FLOW_EN |
76 (0x02 & 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_TOUT_INT_ENA |
79 UART_FRM_ERR_INT_ENA);
80 } else {
81 WRITE_PERI_REG(UART_CONF1(uart_no),
82 ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
83 }
84
85 // clear all interrupt
86 WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
87 // enable rx_interrupt
88 SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
89
Damien Georgefb6cc962016-04-01 14:30:47 +030090 /* unused
Damien George075d5972014-11-27 20:30:33 +000091 // init RX buffer
92 rx_buf_in = 0;
93 rx_buf_out = 0;
Damien Georgefb6cc962016-04-01 14:30:47 +030094 */
Damien George075d5972014-11-27 20:30:33 +000095}
96
97/******************************************************************************
98 * FunctionName : uart1_tx_one_char
99 * Description : Internal used function
100 * Use uart1 interface to transfer one char
101 * Parameters : uint8 TxChar - character to tx
102 * Returns : OK
103*******************************************************************************/
104void uart_tx_one_char(uint8 uart, uint8 TxChar) {
105 while (true) {
106 uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
107 if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
108 break;
109 }
110 }
111 WRITE_PERI_REG(UART_FIFO(uart), TxChar);
112}
113
Paul Sokolovskyd9d4a722016-01-03 07:33:42 +0200114void uart_flush(uint8 uart) {
115 while (true) {
116 uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
117 if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) == 0) {
118 break;
119 }
120 }
121}
122
Damien George075d5972014-11-27 20:30:33 +0000123/******************************************************************************
124 * FunctionName : uart1_write_char
125 * Description : Internal used function
126 * Do some special deal while tx char is '\r' or '\n'
127 * Parameters : char c - character to tx
128 * Returns : NONE
129*******************************************************************************/
130static void ICACHE_FLASH_ATTR
Josef Gajdusek1c132c82015-05-13 15:39:25 +0200131uart_os_write_char(char c) {
Damien George075d5972014-11-27 20:30:33 +0000132 if (c == '\n') {
Josef Gajdusek1c132c82015-05-13 15:39:25 +0200133 uart_tx_one_char(UART_OS, '\r');
134 uart_tx_one_char(UART_OS, '\n');
Damien George075d5972014-11-27 20:30:33 +0000135 } else if (c == '\r') {
136 } else {
Josef Gajdusek1c132c82015-05-13 15:39:25 +0200137 uart_tx_one_char(UART_OS, c);
Damien George075d5972014-11-27 20:30:33 +0000138 }
139}
140
141/******************************************************************************
142 * FunctionName : uart0_rx_intr_handler
143 * Description : Internal used function
144 * UART0 interrupt handler, add self handle code inside
145 * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
146 * Returns : NONE
147*******************************************************************************/
148
149static void uart0_rx_intr_handler(void *para) {
150 /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
151 * uart1 and uart0 respectively
152 */
153
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300154 uint8 uart_no = UART_REPL;
Damien George075d5972014-11-27 20:30:33 +0000155
156 if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) {
157 // frame error
158 WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
159 }
160
161 if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) {
162 // fifo full
Damien George075d5972014-11-27 20:30:33 +0000163 goto read_chars;
164 } 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 +0000165 read_chars:
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200166#if 1 //MICROPY_REPL_EVENT_DRIVEN is not available here
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300167 ETS_UART_INTR_DISABLE();
Paul Sokolovsky61fa7c82016-03-30 18:50:38 +0300168
169 while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
170 uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
171 ringbuf_put(&input_buf, RcvChar);
172 }
173
174 mp_hal_signal_input();
175
176 // Clear pending FIFO interrupts
177 WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST);
178 ETS_UART_INTR_ENABLE();
179
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200180#else
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300181 while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
182 uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
Damien George075d5972014-11-27 20:30:33 +0000183 uint16_t rx_buf_in_next = (rx_buf_in + 1) % RX_BUF_SIZE;
184 if (rx_buf_in_next != rx_buf_out) {
185 rx_buf[rx_buf_in] = RcvChar;
186 rx_buf_in = rx_buf_in_next;
187 }
188 }
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300189#endif
Damien George075d5972014-11-27 20:30:33 +0000190 }
191}
192
Damien Georgefb6cc962016-04-01 14:30:47 +0300193/* unused
Damien George075d5972014-11-27 20:30:33 +0000194int uart0_rx(void) {
195 if (rx_buf_out != rx_buf_in) {
196 int chr = rx_buf[rx_buf_out];
197 rx_buf_out = (rx_buf_out + 1) % RX_BUF_SIZE;
198 return chr;
199 } else {
200 return -1;
201 }
202}
Damien Georgefb6cc962016-04-01 14:30:47 +0300203*/
Damien George075d5972014-11-27 20:30:33 +0000204
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300205int uart_rx_one_char(uint8 uart_no) {
206 if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
207 return READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
208 }
209 return -1;
210}
211
Damien George075d5972014-11-27 20:30:33 +0000212/******************************************************************************
213 * FunctionName : uart_init
214 * Description : user interface for init uart
215 * Parameters : UartBautRate uart0_br - uart0 bautrate
216 * UartBautRate uart1_br - uart1 bautrate
217 * Returns : NONE
218*******************************************************************************/
219void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) {
220 // rom use 74880 baut_rate, here reinitialize
221 UartDev.baut_rate = uart0_br;
222 uart_config(UART0);
223 UartDev.baut_rate = uart1_br;
224 uart_config(UART1);
225 ETS_UART_INTR_ENABLE();
226
Paul Sokolovskyc4506ed2016-03-29 21:10:10 +0300227 // install handler for "os" messages
Josef Gajdusek1c132c82015-05-13 15:39:25 +0200228 os_install_putc1((void *)uart_os_write_char);
Damien George075d5972014-11-27 20:30:33 +0000229}
230
231void ICACHE_FLASH_ATTR uart_reattach() {
232 uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880);
233}
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200234
235// Task-based UART interface
236
Damien Georgec98c1282015-05-06 00:02:58 +0100237#include "py/obj.h"
Damien George40274fe2015-11-09 13:13:09 +0000238#include "lib/utils/pyexec.h"
Damien Georgec98c1282015-05-06 00:02:58 +0100239
240void soft_reset(void);
Paul Sokolovskyd3a4d392015-12-20 13:58:58 +0200241void mp_keyboard_interrupt(void);
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200242
Paul Sokolovskyd3a4d392015-12-20 13:58:58 +0200243int interrupt_char;
Paul Sokolovsky785cf9a2016-04-01 14:02:36 +0300244#if MICROPY_REPL_EVENT_DRIVEN
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200245void uart_task_handler(os_event_t *evt) {
Paul Sokolovsky777232c2016-04-01 12:53:50 +0300246 if (pyexec_repl_active) {
247 // TODO: Just returning here isn't exactly right.
248 // What really should be done is something like
249 // enquing delayed event to itself, for another
250 // chance to feed data to REPL. Otherwise, there
251 // can be situation when buffer has bunch of data,
252 // and sits unprocessed, because we consumed all
253 // processing signals like this.
254 return;
255 }
256
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300257 int c, ret = 0;
Paul Sokolovsky61fa7c82016-03-30 18:50:38 +0300258 while ((c = ringbuf_get(&input_buf)) >= 0) {
Paul Sokolovskyd3a4d392015-12-20 13:58:58 +0200259 if (c == interrupt_char) {
260 mp_keyboard_interrupt();
261 }
Paul Sokolovsky2fc1e642015-06-01 01:27:39 +0300262 ret = pyexec_event_repl_process_char(c);
263 if (ret & PYEXEC_FORCED_EXIT) {
264 break;
265 }
266 }
267
Damien Georgec98c1282015-05-06 00:02:58 +0100268 if (ret & PYEXEC_FORCED_EXIT) {
269 soft_reset();
270 }
Paul Sokolovskyf12ea7c2015-01-16 01:54:40 +0200271}
272
273void uart_task_init() {
274 system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue));
275}
Paul Sokolovsky785cf9a2016-04-01 14:02:36 +0300276#endif