Skip to content

Function added to detect baudrate #4978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions cores/esp8266/HardwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,30 @@ void HardwareSerial::flush()
delayMicroseconds(11000000 / uart_get_baudrate(_uart) + 1);
}

void HardwareSerial::startDetectBaudrate()
{
uart_start_detect_baudrate(_uart_nr);
}

unsigned long HardwareSerial::testBaudrate()
{
return uart_detect_baudrate(_uart_nr);
}

unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis)
{
time_t startMillis = millis();
unsigned long detectedBaudrate;
while ((time_t) millis() - startMillis < timeoutMillis) {
if ((detectedBaudrate = testBaudrate())) {
break;
}
yield();
delay(100);
}
return detectedBaudrate;
}

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
HardwareSerial Serial(UART0);
#endif
Expand Down
6 changes: 6 additions & 0 deletions cores/esp8266/HardwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ class HardwareSerial: public Stream
return uart_has_overrun(_uart);
}

void startDetectBaudrate();

unsigned long testBaudrate();

unsigned long detectBaudrate(time_t timeoutMillis);

protected:
int _uart_nr;
uart_t* _uart = nullptr;
Expand Down
47 changes: 47 additions & 0 deletions cores/esp8266/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -739,3 +740,49 @@ 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().
*/
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)
{
static bool doTrigger = true;

if (doTrigger)
{
uart_start_detect_baudrate(uart_nr);
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};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all of these rates valid for both 80MHz and 160MHz CPU speed?
Or rather, has the detection process been tested with both CPU speeds and different baudrates?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These baud rates are common rates. Yes it has been tested with both 80MHz and 160 MHz, and with two devices, one at 9600 baud and one at 115200 baud. I did not test changing the crystal frequency, because I do not know the purpose of changing the crystal frequency.


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];
}
3 changes: 3 additions & 0 deletions cores/esp8266/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ 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);


#if defined (__cplusplus)
} // extern "C"
Expand Down
11 changes: 11 additions & 0 deletions doc/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,17 @@ 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 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.

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#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 %lu, 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:

}