mirror of https://github.com/arendst/Tasmota.git
Merge pull request #6373 from s-hadinger/serial_115200
TasmotaSerial: Reduce IRAM usage by 280 bytes and improve reliability at 115200 bauds
This commit is contained in:
commit
a59dea5a74
|
@ -27,6 +27,9 @@ extern "C" {
|
||||||
|
|
||||||
#include <TasmotaSerial.h>
|
#include <TasmotaSerial.h>
|
||||||
|
|
||||||
|
// for STAGE and pre-2.6, we can have a single wrapper using attachInterruptArg()
|
||||||
|
void ICACHE_RAM_ATTR callRxRead(void *self) { ((TasmotaSerial*)self)->rxRead(); };
|
||||||
|
|
||||||
// As the Arduino attachInterrupt has no parameter, lists of objects
|
// As the Arduino attachInterrupt has no parameter, lists of objects
|
||||||
// and callbacks corresponding to each possible GPIO pins have to be defined
|
// and callbacks corresponding to each possible GPIO pins have to be defined
|
||||||
TasmotaSerial *tms_obj_list[16];
|
TasmotaSerial *tms_obj_list[16];
|
||||||
|
@ -103,9 +106,14 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
|
||||||
if (m_buffer == NULL) return;
|
if (m_buffer == NULL) return;
|
||||||
// Use getCycleCount() loop to get as exact timing as possible
|
// Use getCycleCount() loop to get as exact timing as possible
|
||||||
m_bit_time = ESP.getCpuFreqMHz() * 1000000 / TM_SERIAL_BAUDRATE;
|
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);
|
pinMode(m_rx_pin, INPUT);
|
||||||
tms_obj_list[m_rx_pin] = this;
|
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)
|
||||||
attachInterrupt(m_rx_pin, ISRList[m_rx_pin], (m_nwmode) ? CHANGE : FALLING);
|
attachInterrupt(m_rx_pin, ISRList[m_rx_pin], (m_nwmode) ? CHANGE : FALLING);
|
||||||
|
#else
|
||||||
|
attachInterruptArg(m_rx_pin, callRxRead, this, (m_nwmode) ? CHANGE : FALLING);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (m_tx_pin > -1) {
|
if (m_tx_pin > -1) {
|
||||||
pinMode(m_tx_pin, OUTPUT);
|
pinMode(m_tx_pin, OUTPUT);
|
||||||
|
@ -148,7 +156,9 @@ bool TasmotaSerial::begin(long speed, int stop_bits) {
|
||||||
} else {
|
} else {
|
||||||
// Use getCycleCount() loop to get as exact timing as possible
|
// Use getCycleCount() loop to get as exact timing as possible
|
||||||
m_bit_time = ESP.getCpuFreqMHz() * 1000000 / speed;
|
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_high_speed = (speed >= 9600);
|
||||||
|
m_very_high_speed = (speed >= 100000);
|
||||||
}
|
}
|
||||||
return m_valid;
|
return m_valid;
|
||||||
}
|
}
|
||||||
|
@ -202,9 +212,12 @@ int TasmotaSerial::available()
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TM_SERIAL_USE_IRAM
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
size_t TasmotaSerial::write(uint8_t b)
|
size_t TasmotaSerial::write(uint8_t b)
|
||||||
|
@ -215,22 +228,23 @@ size_t TasmotaSerial::write(uint8_t b)
|
||||||
if (-1 == m_tx_pin) return 0;
|
if (-1 == m_tx_pin) return 0;
|
||||||
if (m_high_speed) cli(); // Disable interrupts in order to get a clean transmit
|
if (m_high_speed) cli(); // Disable interrupts in order to get a clean transmit
|
||||||
uint32_t wait = m_bit_time;
|
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();
|
uint32_t start = ESP.getCycleCount();
|
||||||
// Start bit;
|
// Start bit;
|
||||||
digitalWrite(m_tx_pin, LOW);
|
digitalWrite(m_tx_pin, LOW);
|
||||||
TM_SERIAL_WAIT;
|
TM_SERIAL_WAIT_SND;
|
||||||
for (uint32_t i = 0; i < 8; i++) {
|
for (uint32_t i = 0; i < 8; i++) {
|
||||||
digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW);
|
digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW);
|
||||||
TM_SERIAL_WAIT;
|
TM_SERIAL_WAIT_SND;
|
||||||
b >>= 1;
|
b >>= 1;
|
||||||
}
|
}
|
||||||
// Stop bit(s)
|
// Stop bit(s)
|
||||||
for (uint32_t i = 0; i < m_stop_bits; i++) {
|
digitalWrite(m_tx_pin, HIGH);
|
||||||
digitalWrite(m_tx_pin, HIGH);
|
// re-enable interrupts during stop bits, it's not an issue if they are longer than expected
|
||||||
TM_SERIAL_WAIT;
|
|
||||||
}
|
|
||||||
if (m_high_speed) sei();
|
if (m_high_speed) sei();
|
||||||
|
for (uint32_t i = 0; i < m_stop_bits; i++) {
|
||||||
|
TM_SERIAL_WAIT_SND;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,27 +257,49 @@ void TasmotaSerial::rxRead()
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
if (!m_nwmode) {
|
if (!m_nwmode) {
|
||||||
|
int32_t loop_read = serial_buffer_size;
|
||||||
// Advance the starting point for the samples but compensate for the
|
// Advance the starting point for the samples but compensate for the
|
||||||
// initial delay which occurs before the interrupt is delivered
|
// 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();
|
uint32_t start = ESP.getCycleCount();
|
||||||
uint8_t rec = 0;
|
while (loop_read-- > 0) { // try to receveive all consecutive bytes in a raw
|
||||||
for (uint32_t i = 0; i < 8; i++) {
|
uint32_t rec = 0;
|
||||||
TM_SERIAL_WAIT;
|
for (uint32_t i = 0; i < 8; i++) {
|
||||||
rec >>= 1;
|
TM_SERIAL_WAIT_RCV;
|
||||||
if (digitalRead(m_rx_pin)) rec |= 0x80;
|
rec >>= 1;
|
||||||
}
|
if (digitalRead(m_rx_pin)) rec |= 0x80;
|
||||||
// Stop bit(s)
|
}
|
||||||
TM_SERIAL_WAIT;
|
// Store the received value in the buffer unless we have an overflow
|
||||||
if (2 == m_stop_bits) {
|
uint32_t next = (m_in_pos+1) % serial_buffer_size;
|
||||||
digitalRead(m_rx_pin);
|
if (next != (int)m_out_pos) {
|
||||||
TM_SERIAL_WAIT;
|
m_buffer[m_in_pos] = rec;
|
||||||
}
|
m_in_pos = next;
|
||||||
// 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) {
|
// Stop bit(s) -- actually we don't need to wait for stop bits
|
||||||
m_buffer[m_in_pos] = rec;
|
// so we free some time for other interrupt handlers to do their work
|
||||||
m_in_pos = next;
|
bool start_of_next_byte = false;
|
||||||
|
for (uint32_t i = 0; i < 14; 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) {
|
||||||
|
loop_read = 0; // exit loop
|
||||||
|
}
|
||||||
|
|
||||||
|
// TM_SERIAL_WAIT_RCV;
|
||||||
|
// if (2 == m_stop_bits) {
|
||||||
|
// digitalRead(m_rx_pin);
|
||||||
|
// TM_SERIAL_WAIT_RCV;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
// Must clear this bit in the interrupt register,
|
// Must clear this bit in the interrupt register,
|
||||||
// it gets set even when interrupts are disabled
|
// it gets set even when interrupts are disabled
|
||||||
|
|
|
@ -53,6 +53,8 @@ class TasmotaSerial : public Stream {
|
||||||
|
|
||||||
void rxRead();
|
void rxRead();
|
||||||
|
|
||||||
|
uint32_t getLoopReadMetric(void) const { return m_bit_follow_metric; }
|
||||||
|
|
||||||
using Print::write;
|
using Print::write;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -67,6 +69,8 @@ class TasmotaSerial : public Stream {
|
||||||
uint32_t ss_bstart;
|
uint32_t ss_bstart;
|
||||||
uint32_t ss_index;
|
uint32_t ss_index;
|
||||||
uint32_t m_bit_time;
|
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_in_pos;
|
||||||
uint32_t m_out_pos;
|
uint32_t m_out_pos;
|
||||||
uint32_t serial_buffer_size;
|
uint32_t serial_buffer_size;
|
||||||
|
@ -74,7 +78,8 @@ class TasmotaSerial : public Stream {
|
||||||
bool m_nwmode;
|
bool m_nwmode;
|
||||||
bool m_hardserial;
|
bool m_hardserial;
|
||||||
bool m_hardswap;
|
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;
|
uint8_t *m_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* 6.6.0.11 20190907
|
* 6.6.0.11 20190907
|
||||||
* Change Settings crc calculation allowing short term backward compatibility
|
* Change Settings crc calculation allowing short term backward compatibility
|
||||||
* Add support for up to 4 INA226 Voltage and Current sensors by Steve Rogers (#6342)
|
* 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
|
||||||
*
|
*
|
||||||
* 6.6.0.10 20190905
|
* 6.6.0.10 20190905
|
||||||
* Redesign Tuya support by Shantur Rathore (#6353)
|
* Redesign Tuya support by Shantur Rathore (#6353)
|
||||||
|
|
Loading…
Reference in New Issue