Using the tx/rx pins not for UART
Re: Using the tx/rx pins not for UART
Hi,
I also want to use the UART to talk to an external device and would love to disable REPL-traffic in the UART. Can you please be more precise what you changed? Or maybe you can just share the binary to put on the board?
Regs Henning
I also want to use the UART to talk to an external device and would love to disable REPL-traffic in the UART. Can you please be more precise what you changed? Or maybe you can just share the binary to put on the board?
Regs Henning
Re: Using the tx/rx pins not for UART
The REPL only happens if you don't arrange for something else to happen at startup using a main.py/boot.by so this isn't a real problem.
Dealing with the garbage is a combination of esp.osdebug(False) and the hardware tweaks I covered in another post http://forum.micropython.org/viewtopic. ... t+use+uart
Jon
Dealing with the garbage is a combination of esp.osdebug(False) and the hardware tweaks I covered in another post http://forum.micropython.org/viewtopic. ... t+use+uart
Jon
Re: Using the tx/rx pins not for UART
Actually it is a real problem, if you want to use WebREPL without using the REPL.
Re: Using the tx/rx pins not for UART
Yes, using the WebREPL while having fully independent control of the UART interface is nice. In general it's good to have STDOUT/STDIN decoupled from any particular interface (our lonely UART in the case of ESP8266). As I mentioned in my previous post, I'd like to hear from other MP users regarding what an appropriate API would be to do this. For my purposes, it was just fine to overload the meaning of esp.osdebug(None) as I mentioned previously. My patch is simple, and only touches three files on v1.8.2. See patch below for complete changes. Hope this helps! Would love to see this incorporated in mainline MP.
-----
diff --git a/esp8266/esp_mphal.c b/esp8266/esp_mphal.c
index 3cc4610..a3ddbce 100644
--- a/esp8266/esp_mphal.c
+++ b/esp8266/esp_mphal.c
@@ -40,8 +40,14 @@ extern void ets_wdt_disable(void);
extern void wdt_feed(void);
extern void ets_delay_us();
+
+// Buffer for UART
STATIC byte input_buf_array[256];
ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)};
+// Separate buffer for duplicate terminal (WebREPL) so that UART can be detached from REPL
+STATIC byte dupterm_buf_array[256];
+ringbuf_t dupterm_buf = {dupterm_buf_array, sizeof(dupterm_buf_array)};
+
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len);
const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked};
@@ -60,16 +66,27 @@ void mp_hal_delay_us(uint32_t us) {
int mp_hal_stdin_rx_chr(void) {
for (;;) {
- int c = ringbuf_get(&input_buf);
+ //int c = ringbuf_get(&input_buf);
+
+ // Read next char from UART if enabled
+ int c = uart_std_getc(); // DBE
+ if (c != -1) {
+ return c;
+ }
+
+ // Read next char from duplicate terminal (WebREPL) - note that UART has priority when enabled
+ c = ringbuf_get(&dupterm_buf);
if (c != -1) {
return c;
}
+
mp_hal_delay_us(1);
}
}
void mp_hal_stdout_tx_char(char c) {
- uart_tx_one_char(UART0, c);
+ //uart_tx_one_char(UART0, c);
+ uart_std_putc(c); //DBE
mp_uos_dupterm_tx_strn(&c, 1);
}
@@ -200,7 +217,8 @@ STATIC void dupterm_task_handler(os_event_t *evt) {
if (c < 0) {
break;
}
- ringbuf_put(&input_buf, c);
+ //ringbuf_put(&input_buf, c);
+ ringbuf_put(&dupterm_buf, c); // DBE
}
mp_hal_signal_input();
lock = 0;
diff --git a/esp8266/uart.c b/esp8266/uart.c
index d724331..267eb9e 100644
--- a/esp8266/uart.c
+++ b/esp8266/uart.c
@@ -172,7 +172,7 @@ static void uart0_rx_intr_handler(void *para) {
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
- if (RcvChar == interrupt_char) {
+ if (RcvChar == interrupt_char && uart_os >= 0) {
mp_keyboard_interrupt();
} else {
ringbuf_put(&input_buf, RcvChar);
@@ -202,6 +202,23 @@ bool uart_rx_wait(uint32_t timeout_us) {
}
}
+void uart_std_putc(uint8 c)
+{
+ if (uart_os < 0) {
+ return;
+ }
+ uart_tx_one_char(UART0, c);
+}
+
+// Returns char from the input buffer, else -1 if buffer is empty.
+int uart_std_getc(void) {
+ // DBE - Disconnect REPL
+ if (uart_os < 0) {
+ return -1;
+ }
+ return ringbuf_get(&input_buf);
+}
+
// Returns char from the input buffer, else -1 if buffer is empty.
int uart_rx_char(void) {
return ringbuf_get(&input_buf);
diff --git a/esp8266/uart.h b/esp8266/uart.h
index 21894d3..91a4d31 100644
--- a/esp8266/uart.h
+++ b/esp8266/uart.h
@@ -98,4 +98,8 @@ void uart_flush(uint8 uart);
void uart_os_config(int uart);
void uart_setup(uint8 uart);
+// UART functions used by STDIO (REPL)
+int uart_std_getc(void);
+void uart_std_putc(uint8 c);
+
#endif // _INCLUDED_UART_H_
-----
diff --git a/esp8266/esp_mphal.c b/esp8266/esp_mphal.c
index 3cc4610..a3ddbce 100644
--- a/esp8266/esp_mphal.c
+++ b/esp8266/esp_mphal.c
@@ -40,8 +40,14 @@ extern void ets_wdt_disable(void);
extern void wdt_feed(void);
extern void ets_delay_us();
+
+// Buffer for UART
STATIC byte input_buf_array[256];
ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)};
+// Separate buffer for duplicate terminal (WebREPL) so that UART can be detached from REPL
+STATIC byte dupterm_buf_array[256];
+ringbuf_t dupterm_buf = {dupterm_buf_array, sizeof(dupterm_buf_array)};
+
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len);
const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked};
@@ -60,16 +66,27 @@ void mp_hal_delay_us(uint32_t us) {
int mp_hal_stdin_rx_chr(void) {
for (;;) {
- int c = ringbuf_get(&input_buf);
+ //int c = ringbuf_get(&input_buf);
+
+ // Read next char from UART if enabled
+ int c = uart_std_getc(); // DBE
+ if (c != -1) {
+ return c;
+ }
+
+ // Read next char from duplicate terminal (WebREPL) - note that UART has priority when enabled
+ c = ringbuf_get(&dupterm_buf);
if (c != -1) {
return c;
}
+
mp_hal_delay_us(1);
}
}
void mp_hal_stdout_tx_char(char c) {
- uart_tx_one_char(UART0, c);
+ //uart_tx_one_char(UART0, c);
+ uart_std_putc(c); //DBE
mp_uos_dupterm_tx_strn(&c, 1);
}
@@ -200,7 +217,8 @@ STATIC void dupterm_task_handler(os_event_t *evt) {
if (c < 0) {
break;
}
- ringbuf_put(&input_buf, c);
+ //ringbuf_put(&input_buf, c);
+ ringbuf_put(&dupterm_buf, c); // DBE
}
mp_hal_signal_input();
lock = 0;
diff --git a/esp8266/uart.c b/esp8266/uart.c
index d724331..267eb9e 100644
--- a/esp8266/uart.c
+++ b/esp8266/uart.c
@@ -172,7 +172,7 @@ static void uart0_rx_intr_handler(void *para) {
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
- if (RcvChar == interrupt_char) {
+ if (RcvChar == interrupt_char && uart_os >= 0) {
mp_keyboard_interrupt();
} else {
ringbuf_put(&input_buf, RcvChar);
@@ -202,6 +202,23 @@ bool uart_rx_wait(uint32_t timeout_us) {
}
}
+void uart_std_putc(uint8 c)
+{
+ if (uart_os < 0) {
+ return;
+ }
+ uart_tx_one_char(UART0, c);
+}
+
+// Returns char from the input buffer, else -1 if buffer is empty.
+int uart_std_getc(void) {
+ // DBE - Disconnect REPL
+ if (uart_os < 0) {
+ return -1;
+ }
+ return ringbuf_get(&input_buf);
+}
+
// Returns char from the input buffer, else -1 if buffer is empty.
int uart_rx_char(void) {
return ringbuf_get(&input_buf);
diff --git a/esp8266/uart.h b/esp8266/uart.h
index 21894d3..91a4d31 100644
--- a/esp8266/uart.h
+++ b/esp8266/uart.h
@@ -98,4 +98,8 @@ void uart_flush(uint8 uart);
void uart_os_config(int uart);
void uart_setup(uint8 uart);
+// UART functions used by STDIO (REPL)
+int uart_std_getc(void);
+void uart_std_putc(uint8 c);
+
#endif // _INCLUDED_UART_H_
Re: Using the tx/rx pins not for UART
The problem isnt's just the REPL.
There are many things that output stuff when strictly then shouldn't (for example ntptime) and given the lack of a concept of stdout and things an operating system would provide where should these go ?
Jon
There are many things that output stuff when strictly then shouldn't (for example ntptime) and given the lack of a concept of stdout and things an operating system would provide where should these go ?
Jon
Re: Using the tx/rx pins not for UART
Ideally we would be able to redirect the repl to /dev/null, and still connect over webrepl (if enabled), but then use rx/tx for something else.
I don't think we can prevent the firmware and bootloader spitting out rubbish at 75k baud at boot-time, but that only affects tx (and some rubbish comes out of gpio2 too)
I don't think we can prevent the firmware and bootloader spitting out rubbish at 75k baud at boot-time, but that only affects tx (and some rubbish comes out of gpio2 too)
Re: Using the tx/rx pins not for UART
Redirecting the UartREPL to /dev/null while keeping the WebREPL active is effectively what my patch does. So what's a "proper" API to achieve this?
I agree that eliminating the startup garbage would require changes to ESP code outside the Micropython sources. For my purposes it's not a problem since I'm using the UART pins for a UART peripheral at a different baud rate.
As to the concept of STDIN/STDOUT, python itself gives us that in the sys module - sys.stdout being where the output of 'print' is sent by default, etc. Since in CPython setting sys.stdout=None eliminates print() output without affecting the REPL, we might want to decouple the concepts eventually. Currently Micropython writes/reads from both interfaces (UART and Websocket) in mp_hal_stdout_tx_char() and mp_hal_stdin_rx_chr() functions. A simple 'redirect' of sys.stdout/sys.stdin/sys.stderr to one interface or the other would lose the ability to achieve this "multi-interface" feature. Actually, I'm not sure if anyone out there is actively relying on the concurrent use of WebREPL + UART, but any change would need to consider this.
I agree that eliminating the startup garbage would require changes to ESP code outside the Micropython sources. For my purposes it's not a problem since I'm using the UART pins for a UART peripheral at a different baud rate.
As to the concept of STDIN/STDOUT, python itself gives us that in the sys module - sys.stdout being where the output of 'print' is sent by default, etc. Since in CPython setting sys.stdout=None eliminates print() output without affecting the REPL, we might want to decouple the concepts eventually. Currently Micropython writes/reads from both interfaces (UART and Websocket) in mp_hal_stdout_tx_char() and mp_hal_stdin_rx_chr() functions. A simple 'redirect' of sys.stdout/sys.stdin/sys.stderr to one interface or the other would lose the ability to achieve this "multi-interface" feature. Actually, I'm not sure if anyone out there is actively relying on the concurrent use of WebREPL + UART, but any change would need to consider this.
Re: Using the tx/rx pins not for UART
@brad, if you want your patch to be incorporated into MicroPython, and if you want to hear feedback from the developers as to how to do it best, it's best if you make a pull request on github.
Re: Using the tx/rx pins not for UART
Yes, I will do that. Thanks.
Re: Using the tx/rx pins not for UART
Thx Brad,
I'll try to bake an firmware with your changes.
Henning
I'll try to bake an firmware with your changes.
Henning