Using the tx/rx pins not for UART

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
HenningA
Posts: 5
Joined: Sat Sep 17, 2016 3:45 pm
Location: Germany

Re: Using the tx/rx pins not for UART

Post by HenningA » Sat Sep 17, 2016 3:47 pm

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

jms
Posts: 108
Joined: Thu May 05, 2016 8:29 pm
Contact:

Re: Using the tx/rx pins not for UART

Post by jms » Sun Sep 18, 2016 6:53 pm

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

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: Using the tx/rx pins not for UART

Post by deshipu » Sun Sep 18, 2016 7:55 pm

Actually it is a real problem, if you want to use WebREPL without using the REPL.

brad
Posts: 7
Joined: Sun Jul 17, 2016 12:36 pm

Re: Using the tx/rx pins not for UART

Post by brad » Sun Sep 18, 2016 10:18 pm

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_

jms
Posts: 108
Joined: Thu May 05, 2016 8:29 pm
Contact:

Re: Using the tx/rx pins not for UART

Post by jms » Mon Sep 19, 2016 10:09 am

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

markxr
Posts: 62
Joined: Wed Jun 01, 2016 3:41 pm

Re: Using the tx/rx pins not for UART

Post by markxr » Mon Sep 19, 2016 1:57 pm

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)

brad
Posts: 7
Joined: Sun Jul 17, 2016 12:36 pm

Re: Using the tx/rx pins not for UART

Post by brad » Mon Sep 19, 2016 2:27 pm

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.

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: Using the tx/rx pins not for UART

Post by deshipu » Mon Sep 19, 2016 4:25 pm

@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.

brad
Posts: 7
Joined: Sun Jul 17, 2016 12:36 pm

Re: Using the tx/rx pins not for UART

Post by brad » Mon Sep 19, 2016 11:05 pm

Yes, I will do that. Thanks.

HenningA
Posts: 5
Joined: Sat Sep 17, 2016 3:45 pm
Location: Germany

Re: Using the tx/rx pins not for UART

Post by HenningA » Tue Sep 20, 2016 1:42 pm

Thx Brad,

I'll try to bake an firmware with your changes.

Henning

Post Reply