From cb54e57d847a71c1d8cac2f61e0404cdbc39a59a Mon Sep 17 00:00:00 2001 From: Bonne Eggleston Date: Sun, 30 Aug 2026 14:43:28 -0700 Subject: [PATCH] [modbus] Yield the whole-millisecond part of the interframe wait (#18898) --- esphome/components/modbus/modbus.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/esphome/components/modbus/modbus.cpp b/esphome/components/modbus/modbus.cpp index f77492f48b..25687ba106 100644 --- a/esphome/components/modbus/modbus.cpp +++ b/esphome/components/modbus/modbus.cpp @@ -777,9 +777,10 @@ void ModbusServerHub::process_modbus_client_frame_(uint8_t address, uint8_t func bool Modbus::send_frame_(const ModbusFrame &frame) { int32_t tx_delay_remaining = this->tx_delay_remaining(); if (tx_delay_remaining > 0) { - // delay() only lands on tick boundaries, so yield with it to get close, then busy-wait the rest. - if (tx_delay_remaining > (int32_t) (2 * US_PER_MS)) { - delay((tx_delay_remaining - US_PER_MS) / US_PER_MS); + // Yield the whole-ms part: delay() never blocks past the request on FreeRTOS, and only slightly + // over elsewhere, which just lengthens the gap. The recompute below makes the remainder exact. + if (tx_delay_remaining >= (int32_t) US_PER_MS) { + delay(tx_delay_remaining / US_PER_MS); tx_delay_remaining = this->tx_delay_remaining(); } if (tx_delay_remaining > 0) @@ -814,6 +815,9 @@ bool Modbus::send_frame_(const ModbusFrame &frame) { } void ModbusClientHub::send_next_frame_() { + if (this->tx_buffer_.empty()) + return; + if (this->tx_blocked()) return;