diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 1871a4b5..0ad44258 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -30,7 +30,7 @@ HardwareSerial Serial2(2); HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {} -void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert) +void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms) { if(0 > _uart_nr || _uart_nr > 2) { log_e("Serial number is invalid, please use 0, 1 or 2"); @@ -51,7 +51,26 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in rxPin = RX2; txPin = TX2; } - _uart = uartBegin(_uart_nr, baud, config, rxPin, txPin, 256, invert); + + _uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert); + + if(!baud) { + time_t startMillis = millis(); + unsigned long detectedBaudRate; + while(millis() - startMillis < timeout_ms && !(detectedBaudRate = uartDetectBaudrate(_uart))) { + yield(); + } + + end(); + + if(detectedBaudRate) { + delay(100); // Give some time... + _uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, 256, invert); + } else { + log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible"); + _uart = NULL; + } + } } void HardwareSerial::end() diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index a5a3f671..8e312c8d 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -22,6 +22,24 @@ Modified 18 December 2014 by Ivan Grokhotkov (esp8266 platform support) Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266) Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266) + Modified 13 October 2018 by Jeroen Döll (add baudrate detection) + Baudrate detection example usage (detection on Serial1): + void setup() { + Serial.begin(115200); + delay(100); + Serial.println(); + + Serial1.begin(0, SERIAL_8N1, -1, -1, true, 11000UL); // Passing 0 for baudrate to detect it, the last parameter is a timeout in ms + + unsigned long detectedBaudRate = Serial1.baudRate(); + if(detectedBaudRate) { + Serial.printf("Detected baudrate is %lu\n", detectedBaudRate); + } else { + Serial.println("No baudrate detected, Serial1 will not work!"); + } + } + + Pay attention: the baudrate returned by baudRate() may be rounded, eg 115200 returns 115201 */ #ifndef HardwareSerial_h @@ -37,7 +55,7 @@ class HardwareSerial: public Stream public: HardwareSerial(int uart_nr); - void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false); + void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL); void end(); int available(void); int availableForWrite(void); diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 08956e18..16854308 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -242,7 +242,7 @@ void uartEnd(uart_t* uart) size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) { if(uart == NULL) { - return; + return 0; } UART_MUTEX_LOCK(); @@ -455,3 +455,65 @@ int log_printf(const char *format, ...) } return len; } + +/* + * if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two. + * This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses. + */ +unsigned long uartBaudrateDetect(uart_t *uart, bool flg) +{ + while(uart->dev->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num) + if(flg) return 0; + ets_delay_us(1000); + } + + UART_MUTEX_LOCK(); + unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12; + UART_MUTEX_UNLOCK(); + + return ret; +} + +/* + * To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is + * detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is + * rounded to the closed real baudrate. +*/ +unsigned long +uartDetectBaudrate(uart_t *uart) +{ + static bool uartStateDetectingBaudrate = false; + + if(!uartStateDetectingBaudrate) { + uart->dev->auto_baud.glitch_filt = 0x08; + uart->dev->auto_baud.en = 0; + uart->dev->auto_baud.en = 1; + uartStateDetectingBaudrate = true; + } + + unsigned long divisor = uartBaudrateDetect(uart, true); + if (!divisor) { + return 0; + } + + uart->dev->auto_baud.en = 0; + uartStateDetectingBaudrate = false; // Initialize for the next round + + unsigned long baudrate = UART_CLK_FREQ / divisor; + + static const unsigned long 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/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h index e3023a1c..3a317324 100644 --- a/cores/esp32/esp32-hal-uart.h +++ b/cores/esp32/esp32-hal-uart.h @@ -72,6 +72,8 @@ size_t uartResizeRxBuffer(uart_t* uart, size_t new_size); void uartSetDebug(uart_t* uart); int uartGetDebug(); +unsigned long uartDetectBaudrate(uart_t *uart); + #ifdef __cplusplus } #endif