mirror of
https://github.com/esphome/esphome.git
synced 2026-03-04 11:48:21 -07:00
[logger] Optimize ESP8266 UART write path with direct FIFO register access
This commit is contained in:
@@ -2,10 +2,31 @@
|
||||
#include "logger.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
// Direct UART register access for optimized write path
|
||||
// Arduino's Serial.write() has significant overhead:
|
||||
// - pgm_read_byte() for every character (unnecessary for RAM buffers)
|
||||
// - optimistic_yield() after every character (massive scheduler overhead)
|
||||
// - Per-character FIFO checks (could batch)
|
||||
// Direct register writes with batching are 10-50x faster for CPU-side work.
|
||||
#include <esp8266_peri.h> // USF, USS, USTXC register macros
|
||||
|
||||
namespace esphome::logger {
|
||||
|
||||
static const char *const TAG = "logger";
|
||||
|
||||
// UART TX FIFO size is 128 bytes, use 0x7F as threshold
|
||||
static constexpr uint8_t UART_TX_FIFO_THRESHOLD = 0x7F;
|
||||
|
||||
// Yield timeout in microseconds - matches Arduino's uart_write behavior
|
||||
static constexpr uint32_t YIELD_TIMEOUT_US = 10000UL;
|
||||
|
||||
// Determine UART number at compile time
|
||||
#if defined(USE_ESP8266_LOGGER_SERIAL)
|
||||
static const uint8_t LOGGER_UART_NUM = 0;
|
||||
#elif defined(USE_ESP8266_LOGGER_SERIAL1)
|
||||
static const uint8_t LOGGER_UART_NUM = 1;
|
||||
#endif
|
||||
|
||||
void Logger::pre_setup() {
|
||||
#if defined(USE_ESP8266_LOGGER_SERIAL)
|
||||
this->hw_serial_ = &Serial;
|
||||
@@ -29,8 +50,30 @@ void Logger::pre_setup() {
|
||||
}
|
||||
|
||||
void HOT Logger::write_msg_(const char *msg, size_t len) {
|
||||
// Single write with newline already in buffer (added by caller)
|
||||
this->hw_serial_->write(msg, len);
|
||||
#if defined(USE_ESP8266_LOGGER_SERIAL) || defined(USE_ESP8266_LOGGER_SERIAL1)
|
||||
// Direct FIFO writes with batching - much faster than Arduino's per-character approach
|
||||
// Arduino's uart_write() calls optimistic_yield() after EVERY character,
|
||||
// but we can burst up to 127 bytes at once and only yield when FIFO is actually full.
|
||||
while (len > 0) {
|
||||
// Check current FIFO level (USTXC field at bits 16-23)
|
||||
uint8_t fifo_cnt = (USS(LOGGER_UART_NUM) >> USTXC) & 0xFF;
|
||||
|
||||
if (fifo_cnt >= UART_TX_FIFO_THRESHOLD) {
|
||||
// FIFO full - yield once and retry
|
||||
optimistic_yield(YIELD_TIMEOUT_US);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Burst write to FIFO - no function calls, no PROGMEM overhead
|
||||
size_t fifo_free = UART_TX_FIFO_THRESHOLD - fifo_cnt;
|
||||
size_t to_write = len < fifo_free ? len : fifo_free;
|
||||
len -= to_write;
|
||||
|
||||
while (to_write--) {
|
||||
USF(LOGGER_UART_NUM) = *msg++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const LogString *Logger::get_uart_selection_() {
|
||||
|
||||
Reference in New Issue
Block a user