From ff2858a906fc65e2b3c5c251e3488ffa6d53ff60 Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Sun, 29 Jul 2018 12:41:26 +0200 Subject: [PATCH 1/8] Function added to detect baudrate --- cores/esp8266/uart.c | 37 +++++++++++++++++++++++++++++++++++++ cores/esp8266/uart.h | 2 ++ 2 files changed, 39 insertions(+) diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c index 47814f7a9d..2c9f56bcb9 100644 --- a/cores/esp8266/uart.c +++ b/cores/esp8266/uart.c @@ -44,6 +44,7 @@ #include "uart.h" #include "esp8266_peri.h" #include "user_interface.h" +#include "uart_register.h" const char overrun_str [] ICACHE_RODATA_ATTR STORE_ATTR = "uart input full!\r\n"; static int s_uart_debug_nr = UART0; @@ -739,3 +740,39 @@ uart_get_debug() { return s_uart_debug_nr; } + +/* +To start detection of baud rate with the UART the UART_AUTOBAUD_EN bit needs to be cleared and set. The ROM function uart_baudrate_detect() does this only once, so on a next call the UartDev.rcv_state is not equal to BAUD_RATE_DET. Instead of poking around in the UartDev struct with unknown effect, the UART_AUTOBAUD_EN bit is directly triggered by the function uart_detect_baudrate(). +*/ +int +uart_detect_baudrate(int uart_nr) +{ + static bool doTrigger = true; + + if(doTrigger) + { + USA(uart_nr) &= ~(UART_GLITCH_FILT << UART_GLITCH_FILT_S | UART_AUTOBAUD_EN); + USA(uart_nr) = 0x08 << UART_GLITCH_FILT_S | UART_AUTOBAUD_EN; + doTrigger = false; + } + + int32_t divisor = uart_baudrate_detect(uart_nr, 1); + if(!divisor) return 0; + + doTrigger = true; // Initialize for a next round + int32_t baudrate = UART_CLK_FREQ / divisor; + + static const int default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400}; + + size_t i; + for(i = 1; i < sizeof(default_rates) / sizeof(default_rates[0]) - 1; i++) // find the nearest real baudrate + { + if(baudrate <= default_rates[i]) + { + if(baudrate - default_rates[i - 1] < default_rates[i] - baudrate) i--; + break; + } + } + + return default_rates[i]; +} diff --git a/cores/esp8266/uart.h b/cores/esp8266/uart.h index 127c5d0ebb..9b050645e7 100644 --- a/cores/esp8266/uart.h +++ b/cores/esp8266/uart.h @@ -141,6 +141,8 @@ bool uart_has_overrun (uart_t* uart); // returns then clear overrun flag void uart_set_debug(int uart_nr); int uart_get_debug(); +int uart_detect_baudrate(int uart_nr); + #if defined (__cplusplus) } // extern "C" From 8dd845eca53b93836f2afd925d7c54d34aba791e Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Mon, 30 Jul 2018 17:04:57 +0200 Subject: [PATCH 2/8] Added uart_start_detect_baudrate, detectBaudrate() wrappers for HardwareSerial and an example usage SerialDetectBaudrate.ino --- cores/esp8266/HardwareSerial.cpp | 22 +++++++++++++ cores/esp8266/HardwareSerial.h | 6 ++++ cores/esp8266/uart.c | 10 ++++-- cores/esp8266/uart.h | 1 + .../SerialDetectBaudrate.ino | 32 +++++++++++++++++++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 416aa73c43..0a4d626ca4 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -108,6 +108,28 @@ void HardwareSerial::flush() delayMicroseconds(11000000 / uart_get_baudrate(_uart) + 1); } +void HardwareSerial::startDetectBaudrate() +{ + uart_start_detect_baudrate(_uart_nr); +} + +unsigned long HardwareSerial::detectBaudrate() +{ + return uart_detect_baudrate(_uart_nr); +} + +unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis) +{ + time_t startMillis = millis(); + unsigned long detectedBaudrate; + while(millis() - startMillis < timeoutMillis) { + if(detectedBaudrate = detectBaudrate()) break; + yield(); + delay(100); + } + return detectedBaudrate; +} + #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) HardwareSerial Serial(UART0); #endif diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h index 0333d4ca87..71d1f1f934 100644 --- a/cores/esp8266/HardwareSerial.h +++ b/cores/esp8266/HardwareSerial.h @@ -184,6 +184,12 @@ class HardwareSerial: public Stream return uart_has_overrun(_uart); } + void startDetectBaudrate(); + + unsigned long detectBaudrate(); + + unsigned long detectBaudrate(time_t timeoutMillis); + protected: int _uart_nr; uart_t* _uart = nullptr; diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c index 2c9f56bcb9..8eecaa9235 100644 --- a/cores/esp8266/uart.c +++ b/cores/esp8266/uart.c @@ -744,6 +744,13 @@ uart_get_debug() /* To start detection of baud rate with the UART the UART_AUTOBAUD_EN bit needs to be cleared and set. The ROM function uart_baudrate_detect() does this only once, so on a next call the UartDev.rcv_state is not equal to BAUD_RATE_DET. Instead of poking around in the UartDev struct with unknown effect, the UART_AUTOBAUD_EN bit is directly triggered by the function uart_detect_baudrate(). */ +void +uart_start_detect_baudrate(int uart_nr) +{ + USA(uart_nr) &= ~(UART_GLITCH_FILT << UART_GLITCH_FILT_S | UART_AUTOBAUD_EN); + USA(uart_nr) = 0x08 << UART_GLITCH_FILT_S | UART_AUTOBAUD_EN; +} + int uart_detect_baudrate(int uart_nr) { @@ -751,8 +758,7 @@ uart_detect_baudrate(int uart_nr) if(doTrigger) { - USA(uart_nr) &= ~(UART_GLITCH_FILT << UART_GLITCH_FILT_S | UART_AUTOBAUD_EN); - USA(uart_nr) = 0x08 << UART_GLITCH_FILT_S | UART_AUTOBAUD_EN; + uart_start_detect_baudrate(uart_nr); doTrigger = false; } diff --git a/cores/esp8266/uart.h b/cores/esp8266/uart.h index 9b050645e7..f430d88e1d 100644 --- a/cores/esp8266/uart.h +++ b/cores/esp8266/uart.h @@ -141,6 +141,7 @@ bool uart_has_overrun (uart_t* uart); // returns then clear overrun flag void uart_set_debug(int uart_nr); int uart_get_debug(); +void uart_start_detect_baudrate(int uart_nr); int uart_detect_baudrate(int uart_nr); diff --git a/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino b/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino new file mode 100644 index 0000000000..e75c0a24fd --- /dev/null +++ b/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino @@ -0,0 +1,32 @@ +#define TIMEOUT (10000UL) // Maximum time to wait for serial activity to start + +void setup() { + // put your setup code here, to run once: + + Serial.begin(115200); + + // Serial.detectBaudrate() may also be called before Serial.begin() + // There must be activity on the serial port for the baudrate to be detected + unsigned long detectedBaudrate = Serial.detectBaudrate(TIMEOUT); + + if(detectedBaudrate) { + Serial.printf("\nDetected baudrate is %d, switching to that baudrate now...\n", detectedBaudrate); + + // Wait for printf to finish + while(Serial.availableForWrite() != UART_TX_FIFO_SIZE) yield(); + + // Clear Tx buffer to avoid extra characters being printed + Serial.flush(); + + // After this, any writing to Serial will print gibberish on the serial monitor if the baudrate doesn't match + Serial.begin(detectedBaudrate); + } else { + Serial.println("\nNothing detected"); + } +} + +void loop() { + // put your main code here, to run repeatedly: + +} + From 27574a4e2deb99f714ea479a45d70b643b9dd399 Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Mon, 30 Jul 2018 17:29:41 +0200 Subject: [PATCH 3/8] Some layout changes to pass Travis tests --- cores/esp8266/HardwareSerial.cpp | 4 ++-- cores/esp8266/uart.c | 12 ++++++------ .../SerialDetectBaudrate/SerialDetectBaudrate.ino | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 0a4d626ca4..727a16d1cf 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -122,8 +122,8 @@ unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis) { time_t startMillis = millis(); unsigned long detectedBaudrate; - while(millis() - startMillis < timeoutMillis) { - if(detectedBaudrate = detectBaudrate()) break; + while ((time_t) millis() - startMillis < timeoutMillis) { + if ((detectedBaudrate = detectBaudrate())) break; yield(); delay(100); } diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c index 8eecaa9235..6be7410c8e 100644 --- a/cores/esp8266/uart.c +++ b/cores/esp8266/uart.c @@ -756,14 +756,14 @@ uart_detect_baudrate(int uart_nr) { static bool doTrigger = true; - if(doTrigger) + if (doTrigger) { uart_start_detect_baudrate(uart_nr); doTrigger = false; } int32_t divisor = uart_baudrate_detect(uart_nr, 1); - if(!divisor) return 0; + if (!divisor) return 0; doTrigger = true; // Initialize for a next round int32_t baudrate = UART_CLK_FREQ / divisor; @@ -771,14 +771,14 @@ uart_detect_baudrate(int uart_nr) static const int default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400}; size_t i; - for(i = 1; i < sizeof(default_rates) / sizeof(default_rates[0]) - 1; i++) // find the nearest real baudrate + for (i = 1; i < sizeof(default_rates) / sizeof(default_rates[0]) - 1; i++) // find the nearest real baudrate { - if(baudrate <= default_rates[i]) + if (baudrate <= default_rates[i]) { - if(baudrate - default_rates[i - 1] < default_rates[i] - baudrate) i--; + if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) i--; break; } } - return default_rates[i]; + return default_rates[i]; } diff --git a/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino b/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino index e75c0a24fd..08be24b634 100644 --- a/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino +++ b/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino @@ -9,11 +9,11 @@ void setup() { // There must be activity on the serial port for the baudrate to be detected unsigned long detectedBaudrate = Serial.detectBaudrate(TIMEOUT); - if(detectedBaudrate) { + if (detectedBaudrate) { Serial.printf("\nDetected baudrate is %d, switching to that baudrate now...\n", detectedBaudrate); // Wait for printf to finish - while(Serial.availableForWrite() != UART_TX_FIFO_SIZE) yield(); + while (Serial.availableForWrite() != UART_TX_FIFO_SIZE) yield(); // Clear Tx buffer to avoid extra characters being printed Serial.flush(); From 223388c402905b1d7549d01c511a1ffecab7e92e Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Mon, 30 Jul 2018 19:06:16 +0200 Subject: [PATCH 4/8] Some more nitty-gritty layout changes to pass Travis tests --- .../examples/SerialDetectBaudrate/SerialDetectBaudrate.ino | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino b/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino index 08be24b634..70d77e1fd3 100644 --- a/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino +++ b/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino @@ -10,10 +10,12 @@ void setup() { unsigned long detectedBaudrate = Serial.detectBaudrate(TIMEOUT); if (detectedBaudrate) { - Serial.printf("\nDetected baudrate is %d, switching to that baudrate now...\n", detectedBaudrate); + Serial.printf("\nDetected baudrate is %lu, switching to that baudrate now...\n", detectedBaudrate); // Wait for printf to finish - while (Serial.availableForWrite() != UART_TX_FIFO_SIZE) yield(); + while (Serial.availableForWrite() != UART_TX_FIFO_SIZE) { + yield(); + } // Clear Tx buffer to avoid extra characters being printed Serial.flush(); From d30d9e8785e97ed98927a21cd157cef4ef69a820 Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Mon, 30 Jul 2018 19:18:58 +0200 Subject: [PATCH 5/8] Some even more nitty-gritty layout changes to pass Travis tests --- .../examples/SerialDetectBaudrate/SerialDetectBaudrate.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino b/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino index 70d77e1fd3..61967c691f 100644 --- a/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino +++ b/libraries/esp8266/examples/SerialDetectBaudrate/SerialDetectBaudrate.ino @@ -14,7 +14,7 @@ void setup() { // Wait for printf to finish while (Serial.availableForWrite() != UART_TX_FIFO_SIZE) { - yield(); + yield(); } // Clear Tx buffer to avoid extra characters being printed From 8dc44aa3eeb68a7fb11d950f917ce55529665875 Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Wed, 1 Aug 2018 15:54:40 +0200 Subject: [PATCH 6/8] renamed one function to testBaudrate() and updated doc/reference.rst --- cores/esp8266/HardwareSerial.cpp | 4 ++-- cores/esp8266/HardwareSerial.h | 2 +- doc/reference.rst | 10 ++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 727a16d1cf..825d85ab6e 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -113,7 +113,7 @@ void HardwareSerial::startDetectBaudrate() uart_start_detect_baudrate(_uart_nr); } -unsigned long HardwareSerial::detectBaudrate() +unsigned long HardwareSerial::testBaudrate() { return uart_detect_baudrate(_uart_nr); } @@ -123,7 +123,7 @@ unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis) time_t startMillis = millis(); unsigned long detectedBaudrate; while ((time_t) millis() - startMillis < timeoutMillis) { - if ((detectedBaudrate = detectBaudrate())) break; + if ((detectedBaudrate = testBaudrate())) break; yield(); delay(100); } diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h index 71d1f1f934..cac9d35509 100644 --- a/cores/esp8266/HardwareSerial.h +++ b/cores/esp8266/HardwareSerial.h @@ -186,7 +186,7 @@ class HardwareSerial: public Stream void startDetectBaudrate(); - unsigned long detectBaudrate(); + unsigned long testBaudrate(); unsigned long detectBaudrate(time_t timeoutMillis); diff --git a/doc/reference.rst b/doc/reference.rst index 053d75d776..e09d945591 100644 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -155,6 +155,16 @@ current speed. For example | Note that this implementation is **only for ESP8266 based boards**, and will not works with other Arduino boards. +To detect an unknown baudrate of data coming into Serial use ``Serial.detectBaudrate(time_t timeoutMillis)``. This method tries to detect the baudrate for a maximum timeoutMillis ms. It returns zero if no baudrate was detected, or the detected baudrate otherwise. The ``detectBaudrate()`` function may be called before ``Serial.begin()`` is called, because it does not need the receive buffer nor the SerialConfig parameters. + +The uart can not detect other parameters like number of start- or stopbits, number of data bits or parity. + +The detection itself does not change the baudrate, after detection it should be set as usual using ``Serial.begin(detectedBaudrate)``. + +Detection is very fast, it takes only a few incoming bytes. + +SerialDetectBaudrate.ino is a full example of usage. + Progmem ------- From 33d58bed8d94f97533d8572356821b91c95cf086 Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Wed, 1 Aug 2018 15:58:30 +0200 Subject: [PATCH 7/8] Minor updates to doc/reference.rst --- doc/reference.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/reference.rst b/doc/reference.rst index e09d945591..fbff990f93 100644 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -155,7 +155,8 @@ current speed. For example | Note that this implementation is **only for ESP8266 based boards**, and will not works with other Arduino boards. -To detect an unknown baudrate of data coming into Serial use ``Serial.detectBaudrate(time_t timeoutMillis)``. This method tries to detect the baudrate for a maximum timeoutMillis ms. It returns zero if no baudrate was detected, or the detected baudrate otherwise. The ``detectBaudrate()`` function may be called before ``Serial.begin()`` is called, because it does not need the receive buffer nor the SerialConfig parameters. + +To detect an unknown baudrate of data coming into Serial use ``Serial.detectBaudrate(time_t timeoutMillis)``. This method tries to detect the baudrate for a maximum of timeoutMillis ms. It returns zero if no baudrate was detected, or the detected baudrate otherwise. The ``detectBaudrate()`` function may be called before ``Serial.begin()`` is called, because it does not need the receive buffer nor the SerialConfig parameters. The uart can not detect other parameters like number of start- or stopbits, number of data bits or parity. From 2ac82fd98b1f170cf88bc0e7dab3a4437288b1d1 Mon Sep 17 00:00:00 2001 From: Jeroen88 Date: Wed, 1 Aug 2018 18:39:39 +0200 Subject: [PATCH 8/8] New lines added --- cores/esp8266/HardwareSerial.cpp | 4 +++- cores/esp8266/uart.c | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 825d85ab6e..ba3d622bb9 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -123,7 +123,9 @@ unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis) time_t startMillis = millis(); unsigned long detectedBaudrate; while ((time_t) millis() - startMillis < timeoutMillis) { - if ((detectedBaudrate = testBaudrate())) break; + if ((detectedBaudrate = testBaudrate())) { + break; + } yield(); delay(100); } diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c index 6be7410c8e..02960f4c90 100644 --- a/cores/esp8266/uart.c +++ b/cores/esp8266/uart.c @@ -763,7 +763,9 @@ uart_detect_baudrate(int uart_nr) } int32_t divisor = uart_baudrate_detect(uart_nr, 1); - if (!divisor) return 0; + if (!divisor) { + return 0; + } doTrigger = true; // Initialize for a next round int32_t baudrate = UART_CLK_FREQ / divisor; @@ -775,7 +777,9 @@ uart_detect_baudrate(int uart_nr) { if (baudrate <= default_rates[i]) { - if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) i--; + if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) { + i--; + } break; } }