Skip to content

Commit e4d9c27

Browse files
Jeroen88devyte
Jeroen88
authored andcommitted
Function added to detect baudrate (#4978)
* Function added to detect baudrate * Added uart_start_detect_baudrate, detectBaudrate() wrappers for HardwareSerial and an example usage SerialDetectBaudrate.ino * Some layout changes to pass Travis tests * Some more nitty-gritty layout changes to pass Travis tests * Some even more nitty-gritty layout changes to pass Travis tests * renamed one function to testBaudrate() and updated doc/reference.rst * Minor updates to doc/reference.rst * New lines added
1 parent 3ab38d6 commit e4d9c27

File tree

6 files changed

+125
-0
lines changed

6 files changed

+125
-0
lines changed

cores/esp8266/HardwareSerial.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,30 @@ void HardwareSerial::flush()
108108
delayMicroseconds(11000000 / uart_get_baudrate(_uart) + 1);
109109
}
110110

111+
void HardwareSerial::startDetectBaudrate()
112+
{
113+
uart_start_detect_baudrate(_uart_nr);
114+
}
115+
116+
unsigned long HardwareSerial::testBaudrate()
117+
{
118+
return uart_detect_baudrate(_uart_nr);
119+
}
120+
121+
unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis)
122+
{
123+
time_t startMillis = millis();
124+
unsigned long detectedBaudrate;
125+
while ((time_t) millis() - startMillis < timeoutMillis) {
126+
if ((detectedBaudrate = testBaudrate())) {
127+
break;
128+
}
129+
yield();
130+
delay(100);
131+
}
132+
return detectedBaudrate;
133+
}
134+
111135
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
112136
HardwareSerial Serial(UART0);
113137
#endif

cores/esp8266/HardwareSerial.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ class HardwareSerial: public Stream
184184
return uart_has_overrun(_uart);
185185
}
186186

187+
void startDetectBaudrate();
188+
189+
unsigned long testBaudrate();
190+
191+
unsigned long detectBaudrate(time_t timeoutMillis);
192+
187193
protected:
188194
int _uart_nr;
189195
uart_t* _uart = nullptr;

cores/esp8266/uart.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "uart.h"
4545
#include "esp8266_peri.h"
4646
#include "user_interface.h"
47+
#include "uart_register.h"
4748

4849
const char overrun_str [] ICACHE_RODATA_ATTR STORE_ATTR = "uart input full!\r\n";
4950
static int s_uart_debug_nr = UART0;
@@ -739,3 +740,49 @@ uart_get_debug()
739740
{
740741
return s_uart_debug_nr;
741742
}
743+
744+
/*
745+
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().
746+
*/
747+
void
748+
uart_start_detect_baudrate(int uart_nr)
749+
{
750+
USA(uart_nr) &= ~(UART_GLITCH_FILT << UART_GLITCH_FILT_S | UART_AUTOBAUD_EN);
751+
USA(uart_nr) = 0x08 << UART_GLITCH_FILT_S | UART_AUTOBAUD_EN;
752+
}
753+
754+
int
755+
uart_detect_baudrate(int uart_nr)
756+
{
757+
static bool doTrigger = true;
758+
759+
if (doTrigger)
760+
{
761+
uart_start_detect_baudrate(uart_nr);
762+
doTrigger = false;
763+
}
764+
765+
int32_t divisor = uart_baudrate_detect(uart_nr, 1);
766+
if (!divisor) {
767+
return 0;
768+
}
769+
770+
doTrigger = true; // Initialize for a next round
771+
int32_t baudrate = UART_CLK_FREQ / divisor;
772+
773+
static const int default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};
774+
775+
size_t i;
776+
for (i = 1; i < sizeof(default_rates) / sizeof(default_rates[0]) - 1; i++) // find the nearest real baudrate
777+
{
778+
if (baudrate <= default_rates[i])
779+
{
780+
if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) {
781+
i--;
782+
}
783+
break;
784+
}
785+
}
786+
787+
return default_rates[i];
788+
}

cores/esp8266/uart.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ bool uart_has_overrun (uart_t* uart); // returns then clear overrun flag
141141
void uart_set_debug(int uart_nr);
142142
int uart_get_debug();
143143

144+
void uart_start_detect_baudrate(int uart_nr);
145+
int uart_detect_baudrate(int uart_nr);
146+
144147

145148
#if defined (__cplusplus)
146149
} // extern "C"

doc/reference.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,17 @@ current speed. For example
155155
| Note that this implementation is **only for ESP8266 based boards**,
156156
and will not works with other Arduino boards.
157157
158+
159+
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.
160+
161+
The uart can not detect other parameters like number of start- or stopbits, number of data bits or parity.
162+
163+
The detection itself does not change the baudrate, after detection it should be set as usual using ``Serial.begin(detectedBaudrate)``.
164+
165+
Detection is very fast, it takes only a few incoming bytes.
166+
167+
SerialDetectBaudrate.ino is a full example of usage.
168+
158169
Progmem
159170
-------
160171

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#define TIMEOUT (10000UL) // Maximum time to wait for serial activity to start
2+
3+
void setup() {
4+
// put your setup code here, to run once:
5+
6+
Serial.begin(115200);
7+
8+
// Serial.detectBaudrate() may also be called before Serial.begin()
9+
// There must be activity on the serial port for the baudrate to be detected
10+
unsigned long detectedBaudrate = Serial.detectBaudrate(TIMEOUT);
11+
12+
if (detectedBaudrate) {
13+
Serial.printf("\nDetected baudrate is %lu, switching to that baudrate now...\n", detectedBaudrate);
14+
15+
// Wait for printf to finish
16+
while (Serial.availableForWrite() != UART_TX_FIFO_SIZE) {
17+
yield();
18+
}
19+
20+
// Clear Tx buffer to avoid extra characters being printed
21+
Serial.flush();
22+
23+
// After this, any writing to Serial will print gibberish on the serial monitor if the baudrate doesn't match
24+
Serial.begin(detectedBaudrate);
25+
} else {
26+
Serial.println("\nNothing detected");
27+
}
28+
}
29+
30+
void loop() {
31+
// put your main code here, to run repeatedly:
32+
33+
}
34+

0 commit comments

Comments
 (0)