From 815fd4d6618e1b1a6655cffa5ce886ffd810b0f9 Mon Sep 17 00:00:00 2001 From: Zefek Date: Tue, 28 Jul 2026 09:14:19 +0200 Subject: [PATCH 1/3] Schmit hystereze --- src/ESP32/ESP32.ino | 66 +++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/src/ESP32/ESP32.ino b/src/ESP32/ESP32.ino index 3a1bdd2..0c4cc1d 100644 --- a/src/ESP32/ESP32.ino +++ b/src/ESP32/ESP32.ino @@ -12,9 +12,13 @@ #endif #define LSSensorPIN1 32 #define LSSensorPIN2 33 -#define PIN_PULL INPUT -#define PIN_EDGE RISING -#define PULSE_DEBOUNCE_MS 84 +#define SAMPLE_INTERVAL_MS 1 +#define ADC_TH_LOW_MV 1000 +#define ADC_TH_HIGH_MV 1800 +#define PULSE_MIN_INTERVAL_MS 30 +#define SAMPLER_CORE 1 +#define SAMPLER_PRIORITY 2 +#define SAMPLER_STACK 2048 #define PIN_DIAG_INTERVAL_MS 500UL #define PULSE_INTERVAL 60000UL #define DIAG_INTERVAL 300000UL @@ -29,10 +33,13 @@ PubSubClient mqtt(net); volatile uint32_t counter1 = 0; volatile uint32_t counter2 = 0; -volatile uint32_t lastTime1 = 0; -volatile uint32_t lastTime2 = 0; portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; +bool chHigh1 = false; +bool chHigh2 = false; +uint32_t chLastCount1 = 0; +uint32_t chLastCount2 = 0; + char data[32]; unsigned long lastPulseSend = 0; unsigned long lastDiagSend = 0; @@ -63,28 +70,42 @@ uint16_t heapKb() return (uint16_t)(ESP.getFreeHeap() / 1024); } -void IRAM_ATTR WattMeter1Received() +void ProcessSample(int mv, bool* high, uint32_t* lastCount, volatile uint32_t* counter, uint32_t now) { - uint32_t t = millis(); - portENTER_CRITICAL_ISR(&mux); - if(t - lastTime1 > PULSE_DEBOUNCE_MS) + if(*high) { - counter1++; - lastTime1 = t; + if(mv < ADC_TH_LOW_MV) + { + *high = false; + } + } + else if(mv > ADC_TH_HIGH_MV) + { + *high = true; + if(now - *lastCount > PULSE_MIN_INTERVAL_MS) + { + portENTER_CRITICAL(&mux); + (*counter)++; + portEXIT_CRITICAL(&mux); + *lastCount = now; + } } - portEXIT_CRITICAL_ISR(&mux); } -void IRAM_ATTR WattMeter2Received() +void SamplerTask(void* arg) { - uint32_t t = millis(); - portENTER_CRITICAL_ISR(&mux); - if(t - lastTime2 > PULSE_DEBOUNCE_MS) + TickType_t last = xTaskGetTickCount(); + chHigh1 = analogReadMilliVolts(LSSensorPIN1) > ADC_TH_HIGH_MV; + chHigh2 = analogReadMilliVolts(LSSensorPIN2) > ADC_TH_HIGH_MV; + for(;;) { - counter2++; - lastTime2 = t; + uint32_t now = millis(); + int mv1 = analogReadMilliVolts(LSSensorPIN1); + int mv2 = analogReadMilliVolts(LSSensorPIN2); + ProcessSample(mv1, &chHigh1, &chLastCount1, &counter1, now); + ProcessSample(mv2, &chHigh2, &chLastCount2, &counter2, now); + vTaskDelayUntil(&last, pdMS_TO_TICKS(SAMPLE_INTERVAL_MS)); } - portEXIT_CRITICAL_ISR(&mux); } bool SyncTime() @@ -144,16 +165,15 @@ bool Connect() void setup() { currentDiagData.resetReason = (uint8_t)esp_reset_reason(); Serial.begin(115200); - pinMode(LSSensorPIN1, PIN_PULL); - pinMode(LSSensorPIN2, PIN_PULL); + analogReadResolution(12); + analogSetAttenuation(ADC_11db); WiFi.mode(WIFI_STA); WiFi.begin(WifiSSID, WifiPassword); net.setCACert(MQTTCACert); mqtt.setServer(MQTTHost, MQTT_TLS_PORT); mqtt.setBufferSize(256); mqtt.setKeepAlive(60); - attachInterrupt(digitalPinToInterrupt(LSSensorPIN1), WattMeter1Received, PIN_EDGE); - attachInterrupt(digitalPinToInterrupt(LSSensorPIN2), WattMeter2Received, PIN_EDGE); + xTaskCreatePinnedToCore(SamplerTask, "sampler", SAMPLER_STACK, NULL, SAMPLER_PRIORITY, NULL, SAMPLER_CORE); esp_task_wdt_config_t wdtConfig = { .timeout_ms = WDT_TIMEOUT_S * 1000, .idle_core_mask = 0, From a35195e783a6f071adb07313e2d19ae7923be0ee Mon Sep 17 00:00:00 2001 From: Zefek Date: Wed, 29 Jul 2026 10:20:57 +0200 Subject: [PATCH 2/3] Sampler a diagnostika --- src/ESP32/ESP32.ino | 51 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/ESP32/ESP32.ino b/src/ESP32/ESP32.ino index 0c4cc1d..a026907 100644 --- a/src/ESP32/ESP32.ino +++ b/src/ESP32/ESP32.ino @@ -3,6 +3,7 @@ #include #include "time.h" #include "esp_task_wdt.h" +#include "esp_timer.h" #include "config.h" #include "secret.h" #include "ota.h" @@ -12,13 +13,14 @@ #endif #define LSSensorPIN1 32 #define LSSensorPIN2 33 -#define SAMPLE_INTERVAL_MS 1 +#define SAMPLE_INTERVAL_MS 5 #define ADC_TH_LOW_MV 1000 #define ADC_TH_HIGH_MV 1800 #define PULSE_MIN_INTERVAL_MS 30 #define SAMPLER_CORE 1 #define SAMPLER_PRIORITY 2 -#define SAMPLER_STACK 2048 +#define SAMPLER_STACK 4096 +#define SAMPLER_REPORT_ITERS 2000 #define PIN_DIAG_INTERVAL_MS 500UL #define PULSE_INTERVAL 60000UL #define DIAG_INTERVAL 300000UL @@ -40,6 +42,11 @@ bool chHigh2 = false; uint32_t chLastCount1 = 0; uint32_t chLastCount2 = 0; +uint32_t samplerMaxUs = 0; +uint32_t samplerAvgUs = 0; +uint32_t samplerOverruns = 0; +uint16_t samplerStackWords = 0; + char data[32]; unsigned long lastPulseSend = 0; unsigned long lastDiagSend = 0; @@ -58,9 +65,12 @@ struct DiagData { int8_t rssi; uint16_t fwVersion; uint16_t otaFailCount; + uint16_t samplerMaxUs; + uint16_t samplerStackWords; + uint16_t samplerOverruns; }; #pragma pack(pop) -static_assert(sizeof(DiagData) == 18, "DiagData wire layout must stay 18 bytes"); +static_assert(sizeof(DiagData) == 24, "DiagData wire layout must stay 24 bytes"); DiagData currentDiagData; uint16_t otaFailures = 0; @@ -97,13 +107,45 @@ void SamplerTask(void* arg) TickType_t last = xTaskGetTickCount(); chHigh1 = analogReadMilliVolts(LSSensorPIN1) > ADC_TH_HIGH_MV; chHigh2 = analogReadMilliVolts(LSSensorPIN2) > ADC_TH_HIGH_MV; + uint32_t iterCount = 0; + uint32_t durSum = 0; + uint32_t durMax = 0; for(;;) { + int64_t start = esp_timer_get_time(); uint32_t now = millis(); int mv1 = analogReadMilliVolts(LSSensorPIN1); int mv2 = analogReadMilliVolts(LSSensorPIN2); ProcessSample(mv1, &chHigh1, &chLastCount1, &counter1, now); ProcessSample(mv2, &chHigh2, &chLastCount2, &counter2, now); + uint32_t dur = (uint32_t)(esp_timer_get_time() - start); + + durSum += dur; + if(dur > durMax) + { + durMax = dur; + } + if(dur > samplerMaxUs) + { + samplerMaxUs = dur; + } + if(dur > SAMPLE_INTERVAL_MS * 1000UL) + { + samplerOverruns++; + Serial.printf("SAMPLER overrun: %lu us\n", (unsigned long)dur); + } + + if(++iterCount >= SAMPLER_REPORT_ITERS) + { + samplerStackWords = uxTaskGetStackHighWaterMark(NULL); + samplerAvgUs = durSum / iterCount; + Serial.printf("SAMPLER avg=%lu us max=%lu us stackHWM=%u words overruns=%lu\n", + (unsigned long)samplerAvgUs, (unsigned long)durMax, samplerStackWords, (unsigned long)samplerOverruns); + iterCount = 0; + durSum = 0; + durMax = 0; + } + vTaskDelayUntil(&last, pdMS_TO_TICKS(SAMPLE_INTERVAL_MS)); } } @@ -226,6 +268,9 @@ void loop() { currentDiagData.rssi = (int8_t)WiFi.RSSI(); currentDiagData.fwVersion = (uint16_t)FW_VERSION; currentDiagData.otaFailCount = otaFailures; + currentDiagData.samplerMaxUs = (samplerMaxUs > 65535UL) ? 65535 : (uint16_t)samplerMaxUs; + currentDiagData.samplerStackWords = samplerStackWords; + currentDiagData.samplerOverruns = (samplerOverruns > 65535UL) ? 65535 : (uint16_t)samplerOverruns; mqtt.publish(LSSENSOR_DIAG, (const uint8_t*)¤tDiagData, sizeof(DiagData), false); currentDiagData.loopMaxMs = 0; } From b3f9f8938c1b50902459a6b2a0fe3b4f9176b33a Mon Sep 17 00:00:00 2001 From: Zefek Date: Wed, 29 Jul 2026 10:41:37 +0200 Subject: [PATCH 3/3] mutex --- src/ESP32/ESP32.ino | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/ESP32/ESP32.ino b/src/ESP32/ESP32.ino index a026907..bda16c6 100644 --- a/src/ESP32/ESP32.ino +++ b/src/ESP32/ESP32.ino @@ -43,7 +43,6 @@ uint32_t chLastCount1 = 0; uint32_t chLastCount2 = 0; uint32_t samplerMaxUs = 0; -uint32_t samplerAvgUs = 0; uint32_t samplerOverruns = 0; uint16_t samplerStackWords = 0; @@ -110,6 +109,8 @@ void SamplerTask(void* arg) uint32_t iterCount = 0; uint32_t durSum = 0; uint32_t durMax = 0; + uint32_t allTimeMaxUs = 0; + uint32_t overrunCount = 0; for(;;) { int64_t start = esp_timer_get_time(); @@ -125,22 +126,27 @@ void SamplerTask(void* arg) { durMax = dur; } - if(dur > samplerMaxUs) + if(dur > allTimeMaxUs) { - samplerMaxUs = dur; + allTimeMaxUs = dur; } if(dur > SAMPLE_INTERVAL_MS * 1000UL) { - samplerOverruns++; + overrunCount++; Serial.printf("SAMPLER overrun: %lu us\n", (unsigned long)dur); } if(++iterCount >= SAMPLER_REPORT_ITERS) { - samplerStackWords = uxTaskGetStackHighWaterMark(NULL); - samplerAvgUs = durSum / iterCount; + uint16_t hwm = (uint16_t)uxTaskGetStackHighWaterMark(NULL); + uint32_t avg = durSum / iterCount; + portENTER_CRITICAL(&mux); + samplerMaxUs = allTimeMaxUs; + samplerStackWords = hwm; + samplerOverruns = overrunCount; + portEXIT_CRITICAL(&mux); Serial.printf("SAMPLER avg=%lu us max=%lu us stackHWM=%u words overruns=%lu\n", - (unsigned long)samplerAvgUs, (unsigned long)durMax, samplerStackWords, (unsigned long)samplerOverruns); + (unsigned long)avg, (unsigned long)durMax, hwm, (unsigned long)overrunCount); iterCount = 0; durSum = 0; durMax = 0; @@ -239,6 +245,9 @@ void loop() { portENTER_CRITICAL(&mux); uint32_t c1 = counter1; uint32_t c2 = counter2; + uint32_t sMaxUs = samplerMaxUs; + uint16_t sStackWords = samplerStackWords; + uint32_t sOverruns = samplerOverruns; portEXIT_CRITICAL(&mux); bool connected = Connect(); @@ -268,9 +277,9 @@ void loop() { currentDiagData.rssi = (int8_t)WiFi.RSSI(); currentDiagData.fwVersion = (uint16_t)FW_VERSION; currentDiagData.otaFailCount = otaFailures; - currentDiagData.samplerMaxUs = (samplerMaxUs > 65535UL) ? 65535 : (uint16_t)samplerMaxUs; - currentDiagData.samplerStackWords = samplerStackWords; - currentDiagData.samplerOverruns = (samplerOverruns > 65535UL) ? 65535 : (uint16_t)samplerOverruns; + currentDiagData.samplerMaxUs = (sMaxUs > 65535UL) ? 65535 : (uint16_t)sMaxUs; + currentDiagData.samplerStackWords = sStackWords; + currentDiagData.samplerOverruns = (sOverruns > 65535UL) ? 65535 : (uint16_t)sOverruns; mqtt.publish(LSSENSOR_DIAG, (const uint8_t*)¤tDiagData, sizeof(DiagData), false); currentDiagData.loopMaxMs = 0; }