From 55935b8b92f7b6293867f5293a6b15b5d3501eef Mon Sep 17 00:00:00 2001 From: DashyFox Date: Tue, 30 Jun 2026 12:25:36 +0300 Subject: [PATCH] fix(ir-dma): volatile active + errorCount() observability; live poll() in longData example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - IrDmaTxStm32.h: TxStream::active -> volatile (делится поток<->ISR: busy()/poll()/колбэки/спин applyCarrierMultiply) - IrDmaTxStm32.h: + volatile errors_ и errorCount(), инкремент в dmaErrorCb (наблюдаемость Transfer-Error) - test_examples/longData: dmaBackend.poll() в loop, иначе watchdog завершения DMA мёртв в эталонном примере Co-Authored-By: Claude Opus 4.8 (1M context) --- IrDmaTxStm32.h | 6 +++++- test_examples/longData/longData.ino | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/IrDmaTxStm32.h b/IrDmaTxStm32.h index 56436a0..7fefd2e 100644 --- a/IrDmaTxStm32.h +++ b/IrDmaTxStm32.h @@ -160,6 +160,8 @@ public: void setStallTimeoutMs(uint32_t ms) { if (ms != 0U) stallTimeoutMs_ = ms; } /** Сколько раз watchdog аварийно восстановил залипший поток (наблюдаемость/логи). */ uint32_t recoveryCount() const { return recoveries_; } + /** Сколько раз DMA-передача завершилась по Transfer-Error (наблюдаемость/логи). */ + uint32_t errorCount() const { return errors_; } private: struct TxStream { @@ -191,7 +193,7 @@ private: uint32_t lastTicks = 0; uint32_t lastProgressMs = 0; - bool active = false; + volatile bool active = false; // Fix: делится поток<->ISR (busy()/poll()/колбэки/спин applyCarrierMultiply) — запрет кэширования компилятором void resetWave() { wave.configure(setWord, resetWord, nullptr, 0, 2, 1); @@ -228,6 +230,7 @@ private: // Fix C: разделяемый activeCount_ удалён — он и был источником гонки поток↔ISR. uint32_t stallTimeoutMs_ = 100; // Fix D uint32_t recoveries_ = 0; // Fix D (только контекст потока) + volatile uint32_t errors_ = 0; // Fix #5: счётчик Transfer-Error (пишется в ISR dmaErrorCb, читается из потока) static uint32_t u32ptr(const volatile void* p) { return (uint32_t)(uintptr_t)p; @@ -292,6 +295,7 @@ private: if (s == nullptr || !s->active) return; // симметрично HT/CPLT: одиночный stop, без двойного finish s->onError(); if (s_instance != nullptr) { + s_instance->errors_++; // Fix #5: наблюдаемость аварийных завершений по Transfer-Error s_instance->stopStream(*s); } } diff --git a/test_examples/longData/longData.ino b/test_examples/longData/longData.ino index d958800..9aca9e5 100644 --- a/test_examples/longData/longData.ino +++ b/test_examples/longData/longData.ino @@ -132,6 +132,7 @@ void setup() { void loop() { #if LONGDATA_USE_DMA IR_Encoder::tick(); + dmaBackend.poll(); // Fix D: watchdog завершения DMA-передачи (как в Car/src/IR/IR.cpp) #endif const uint32_t now = millis();