Merge pull request #6377 from s-hadinger/serial_115200_2

TasmotaSerial: Reduce IRAM usage by 280 bytes and improve reliability at 115200 bauds (v2)
This commit is contained in:
Theo Arends 2019-09-08 18:52:44 +02:00 committed by GitHub
commit 18b5c2154e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 59 additions and 30 deletions

View File

@ -1,6 +1,6 @@
{
"name": "TasmotaSerial",
"version": "2.3.4",
"version": "2.3.5",
"keywords": [
"serial", "io", "TasmotaSerial"
],

View File

@ -1,5 +1,5 @@
name=TasmotaSerial
version=2.3.4
version=2.3.5
author=Theo Arends
maintainer=Theo Arends <theo@arends.com>
sentence=Implementation of software serial with hardware serial fallback for ESP8266.

View File

@ -106,6 +106,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
if (m_buffer == NULL) return;
// Use getCycleCount() loop to get as exact timing as possible
m_bit_time = ESP.getCpuFreqMHz() * 1000000 / TM_SERIAL_BAUDRATE;
m_bit_start_time = m_bit_time + m_bit_time/3 - 500; // pre-compute first wait
pinMode(m_rx_pin, INPUT);
tms_obj_list[m_rx_pin] = this;
#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) || defined(ARDUINO_ESP8266_RELEASE_2_5_2)
@ -155,7 +156,9 @@ bool TasmotaSerial::begin(long speed, int stop_bits) {
} else {
// Use getCycleCount() loop to get as exact timing as possible
m_bit_time = ESP.getCpuFreqMHz() * 1000000 / speed;
m_bit_start_time = m_bit_time + m_bit_time/3 - (ESP.getCpuFreqMHz() > 120 ? 700 : 500); // pre-compute first wait
m_high_speed = (speed >= 9600);
m_very_high_speed = (speed >= 100000);
}
return m_valid;
}
@ -209,9 +212,12 @@ int TasmotaSerial::available()
}
#ifdef TM_SERIAL_USE_IRAM
#define TM_SERIAL_WAIT { while (ESP.getCycleCount()-start < wait) if (!m_high_speed) optimistic_yield(1); wait += m_bit_time; } // Watchdog timeouts
#define TM_SERIAL_WAIT_SND { while (ESP.getCycleCount() < wait + start) if (!m_high_speed) optimistic_yield(1); wait += m_bit_time; } // Watchdog timeouts
#define TM_SERIAL_WAIT_RCV { while (ESP.getCycleCount() < wait + start); wait += m_bit_time; }
#define TM_SERIAL_WAIT_RCV_LOOP { while (ESP.getCycleCount() < wait + start); }
#else
#define TM_SERIAL_WAIT { while (ESP.getCycleCount()-start < wait); wait += m_bit_time; }
#define TM_SERIAL_WAIT_SND { while (ESP.getCycleCount() < wait + start); wait += m_bit_time; }
#define TM_SERIAL_WAIT_RCV { while (ESP.getCycleCount() < wait + start); wait += m_bit_time; }
#endif
size_t TasmotaSerial::write(uint8_t b)
@ -222,22 +228,23 @@ size_t TasmotaSerial::write(uint8_t b)
if (-1 == m_tx_pin) return 0;
if (m_high_speed) cli(); // Disable interrupts in order to get a clean transmit
uint32_t wait = m_bit_time;
digitalWrite(m_tx_pin, HIGH);
//digitalWrite(m_tx_pin, HIGH); // already in HIGH mode
uint32_t start = ESP.getCycleCount();
// Start bit;
digitalWrite(m_tx_pin, LOW);
TM_SERIAL_WAIT;
TM_SERIAL_WAIT_SND;
for (uint32_t i = 0; i < 8; i++) {
digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW);
TM_SERIAL_WAIT;
TM_SERIAL_WAIT_SND;
b >>= 1;
}
// Stop bit(s)
for (uint32_t i = 0; i < m_stop_bits; i++) {
digitalWrite(m_tx_pin, HIGH);
TM_SERIAL_WAIT;
}
digitalWrite(m_tx_pin, HIGH);
// re-enable interrupts during stop bits, it's not an issue if they are longer than expected
if (m_high_speed) sei();
for (uint32_t i = 0; i < m_stop_bits; i++) {
TM_SERIAL_WAIT_SND;
}
return 1;
}
}
@ -250,27 +257,43 @@ void TasmotaSerial::rxRead()
{
#endif
if (!m_nwmode) {
int32_t loop_read = m_very_high_speed ? serial_buffer_size : 1;
// Advance the starting point for the samples but compensate for the
// initial delay which occurs before the interrupt is delivered
uint32_t wait = m_bit_time + m_bit_time/3 - 500;
uint32_t wait = m_bit_start_time;
uint32_t start = ESP.getCycleCount();
uint8_t rec = 0;
for (uint32_t i = 0; i < 8; i++) {
TM_SERIAL_WAIT;
rec >>= 1;
if (digitalRead(m_rx_pin)) rec |= 0x80;
}
// Stop bit(s)
TM_SERIAL_WAIT;
if (2 == m_stop_bits) {
digitalRead(m_rx_pin);
TM_SERIAL_WAIT;
}
// Store the received value in the buffer unless we have an overflow
uint32_t next = (m_in_pos+1) % serial_buffer_size;
if (next != (int)m_out_pos) {
m_buffer[m_in_pos] = rec;
m_in_pos = next;
while (loop_read-- > 0) { // try to receveive all consecutive bytes in a raw
uint32_t rec = 0;
for (uint32_t i = 0; i < 8; i++) {
TM_SERIAL_WAIT_RCV;
rec >>= 1;
if (digitalRead(m_rx_pin)) rec |= 0x80;
}
// Store the received value in the buffer unless we have an overflow
uint32_t next = (m_in_pos+1) % serial_buffer_size;
if (next != (int)m_out_pos) {
m_buffer[m_in_pos] = rec;
m_in_pos = next;
}
if (loop <= 0) { break; } // exit now if not very high speed or buffer full
bool start_of_next_byte = false;
for (uint32_t i = 0; i < 12; i++) {
TM_SERIAL_WAIT_RCV_LOOP; // wait for 1/4 bits
wait += m_bit_time / 4;
if (!digitalRead(m_rx_pin)) {
// this is the start bit of the next byte
wait += m_bit_time; // we have advanced in the first 1/4 of bit, and already added 1/4 of bit so we're roughly centered. Just skip start bit.
start_of_next_byte = true;
m_bit_follow_metric++;
break; // exit loop
}
}
if (!start_of_next_byte) {
break; // exit now if no sign of next byte
}
}
// Must clear this bit in the interrupt register,
// it gets set even when interrupts are disabled

View File

@ -53,6 +53,8 @@ class TasmotaSerial : public Stream {
void rxRead();
uint32_t getLoopReadMetric(void) const { return m_bit_follow_metric; }
using Print::write;
private:
@ -67,6 +69,8 @@ class TasmotaSerial : public Stream {
uint32_t ss_bstart;
uint32_t ss_index;
uint32_t m_bit_time;
uint32_t m_bit_start_time;
uint32_t m_bit_follow_metric = 0;
uint32_t m_in_pos;
uint32_t m_out_pos;
uint32_t serial_buffer_size;
@ -74,7 +78,8 @@ class TasmotaSerial : public Stream {
bool m_nwmode;
bool m_hardserial;
bool m_hardswap;
bool m_high_speed;
bool m_high_speed = false;
bool m_very_high_speed = false; // above 100000 bauds
uint8_t *m_buffer;
};

View File

@ -2,6 +2,7 @@
* 6.6.0.11 20190907
* Change Settings crc calculation allowing short term backward compatibility
* Add support for up to 4 INA226 Voltage and Current sensors by Steve Rogers (#6342)
* Change Improve reliability of TasmotaSerial at 115200 bauds and reduce IRAM usage for Stage/pre-2.6
* Add support for A4988 stepper-motor-driver-circuit by Tim Leuscher (#6370)
*
* 6.6.0.10 20190905