From d6c5321a5f73e3c28624c1f877af7be3ff44fd06 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 1 Aug 2020 12:17:31 +0200 Subject: [PATCH] update uarts --- src/uart/emsuart_esp32.cpp | 67 +++++++------------ src/uart/emsuart_esp32.h | 14 ++-- src/uart/emsuart_esp8266.cpp | 124 ++++++++--------------------------- src/uart/emsuart_esp8266.h | 13 ++-- 4 files changed, 68 insertions(+), 150 deletions(-) diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index e699bb59b..db9381136 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -34,8 +34,8 @@ static hw_timer_t * timer = NULL; bool drop_next_rx = true; uint8_t tx_mode_ = 0xFF; uint8_t emsTxBuf[EMS_MAXBUFFERSIZE]; -uint8_t emsTxBufIdx; -uint8_t emsTxBufLen; +uint8_t emsTxBufIdx = 0; +uint8_t emsTxBufLen = 0; uint32_t emsTxWait; /* @@ -88,12 +88,15 @@ void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { portENTER_CRITICAL(&mux); if (emsTxBufIdx < emsTxBufLen) { EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; - timerAlarmWrite(timer, emsTxWait, true); + if (emsTxBufIdx == 1) { + timerAlarmWrite(timer, emsTxWait, true); + } } else if (emsTxBufIdx == emsTxBufLen) { EMS_UART.conf0.txd_inv = 1; - timerAlarmWrite(timer, EMSUART_TX_WAIT_BRK, true); + timerAlarmWrite(timer, EMSUART_TX_BRK_TIMER, true); } else if (emsTxBufIdx == emsTxBufLen + 1) { EMS_UART.conf0.txd_inv = 0; + emsTxBufLen = 0; timerAlarmDisable(timer); } emsTxBufIdx++; @@ -130,7 +133,7 @@ void EMSuart::start(const uint8_t tx_mode) { xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 1, NULL); timer = timerBegin(0, 80, true); // timer prescale to 1 us, countup - timerAttachInterrupt(timer, &emsuart_tx_timer_intr_handler, false); // Timer with level interrupt + timerAttachInterrupt(timer, &emsuart_tx_timer_intr_handler, true); // Timer with edge interrupt restart(); } @@ -140,6 +143,9 @@ void EMSuart::start(const uint8_t tx_mode) { void EMSuart::stop() { EMS_UART.int_ena.val = 0; // disable all intr. EMS_UART.conf0.txd_inv = 0; // stop break + if (emsTxBufLen > 0) { + timerAlarmDisable(timer); + } }; /* @@ -165,44 +171,11 @@ void EMSuart::restart() { } } -/* - * Sends a 11-bit break by inverting the tx-port - */ -void EMSuart::tx_brk() { - EMS_UART.conf0.txd_inv = 1; - delayMicroseconds(EMSUART_TX_WAIT_BRK); - EMS_UART.conf0.txd_inv = 0; -} - /* * Sends a 1-byte poll, ending with a */ void EMSuart::send_poll(const uint8_t data) { - if (tx_mode_ > 5) { // timer controlled modes - emsTxBuf[0] = data; - emsTxBufIdx = 0; - emsTxBufLen = 1; - timerAlarmWrite(timer, emsTxWait, true); // start timer with autoreload - timerAlarmEnable(timer); // first interrupt comes immediately - } else if (tx_mode_ == EMS_TXMODE_DEFAULT) { - volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt; - uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; - EMS_UART.fifo.rw_byte = data; - while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) { - delayMicroseconds(EMSUART_TX_BUSY_WAIT); - } - tx_brk(); - } else if (tx_mode_ == EMS_TXMODE_EMSPLUS) { - EMS_UART.fifo.rw_byte = data; - delayMicroseconds(EMSUART_TX_WAIT_PLUS); - tx_brk(); - } else if (tx_mode_ == EMS_TXMODE_HT3) { - EMS_UART.fifo.rw_byte = data; - delayMicroseconds(EMSUART_TX_WAIT_HT3); - tx_brk(); - } else { - EMS_UART.fifo.rw_byte = data; - } + transmit(&data, 1); } /* @@ -221,7 +194,7 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { } emsTxBufIdx = 0; emsTxBufLen = len; - if (tx_mode_ > 100) { + if (tx_mode_ > 100 && len > 1) { timerAlarmWrite(timer, EMSUART_TX_WAIT_REPLY, true); } else { timerAlarmWrite(timer, emsTxWait, true); // start with autoreload @@ -242,7 +215,9 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { EMS_UART.fifo.rw_byte = buf[i]; delayMicroseconds(EMSUART_TX_WAIT_PLUS); } - tx_brk(); + EMS_UART.conf0.txd_inv = 1; // send + delayMicroseconds(EMSUART_TX_BRK_PLUS); + EMS_UART.conf0.txd_inv = 0; return EMS_TX_STATUS_OK; } @@ -251,11 +226,13 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { EMS_UART.fifo.rw_byte = buf[i]; delayMicroseconds(EMSUART_TX_WAIT_HT3); } - tx_brk(); + EMS_UART.conf0.txd_inv = 1; // send + delayMicroseconds(EMSUART_TX_BRK_HT3); + EMS_UART.conf0.txd_inv = 0; return EMS_TX_STATUS_OK; } - // mode 1 + // mode 1: wait for echo after each byte // flush fifos -- not supported in ESP32 uart #2! // EMS_UART.conf0.rxfifo_rst = 1; // EMS_UART.conf0.txfifo_rst = 1; @@ -267,7 +244,9 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... } } - tx_brk(); + EMS_UART.conf0.txd_inv = 1; + delayMicroseconds(EMSUART_TX_BRK_EMS); + EMS_UART.conf0.txd_inv = 0; return EMS_TX_STATUS_OK; } diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index ab2d1fd45..df29566b4 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -46,20 +46,25 @@ #define EMS_TXMODE_NEW 4 // for michael's testing // LEGACY -#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud -#define EMSUART_TX_WAIT_BRK (EMSUART_TX_BIT_TIME * 10) // 10 bt -#define EMSUART_TX_WAIT_REPLY 100000 // delay 100ms after first byte +#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud + +// Timer controlled modes +#define EMSUART_TX_BRK_TIMER (EMSUART_TX_BIT_TIME * 10 + 28) // 10.25 bit times +#define EMSUART_TX_WAIT_REPLY 100000 // delay 100ms after first byte // EMS 1.0 #define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13 -#define EMSUART_TX_TIMEOUT (32 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // 256 +#define EMSUART_TX_TIMEOUT (20 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) +#define EMSUART_TX_BRK_EMS (EMSUART_TX_BIT_TIME * 10) // HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation. // since we use a faster processor the lag is negligible #define EMSUART_TX_WAIT_HT3 (EMSUART_TX_BIT_TIME * 17) // 1768 +#define EMSUART_TX_BRK_HT3 (EMSUART_TX_BIT_TIME * 11) // EMS+ - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) and delay of another Bytetime. #define EMSUART_TX_WAIT_PLUS (EMSUART_TX_BIT_TIME * 20) // 2080 +#define EMSUART_TX_BRK_PLUS (EMSUART_TX_BIT_TIME * 11) // customize the GPIO pins for RX and TX here @@ -91,7 +96,6 @@ class EMSuart { static void emsuart_recvTask(void * para); static void IRAM_ATTR emsuart_rx_intr_handler(void * para); static void IRAM_ATTR emsuart_tx_timer_intr_handler(); - static void tx_brk(); }; } // namespace emsesp diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index f168d3f13..3816fed86 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -95,10 +95,10 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { timer1_write(emsTxWait); } else if (emsTxBufIdx == emsTxBufLen) { USC0(EMSUART_UART) |= (1 << UCBRK); // set - timer1_write(EMSUART_TX_WAIT_BRK * 5); + timer1_write(EMSUART_TX_BRK_TIMER); } else { USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset - sending_ = false; + sending_ = false; } } @@ -114,11 +114,6 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() { * init UART0 driver */ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { - if (tx_mode_ > 100) { - emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode - 90); - } else { - emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode + 10); // bittimes wait to next bytes - } if (tx_mode_ != 0xFF) { // it's a restart no need to configure uart tx_mode_ = tx_mode; restart(); @@ -133,7 +128,6 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { } pEMSRxBuf = paEMSRxBuf[0]; // reset EMS Rx Buffer - ETS_UART_INTR_DISABLE(); ETS_UART_INTR_ATTACH(nullptr, nullptr); // pin settings @@ -153,22 +147,14 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { // UCFFT = RX FIFO Full Threshold (7 bit) = want this to be 31 for 32 bytes of buffer (default was 127) // see https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf // - // change: we set UCFFT to 1 to get an immediate indicator about incoming traffic. - // Otherwise, we're only noticed by UCTOT or RxBRK! // change: don't care, we do not use these interrupts - USC1(EMSUART_UART) = 0; // reset config first + USC1(EMSUART_UART) = 0; // reset config // USC1(EMSUART_UART) = (0x7F << UCFFT) | (0x01 << UCTOT) | (1 << UCTOE); // enable interupts // set interrupts for triggers USIC(EMSUART_UART) = 0xFFFF; // clear all interupts USIE(EMSUART_UART) = 0; // disable all interrupts - // enable rx break, fifo full and timeout. - // but not frame error UIFR (because they are too frequent) or overflow UIOF because our buffer is only max 32 bytes - // change: we don't care about Rx Timeout - it may lead to wrong readouts - // change:we don't care about Fifo full and read only on break-detect - USIE(EMSUART_UART) = (1 << UIBD) | (0 << UIFF) | (0 << UITO); - // set up interrupt callbacks for Rx system_os_task(emsuart_recvTask, EMSUART_recvTaskPrio, recvTaskQueue, EMSUART_recvTaskQueueLen); @@ -182,10 +168,9 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { drop_next_rx = true; // for sending with large delay in EMS+ mode we use a timer interrupt - timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function - timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // 5 MHz timer - ETS_UART_INTR_ENABLE(); - USIE(EMSUART_UART) = (1 << UIBD); + timer1_attachInterrupt(emsuart_tx_timer_intr_handler); + + restart(); } /* @@ -204,67 +189,25 @@ void ICACHE_FLASH_ATTR EMSuart::stop() { */ void ICACHE_FLASH_ATTR EMSuart::restart() { if (USIR(EMSUART_UART) & ((1 << UIBD))) { - USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt + USIC(EMSUART_UART) = (1 << UIBD); // INT clear the detect interrupt drop_next_rx = true; } + if (tx_mode_ > 100) { + emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode_ - 90); + } else { + emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode_ + 10); // bittimes wait to next bytes + } emsTxBufIdx = 0; emsTxBufLen = 0; timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); - USIE(EMSUART_UART) = (1 << UIBD); -} - -/* - * Send a BRK signal - * Which is a 11-bit set of zero's (11 cycles) - */ -void ICACHE_FLASH_ATTR EMSuart::tx_brk() { - // make sure Tx FIFO is empty - while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) { - } - USC0(EMSUART_UART) |= (1 << UCBRK); // set bit - // also for EMS+ there is no need to wait longer, we are finished and can free the bus. - delayMicroseconds(EMSUART_TX_WAIT_BRK); // 1144 - USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear BRK bit + USIE(EMSUART_UART) = (1 << UIBD); // enable interrupt } /* * Sends a 1-byte poll, ending with a - * It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking */ -void EMSuart::send_poll(uint8_t data) { - // reset tx-brk, just in case it is accidentally set - USC0(EMSUART_UART) &= ~(1 << UCBRK); - sending_ = true; - - if (tx_mode_ >= 5) { // timer controlled modes - emsTxBuf[0] = data; - emsTxBufIdx = 0; - emsTxBufLen = 1; - timer1_write(emsTxWait); - } else if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes - USF(EMSUART_UART) = data; - USC0(EMSUART_UART) |= (1 << UCBRK); - } else if (tx_mode_ == EMS_TXMODE_HT3) { - USF(EMSUART_UART) = data; - delayMicroseconds(EMSUART_TX_WAIT_HT3); - tx_brk(); // send - sending_ = false; - } else if (tx_mode_ == EMS_TXMODE_EMSPLUS) { - USF(EMSUART_UART) = data; - delayMicroseconds(EMSUART_TX_WAIT_PLUS); - tx_brk(); // send - sending_ = false; - } else { - // tx_mode 1 - volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF; - USF(EMSUART_UART) = data; - uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; - while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) && (--timeoutcnt > 0)) { - delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... - } - tx_brk(); // send - sending_ = false; - } +void ICACHE_FLASH_ATTR EMSuart::send_poll(uint8_t data) { + transmit(&data, 1); } /* @@ -276,20 +219,18 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { if (len == 0 || len >= EMS_MAXBUFFERSIZE) { return EMS_TX_STATUS_ERR; // nothing or to much to send } - // reset tx-brk, just in case it is accidentally set - USC0(EMSUART_UART) &= ~(1 << UCBRK); - sending_ = true; // timer controlled modes with extra delay if (tx_mode_ >= 5) { + sending_ = true; for (uint8_t i = 0; i < len; i++) { emsTxBuf[i] = buf[i]; } USF(EMSUART_UART) = buf[0]; // send first byte emsTxBufIdx = 0; emsTxBufLen = len; - if (tx_mode_ > 100) { - timer1_write(EMSUART_TX_WAIT_REPLY); + if (tx_mode_ > 100 && len > 1) { + timer1_write(EMSUART_TX_WAIT_REPLY); // large delay after first byte } else { timer1_write(emsTxWait); } @@ -301,7 +242,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; } - USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end + USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end, clear by interrupt return EMS_TX_STATUS_OK; } @@ -311,8 +252,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { USF(EMSUART_UART) = buf[i]; delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070 } - tx_brk(); // send - sending_ = false; + USC0(EMSUART_UART) |= (1 << UCBRK); // set break + delayMicroseconds(EMSUART_TX_BRK_PLUS); + USC0(EMSUART_UART) &= ~(1 << UCBRK); return EMS_TX_STATUS_OK; } @@ -326,8 +268,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { // wait until bits are sent on wire delayMicroseconds(EMSUART_TX_WAIT_HT3); } - tx_brk(); // send - sending_ = false; + USC0(EMSUART_UART) |= (1 << UCBRK); // set break bit + delayMicroseconds(EMSUART_TX_BRK_HT3); + USC0(EMSUART_UART) &= ~(1 << UCBRK); return EMS_TX_STATUS_OK; } @@ -356,9 +299,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { * */ - // disable rx interrupt // clear Rx status register, resetting the Rx FIFO and flush it - // ETS_UART_INTR_DISABLE(); emsuart_flush_fifos(); // send the bytes along the serial line @@ -371,18 +312,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... } } - - // we got the whole telegram in the Rx buffer - // on Rx-BRK (bus collision), we simply enable Rx and leave it - // otherwise we send the final Tx-BRK - // worst case, we'll see an additional Rx-BRK... - // neither bus collision nor timeout - send terminating BRK signal - if (!(USIS(EMSUART_UART) & (1 << UIBD))) { - // no bus collision - send terminating BRK signal - tx_brk(); - } - // ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving - sending_ = false; + USC0(EMSUART_UART) |= (1 << UCBRK); // snd break + delayMicroseconds(EMSUART_TX_BRK_EMS); + USC0(EMSUART_UART) &= ~(1 << UCBRK); return EMS_TX_STATUS_OK; // send the Tx ok status back } diff --git a/src/uart/emsuart_esp8266.h b/src/uart/emsuart_esp8266.h index 01407e54e..be4d1d9fa 100644 --- a/src/uart/emsuart_esp8266.h +++ b/src/uart/emsuart_esp8266.h @@ -40,22 +40,26 @@ #define EMS_TXMODE_NEW 4 // for michael's testing // LEGACY -#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud -#define EMSUART_TX_WAIT_BRK (EMSUART_TX_BIT_TIME * 10) -#define EMSUART_TX_WAIT_REPLY 500000 // delay 100ms after first byte +#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud + +// TIMER modes +#define EMSUART_TX_BRK_TIMER (EMSUART_TX_BIT_TIME * 52) // > 10 bittimes for timer modes +#define EMSUART_TX_WAIT_REPLY 500000 // delay 100ms after first byte // EMS 1.0 #define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13 -// #define EMSUART_TX_TIMEOUT (22 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // 176 // #define EMSUART_TX_TIMEOUT (32 * 8) // 256 for tx_mode 1 - see https://github.com/proddy/EMS-ESP/issues/398#issuecomment-645886277 #define EMSUART_TX_TIMEOUT (220 * 8) // 1760 as in v1.9 (180 ms) +#define EMSUART_TX_BRK_EMS (EMSUART_TX_BIT_TIME * 10) // HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation. // since we use a faster processor the lag is negligible #define EMSUART_TX_WAIT_HT3 (EMSUART_TX_BIT_TIME * 17) // 1768 +#define EMSUART_TX_BRK_HT3 (EMSUART_TX_BIT_TIME * 11) // EMS+ - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) and delay of another Bytetime. #define EMSUART_TX_WAIT_PLUS (EMSUART_TX_BIT_TIME * 20) // 2080 +#define EMSUART_TX_BRK_PLUS (EMSUART_TX_BIT_TIME * 11) namespace emsesp { @@ -85,7 +89,6 @@ class EMSuart { static void ICACHE_RAM_ATTR emsuart_rx_intr_handler(void * para); static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events); static void ICACHE_FLASH_ATTR emsuart_flush_fifos(); - static void ICACHE_FLASH_ATTR tx_brk(); static void ICACHE_RAM_ATTR emsuart_tx_timer_intr_handler(); static bool sending_; };