diff --git a/Config.h b/Config.h index 54e7d7d..5c6e3ea 100644 --- a/Config.h +++ b/Config.h @@ -92,7 +92,8 @@ typedef struct CONFIG_STRUCT { uint64_t nBLESensorAddr2; uint8_t nBLESensorAddrBytes2[8]; }; - char bExtra[64 - 8 * sizeof(bool) - 4 * sizeof(uint8_t) - 6 * sizeof(float) - sizeof(uint64_t)]; + uint8_t ac1ControlMode, ac2ControlMode; // ZCD_CONTROL || PHASE_CONTROL + char bExtra[64 - 8 * sizeof(bool) - 4 * sizeof(uint8_t) - 6 * sizeof(float) - sizeof(uint64_t) - 2 * sizeof(uint8_t)]; // Block 2 - Sensor and TargetTemperature and Himidity // Offset 64 + 2 diff --git a/ConnectWiFi.cpp b/ConnectWiFi.cpp index 0d1359a..a90da02 100644 --- a/ConnectWiFi.cpp +++ b/ConnectWiFi.cpp @@ -10,7 +10,7 @@ void WiFiEvent(WiFiEvent_t event) { case IP_EVENT_STA_GOT_IP: DPRINTF("WiFi connected, IP: %s\n", WiFi.localIP().toString().c_str()); g_bWiFiHasBeenConnected = true; - ledcWrite(PIN_LED_WIFI, PWM_FULL * 9 / 10); // LED_OFF + ledcWrite(PIN_LED_WIFI, PWM_FULL * 19 / 20); // LED_OFF if (!g_bWiFiSetupExecuted) setupPostWiFi(false); break; case WIFI_EVENT_STA_DISCONNECTED: @@ -74,7 +74,7 @@ void checkWiFi(unsigned long tickMillis) { if (status == WL_DISCONNECTED && g_bWiFiHasBeenConnected) { DPRINTLN("Attempting WiFi reconnection..."); WiFi.reconnect(); - ledcWrite(PIN_LED_WIFI, PWM_FULL * 4 / 5); // Light Blink + ledcWrite(PIN_LED_WIFI, PWM_FULL * 19 / 20); // Light Blink lastAttempt = tickMillis; bConnecting = true; } @@ -93,7 +93,7 @@ void checkWiFi(unsigned long tickMillis) { DPRINTF(" WiFi.Begin(%s,%s) returned %d\n", config.ssid, config.pw, ret); lastAttempt = tickMillis; - ledcWrite(PIN_LED_WIFI, PWM_FULL * 4 / 5); // Light Blink + ledcWrite(PIN_LED_WIFI, PWM_FULL / 10); // Light Blink lastAttempt = tickMillis; bConnecting = true; } diff --git a/HermitCrab.h b/HermitCrab.h index fda4aed..3bc646f 100644 --- a/HermitCrab.h +++ b/HermitCrab.h @@ -20,7 +20,7 @@ #ifndef DEBUG #define DEBUG 1 // Set to 0 to disable debug output #endif -#undef DEBUG +//#undef DEBUG //#define BLE_DEBUG diff --git a/HermitCrab.ino b/HermitCrab.ino index 451bed0..c790f32 100644 --- a/HermitCrab.ino +++ b/HermitCrab.ino @@ -12,6 +12,7 @@ #include "BLEScan.h" #include "hal/timer_ll.h" + #if defined(ESP32) #include "esp_wifi.h" #endif @@ -22,7 +23,8 @@ STATUS_TYPE status; // Time volatile unsigned short g_nYear, g_nMonth, g_nDay, g_nHour, g_nMinute, g_nSecond; volatile uint32_t g_millis = 0l; -extern timg_dev_t *tg1; +extern timg_dev_t *tg0; + // Environment bool bShowSensor = false; @@ -39,6 +41,7 @@ void controlLight(short hour, short min, unsigned long tick); void controlFanDuty(); void controlMotorDuty(); void controlLightDuty(); +void setACLoadStatus(uint32_t tNow); // ================================================================================== @@ -49,32 +52,29 @@ void controlLightDuty(); MY_IRAM_ATTR void loop() { static unsigned long lastTickSecond = 0; static uint8_t lastSecond = -1; - g_millis = (uint32_t)timer_ll_get_counter_value(tg1, 1); + + // Read timer from TG0-Timer0 + tg0->hw_timer[0].update.val = 1; + uint32_t tNow = tg0->hw_timer[0].lo.val; + + g_millis = (uint32_t) (tNow / 10); unsigned long tickMillis = g_millis; unsigned long tickSecond = tickMillis / 1000; // Un-Conditional Loop { - //ESP_LOGI(TAG_MAIN,"Checking WiFi2"); - //checkWiFi(tickMillis); - - //ESP_LOGI(TAG_MAIN,"Host Loop"); - //host.Loop(tickMillis); - - // UI Button Check - ui.loopButton(tickMillis); + ui.loopButton(tickMillis); } // Every Second if (tickSecond != lastTickSecond) { // Time and ZCD - setZCD(); + setACLoadStatus(tNow); setTime(); // Temperature and Humidity readSensors(); - //ble.loop(tickMillis); // Fan, Motor, Light Duties controlFanDuty(); @@ -664,23 +664,3 @@ inline void setTime() { g_nYear = timeinfo.tm_year + 1900; } - -inline void setZCD() { - // ZCD - status.zcdAC = zcdACCount; - zcdACCount = 0; - status.zcdLoad = zcdLoadCount; - zcdLoadCount = 0; - if (status.zcdAC < 118 || status.zcdAC > 122) { - status.nFlags |= FLAG_ZCD_AC; - } - else { - status.nFlags &= ~FLAG_ZCD_AC; - } - if (status.zcdLoad < 118 || status.zcdLoad > 122) { - status.nFlags |= FLAG_ZCD_LOAD; - } - else { - status.nFlags &= ~FLAG_ZCD_LOAD; - } -} \ No newline at end of file diff --git a/LED0.cpp b/LED0.cpp deleted file mode 100644 index 44a568d..0000000 --- a/LED0.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "LED0.h" - -CLED0 led0; - -void CLED0::setup(uint8_t _pin, uint16_t _freq, uint16_t _channel) { - freq = _freq; - channel = _channel; - pin = _pin; - bPWMMode = true; - bAC = false; - bLoad = false; - duty = 0; - - ledcAttachChannel(pin, _freq, PWM_RESOLUTION, channel); - setDuty(duty); -}; - -void CLED0::setFreq(uint16_t _freq) { - if (freq != _freq) { - if (_freq == 0) { - ledcDetach(pin); - pinMode(pin, OUTPUT); - digitalWrite(pin, LED_OFF); - bPWMMode = false; - } - else { - ledcAttachChannel(pin, _freq, PWM_RESOLUTION, channel); - bPWMMode = true; - } - freq = _freq; - } -} - -void CLED0::setDuty() { - uint16_t _duty; - - if (bAC) _duty = LED0_DUTY_AC; - else if (bLoad) _duty = LED0_DUTY_LOAD; - else _duty = duty; - - ledcWrite(PIN_LED_WIFI, PWM_FULL * (100 - _duty) / 100); // Light Blink -} - -void CLED0::setDuty(uint16_t _duty) { - if (duty != _duty) { - if (bPWMMode) - ledcWrite(PIN_LED_WIFI, PWM_FULL * (100 - _duty) / 100); // Light Blink - else - digitalWrite(pin, _duty ? LED_ON : LED_OFF); - duty = _duty; - } -}; diff --git a/LED0.h b/LED0.h deleted file mode 100644 index 1e91455..0000000 --- a/LED0.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __LED0_H -#define __LED0_H - -#ifndef __HERMIT_CRAB_H -#include "HermitCrab.h" -#endif - -#define LED0_DUTY_BOOT 20 -#define LED0_DUTY_CONNECTED 0 -#define LED0_DUTY_CONNECTING 5 -#define LED0_DUTY_SMART_CONFIG 100 -#define LED0_DUTY_CLIENT 1 -#define LED0_DUTY_AC 90 -#define LED0_DUTY_LOAD 80 - -class CLED0 { -public: - void setup(uint8_t _pin, uint16_t _freq, uint16_t _channel); - void loop(); - void setFreq(uint16_t _freq); - void setDuty(uint16_t _duty); - void setDuty(); - inline void setAC() { bAC = true; }; - inline void clearAC() { bAC = false; }; - inline void setLoad() { bLoad = true; }; - inline void clearLoad() { bLoad = false; }; - -private: - uint16_t channel; - uint16_t freq; - uint16_t duty; - uint8_t pin; - bool bPWMMode; - bool bAC, bLoad; -}; - -extern CLED0 led0; -#endif \ No newline at end of file diff --git a/OTA.cpp b/OTA.cpp index 6065aa9..d7c8139 100644 --- a/OTA.cpp +++ b/OTA.cpp @@ -17,7 +17,7 @@ // OTA // // ============================================================== -const char *HC__VERSION = "20260416002"; +const char *HC__VERSION = "2026041814"; #define UPDATE_PORT ((uint16_t) 443) const char *url = "visionsoft.kr"; const char *uri = "/sc/pages/firmware_download.php"; diff --git a/Setup.cpp b/Setup.cpp index 1ad34ad..4f91711 100644 --- a/Setup.cpp +++ b/Setup.cpp @@ -12,7 +12,7 @@ #include "BLEScan.h" #include #include "esp_coexist.h" -#include "hal/timer_ll.h" + #define TAG_SETUP "TAG_SETUP" // Task handle @@ -23,7 +23,6 @@ bool g_bWiFiHasBeenConnected = false; extern STATUS_TYPE status; extern CHistory history; -extern timg_dev_t *tg1; void setupConfig(); void setupStatus(); @@ -37,14 +36,6 @@ void setup_BLE(); void scanI2C(); void setup() { - timer_ll_set_clock_prescale(tg1, 1, 80000); - timer_ll_set_count_direction(tg1, 1, GPTIMER_COUNT_UP); - tg1->hw_timer[1].loadhi.val = 0UL; - tg1->hw_timer[1].loadlo.val = 0UL; - tg1->hw_timer[1].load.val = 1UL; - timer_ll_enable_alarm(tg1, 1, false); // No ISR needed for watchdog - timer_ll_enable_counter(tg1, 1, true); - // put your setup code here, to run once: #ifdef DEBUG Serial.begin(115200); @@ -149,7 +140,7 @@ void setupWiFi() { DPRINTLN(); if (WiFi.status() == WL_CONNECTED) { - ledcWrite(PIN_LED_WIFI, PWM_FULL); // LED_OFF + ledcWrite(PIN_LED_WIFI, PWM_FULL * 9 / 10); // LED_OFF ui.message(0, (char *) "WiFi...OK!"); DPRINTLN("WiFi - Connected at SETUP"); DPRINTF("WiFi - SSID(%s) PW(%s) IP(%s)\n", config.ssid, config.pw, WiFi.localIP().toString().c_str()); @@ -179,8 +170,10 @@ void setupPostWiFi(bool bBoot = false) { DPRINTLN("Setup - TimeManager.begin()"); DPRINTLN("\n===============================\n"); DPRINTLN(" Trying OTA"); - ui.message(2, (char *) "Update check..."); + ui.message(2, (char *) "Update check..."); + ledcWrite(PIN_LED_WIFI, PWM_FULL / 20); checkOTA(true); + ledcWrite(PIN_LED_WIFI, PWM_FULL * 19 / 20); ui.message(2, (char *) "Update OK!"); DPRINTLN(" OTA Process completed!"); DPRINTLN("===============================\n"); @@ -228,7 +221,7 @@ void setupPins() { ledcWrite(PIN_FAN, PWM_OFF); ledcWrite(PIN_LIGHT, PWM_OFF); ledcWrite(PIN_MIST, PWM_OFF); - ledcWrite(PIN_LED_WIFI, (PWM_FULL * 4) / 5); // 80% Initial Blink + ledcWrite(PIN_LED_WIFI, PWM_FULL / 10); // 80% Initial Blink // Heaters (Inverted logic for MOSFET safety) ledcWrite(PIN_LED_HEATER1, PWM_FULL - PWM_OFF); diff --git a/Task0.ino b/Task0.ino index d009d87..900f607 100644 --- a/Task0.ino +++ b/Task0.ino @@ -25,7 +25,7 @@ MY_IRAM_ATTR void core0Task(void *pvParameters) { ESP_LOGI(TAG_TASK0,"Core 0 Task Started"); DPRINTLN("Core 0 Task Started"); wl_status_t lastWiFiStatus = WL_DISCONNECTED; - unsigned long tickMillis = g_millis; + unsigned long tickMillis; unsigned long tickSecond; uint8_t slot; uint8_t lastSlot = 255; @@ -36,7 +36,7 @@ MY_IRAM_ATTR void core0Task(void *pvParameters) { while (true) { esp_task_wdt_reset(); - tickMillis = g_millis; + tickMillis = millis(); tickSecond = tickMillis / 1000; slot = (tickMillis % 1000) / 50; diff --git a/UI.cpp b/UI.cpp index 8f1554e..601e008 100644 --- a/UI.cpp +++ b/UI.cpp @@ -1135,18 +1135,18 @@ void CUI::checkButtonStates(unsigned long currentMillis) { // ISR for the Set button handling ARDUINO_ISR_ATTR void buttonSetISR() { // Record the time of the button interrupt and set a flag - ui.buttonSetChangeTime = g_millis; + ui.buttonSetChangeTime = millis(); ui.bButtonSetChanged = true; // Flag for main loop to process } // ISR for the Up button handling ARDUINO_ISR_ATTR void buttonUpISR() { - ui.buttonUpChangeTime = g_millis; + ui.buttonUpChangeTime = millis(); ui.bButtonUpChanged = true; // Flag for main loop to process } // ISR for the Down button handling ARDUINO_ISR_ATTR void buttonDownISR() { - ui.buttonDownChangeTime = g_millis; + ui.buttonDownChangeTime = millis(); ui.bButtonDownChanged = true; // Flag for main loop to process } \ No newline at end of file diff --git a/WiFiHost.cpp b/WiFiHost.cpp index 9e3382b..8168deb 100644 --- a/WiFiHost.cpp +++ b/WiFiHost.cpp @@ -188,7 +188,7 @@ void CWiFiHost::Loop(unsigned long clock) m_bClientConnected = true; m_bHelloSent = false; m_nMode = MODE_PACKET; - ledcWrite(PIN_LED_WIFI, PWM_FULL - 10); + ledcWrite(PIN_LED_WIFI, PWM_FULL * 9 / 10); } return; } @@ -198,7 +198,7 @@ void CWiFiHost::Loop(unsigned long clock) if (!wifiClient || !wifiClient.connected()) { m_bClientConnected = false; m_nMode = MODE_WAITING; - ledcWrite(PIN_LED_WIFI, PWM_FULL - 2); + ledcWrite(PIN_LED_WIFI, PWM_FULL / 10 ); return; } @@ -397,7 +397,7 @@ void CWiFiHost::ProcessPacket(TCP_PACKET& pkt) { // System case CMD_HEARTBEAT: - m_nLastReceivedTime = g_millis; + m_nLastReceivedTime = millis(); //ESP_LOGI(TAG_WIFI_HOST,"H"); break; case CMD_HELLO: diff --git a/zcd.cpp b/zcd.cpp index a6fe3a8..0889c0d 100644 --- a/zcd.cpp +++ b/zcd.cpp @@ -4,36 +4,39 @@ #include #include #include -#include +// Timer Headers #include "hal/timer_ll.h" #include "hal/timer_types.h" #include "driver/timer.h" // Needed for timer_isr_register +#include "rom/ets_sys.h" + -// Assuming tg0 is defined as: timg_dev_t *tg0 = &TIMG0; timg_dev_t *tg0 = &TIMERG0; timg_dev_t *tg1 = &TIMERG1; #define SET_TIMER_1(duty) do { \ - timer_ll_enable_counter(tg0, 0, false); \ - tg0->hw_timer[0].loadhi.val = 0; \ - tg0->hw_timer[0].loadlo.val = 0; \ - tg0->hw_timer[0].load.val = 1; \ - timer_ll_set_alarm_value(tg0, 0, duty); \ - timer_ll_enable_alarm(tg0, 0, true); \ - timer_ll_enable_counter(tg0, 0, true); \ + timer_ll_enable_counter(tg1, 0, false); \ + tg1->hw_timer[0].loadhi.val = 0; \ + tg1->hw_timer[0].loadlo.val = 0; \ + tg1->hw_timer[0].load.val = 1; \ + timer_ll_set_alarm_value(tg1, 0, duty); \ + timer_ll_enable_alarm(tg1, 0, true); \ + timer_ll_enable_counter(tg1, 0, true); \ } while(0) #define SET_TIMER_2(duty) do { \ - timer_ll_enable_counter(tg0, 1, false); \ - tg0->hw_timer[1].loadhi.val = 0; \ - tg0->hw_timer[1].loadlo.val = 0; \ - tg0->hw_timer[1].load.val = 1; \ - timer_ll_set_alarm_value(tg0, 1, duty); \ - timer_ll_enable_alarm(tg0, 1, true); \ - timer_ll_enable_counter(tg0, 1, true); \ + timer_ll_enable_counter(tg1, 1, false); \ + tg1->hw_timer[1].loadhi.val = 0; \ + tg1->hw_timer[1].loadlo.val = 0; \ + tg1->hw_timer[1].load.val = 1; \ + timer_ll_set_alarm_value(tg1, 1, duty); \ + timer_ll_enable_alarm(tg1, 1, true); \ + timer_ll_enable_counter(tg1, 1, true); \ } while(0) +#define ESP_INTR_FLAG_LEVEL3 (1<<3) +#define ESP_INTR_FLAG_LEVEL1 (1<<1) #define TAG_ZCD "ZCD" // Constants @@ -48,6 +51,7 @@ const uint32_t AC_CYCLE_TIME_CLOCKS = 8333; // Half cycle of 60Hz AC in clock cy const uint32_t EFFECTIVE_HALF_CYCLE = EFFECTIVE_POWER * AC_CYCLE_TIME_CLOCKS; // Effective half cycle in clock cycles const uint32_t LEADING_PULSE_COUNT = EFFECTIVE_HALF_CYCLE * LEADING_TIME_RATIO; // Leading pulse count const uint32_t MAX_PULSE_COUNT = LEADING_PULSE_COUNT + EFFECTIVE_HALF_CYCLE; // Maximum valid pulse count +const uint32_t LEADING_ZCD_COUNT = LEADING_PULSE_COUNT / 2; volatile uint32_t dutyHeater1; // Calculated timerHeater1 count for TRIAC firing @@ -65,18 +69,33 @@ volatile uint8_t fireStatusTimer2 = 0; hw_timer_t *timerHeater1; hw_timer_t *timerHeater2; -const char fireTable[9][8] { {0, 0, 0, 0, 0, 0, 0, 0}, // 0 - 0% - {1, 0, 0, 0, 0, 0, 0, 0}, // 1 - 12.5% - {1, 0, 0, 0, 1, 0, 0, 0}, // 2 - 25% - {1, 0, 0, 1, 0, 0, 1, 0}, // 3 - 37.5% - {1, 0, 1, 0, 1, 0, 1, 0}, // 4 - 50% - {1, 1, 0, 1, 1, 0, 1, 0}, // 5 - 62.5% - {1, 1, 1, 0, 1, 1, 1, 0}, // 6 - 75% - {1, 1, 1, 1, 1, 1, 1, 0}, // 7 - 87.5% - {1, 1, 1, 1, 1, 1, 1, 1}}; // 8 - 100% +const char fireTable[17][16] { + {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}, // 0 0% + {1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}, // 1 6.25% (Dist: 16) + {1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0}, // 2 12.5% (Dist: 8, 8) + {1,0,0,0, 0,1,0,0, 0,0,0,1, 0,0,0,0}, // 3 18.75% (Dist: 5, 6, 5) + {1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0}, // 4 25% (Dist: 4, 4, 4, 4) + {1,0,0,1, 0,0,1,0, 0,1,0,0, 1,0,0,0}, // 5 31.25% (Dist: 3, 3, 3, 3, 4) + {1,0,1,0, 0,1,0,0, 1,0,1,0, 0,1,0,0}, // 6 37.5% (Dist: 2, 3, 3, 2, 3, 3) + {1,0,1,0, 1,0,0,1, 0,1,0,1, 0,1,0,0}, // 7 43.75% (Dist: 2, 2, 3, 2, 2, 2, 3) + {1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0}, // 8 50% (Perfect Toggle) + {0,1,0,1, 0,1,1,0, 1,0,1,0, 1,0,1,1}, // 9 56.25% (Inv 7: spaced 0s) + {0,1,0,1, 1,0,1,1, 0,1,0,1, 1,0,1,1}, // 10 62.5% (Inv 6: spaced 0s) + {0,1,1,0, 1,1,0,1, 1,0,1,1, 0,1,1,1}, // 11 68.75% (Inv 5: spaced 0s) + {0,1,1,1, 0,1,1,1, 0,1,1,1, 0,1,1,1}, // 12 75% (Inv 4: spaced 0s) + {0,1,1,1, 1,0,1,1, 1,1,0,1, 1,1,1,0}, // 13 81.25% (Inv 3: spaced 0s) + {0,1,1,1, 1,1,1,1, 0,1,1,1, 1,1,1,1}, // 14 87.5% (Inv 2: spaced 0s) + {0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1}, // 15 93.75% (Inv 1: spaced 0s) + {1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1} // 16 100% +}; + uint8_t seqStep = 0; -uint8_t dutyAC1 = 0; -uint8_t dutyAC2 = 0; +uint8_t dutyAC1TableIndex = 0; +uint8_t dutyAC2TableIndex = 0; + +// AC Frequency and health status +volatile uint8_t zcdACISRCount = 0; +volatile uint8_t zcdLoadISRCount = 0; void setAC1ControlMode(uint8_t mode) { ac1ControlMode = mode; } void setAC2ControlMode(uint8_t mode) { ac2ControlMode = mode; } @@ -96,7 +115,8 @@ short getHeater2Duty() { // Function to set the duty based on percentage (0 to 10000) ARDUINO_ISR_ATTR void setHeater1Duty(short duty) { if (ac1ControlMode == ZCD_CONTROL) { - dutyAC1 = (uint8_t)((duty + 10000/16)/1250); + if (duty > 10000) duty = 10000; + dutyAC1TableIndex = (uint8_t)((duty + 10000/32)/625); } else { if (duty <= 0) { dutyHeater1 = 0; // If 0% duty, no pulse (turn off TRIAC) @@ -135,102 +155,91 @@ ARDUINO_ISR_ATTR void setHeater2Duty(short duty) { } dutyHeater2 = 0; } else { - if (duty <= 0) { - dutyHeater2 = 0; // If 0% duty, no pulse (turn off TRIAC) - } else if (duty >= 10000) { - // 100% duty corresponds to the leading pulse + full effective half cycle - dutyHeater2 = LEADING_PULSE_COUNT; + if (ac2ControlMode == ZCD_CONTROL) { + if (duty > 10000) duty = 10000; + dutyAC2TableIndex = (uint8_t)((duty + 10000/32)/625); } else { - // Map duty to power ratio (0 to 1) - float powerRatio = (float) duty / 10000.0f; + if (duty <= 0) { + dutyHeater2 = 0; // If 0% duty, no pulse (turn off TRIAC) + } else if (duty >= 10000) { + // 100% duty corresponds to the leading pulse + full effective half cycle + dutyHeater2 = LEADING_PULSE_COUNT; + } else { + // Map duty to power ratio (0 to 1) + float powerRatio = (float) duty / 10000.0f; - // Calculate the angle in radians using the inverse cosine directly - float angleRadians = acosf(1.0f - 2.0f * powerRatio); + // Calculate the angle in radians using the inverse cosine directly + float angleRadians = acosf(1.0f - 2.0f * powerRatio); - // Convert angle to time delay (in clock cycles) - // Normalized angle (0 to PI) maps to half-cycle (0 to EFFECTIVE_HALF_CYCLE) - uint32_t pulseCount = (angleRadians / M_PI) * EFFECTIVE_HALF_CYCLE; + // Convert angle to time delay (in clock cycles) + // Normalized angle (0 to PI) maps to half-cycle (0 to EFFECTIVE_HALF_CYCLE) + uint32_t pulseCount = (angleRadians / M_PI) * EFFECTIVE_HALF_CYCLE; - dutyHeater2 = LEADING_PULSE_COUNT + EFFECTIVE_HALF_CYCLE - pulseCount; + dutyHeater2 = LEADING_PULSE_COUNT + EFFECTIVE_HALF_CYCLE - pulseCount; + } } } uint32_t nDuty = duty * PWM_FULL / 10000; ledcWrite(PIN_LED_HEATER2, PWM_FULL - nDuty); - ESP_LOGD(TAG_ZCD,"Set Duty: %.2f%%, Timer Count: %u clock cycles\n", duty, dutyHeater1); + ESP_LOGD(TAG_ZCD,"Set Duty: %.2f%%, Timer Count: %u clock cycles\n", duty, dutyHeater2); } void ARDUINO_ISR_ATTR onTimer1(void *) { - if (fireStatusTimer1) { - REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER1 - 32))); // Clear (Low) - } else { - REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER1 - 32))); // Set (High) + tg1->int_clr_timers.t0_int_clr = 1; // Clear Interrupt + + if (fireStatusTimer1 == 0) { + // First Trigger: Turn ON + REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER1 - 32))); fireStatusTimer1 = 1; - SET_TIMER_1(8); // 8 us + SET_TIMER_1(8); // Schedule OFF pulse 8us later + } else { + // Second Trigger: Turn OFF + REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER1 - 32))); } } void ARDUINO_ISR_ATTR onTimer2(void *) { - if (fireStatusTimer2) { - REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER2 - 32))); // Clear (Low) - } else { - REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER2 - 32))); // Set (High) + tg1->int_clr_timers.t1_int_clr = 1; + + if (fireStatusTimer2 == 0) { + REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER2 - 32))); fireStatusTimer2 = 1; - SET_TIMER_2(8); // 8 us + SET_TIMER_2(8); + } else { + REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER2 - 32))); } } - // Zero-Cross Detection Interrupt Service Routine -void ARDUINO_ISR_ATTR zcdACISR() { - // 1. Check the dedicated Watchdog Timer (Group 1) - uint32_t elapsed = timer_ll_get_counter_value(tg1, 0); - if (elapsed < 8000) return; // Reject noise based on absolute time since last ZCD - tg1->hw_timer[0].loadhi.val = 0UL; - tg1->hw_timer[0].loadlo.val = 0UL; - tg1->hw_timer[0].load.val = 1UL; - - zcdACCount++; +void ARDUINO_ISR_ATTR zcdACISR(void *) { + // 1. Power side AC ZCD Count + zcdACISRCount++; + fireStatusTimer1 = 0; fireStatusTimer2 = 0; - // Heater 1 + // 3. Heater 1 if (ac1ControlMode == ZCD_CONTROL) { - if (fireTable[dutyAC1][seqStep]) { - onTimer1(NULL); - } - } else { - if (dutyHeater1 >= LEADING_PULSE_COUNT && dutyHeater1 < MAX_PULSE_COUNT) { - // Stop the timer, configure new alarm, then explicitly start - SET_TIMER_1(dutyHeater1); // Set alarm with updated duty - } - else if (dutyHeater1 == MAX_PULSE_COUNT) { - onTimer1(NULL); - } + if (fireTable[dutyAC1TableIndex][seqStep]) SET_TIMER_1(LEADING_ZCD_COUNT); + } else if ( dutyHeater1 >= LEADING_PULSE_COUNT){ + SET_TIMER_1(dutyHeater1); } - // Heater 2 + // 4. Heater 2 if (ac2ControlMode == ZCD_CONTROL) { - if (fireTable[dutyAC2][seqStep]) { - onTimer2(NULL); - } - } - else { - if (dutyHeater2 >= LEADING_PULSE_COUNT && dutyHeater2 < MAX_PULSE_COUNT) { - // Stop the timer, configure new alarm, then explicitly start - SET_TIMER_2(dutyHeater2); // Set alarm with updated duty - } - else if (dutyHeater2 == MAX_PULSE_COUNT) { - onTimer2(NULL); - } + if (fireTable[dutyAC2TableIndex][seqStep]) SET_TIMER_2(LEADING_ZCD_COUNT); + } else if (dutyHeater2 >= LEADING_PULSE_COUNT) { + SET_TIMER_2(dutyHeater2); } - seqStep = ++seqStep & 0x07; + seqStep = ++seqStep & 0x0F; } -void ARDUINO_ISR_ATTR zcdLoadISR() { - ++zcdLoadCount; +void ARDUINO_ISR_ATTR zcdLoadISR(void *) { + // Load side AC ZCD Count + zcdLoadISRCount++; } void setupZCD() { @@ -238,6 +247,8 @@ void setupZCD() { pinMode(PIN_ZCD_LOAD, INPUT); pinMode(PIN_HEATER1, OUTPUT); pinMode(PIN_HEATER2, OUTPUT); + digitalWrite(PIN_HEATER1, HEATER_OFF); + digitalWrite(PIN_HEATER2, HEATER_OFF); dutyHeater1 = 0; // Calculated timerHeater1 count for TRIAC firing dutyHeater2 = 0; // Calculated timerZCD count for TRIAC firing @@ -245,28 +256,94 @@ void setupZCD() { zcdLoadCount = 0; timerHeater1 = NULL; - // --- 1. Basic Hardware Config for TG0 (Heaters) --- - // Timer 0 - timer_ll_set_clock_prescale(tg0, 0, 80); + // Test + config.ac1ControlMode = PHASE_CONTROL; + config.ac2ControlMode = PHASE_CONTROL; + + ac1ControlMode = config.ac1ControlMode; + ac2ControlMode = config.ac2ControlMode; + + // --- 0. Hardware Config for TG0-Timer0 (g_millis) + timer_ll_set_clock_prescale(tg0, 0, 8000); // 10KHz timer_ll_set_count_direction(tg0, 0, GPTIMER_COUNT_UP); - timer_ll_enable_alarm(tg0, 0, true); + tg0->hw_timer[0].loadhi.val = 0UL; + tg0->hw_timer[0].loadlo.val = 0UL; + tg0->hw_timer[0].load.val = 1UL; + timer_ll_enable_alarm(tg0, 0, false); // No ISR needed for g_millis + timer_ll_enable_counter(tg0, 0, true); + + // --- 1. Hardware Config for TG0-Timer1 (Watchdog) --- + tg0->hw_timer[1].loadhi.val = 0UL; + tg0->hw_timer[1].loadlo.val = 0UL; + tg0->hw_timer[1].load.val = 1UL; + timer_ll_set_clock_prescale(tg0, 1, 80); // 1MHz + timer_ll_set_count_direction(tg0, 1, GPTIMER_COUNT_UP); + timer_ll_enable_alarm(tg0, 1, false); // No ISR needed for zcdACISR Watchdog + timer_ll_enable_counter(tg0, 1, true); + + // --- 2. Basic Hardware Config for TG1 (Heaters) --- + // Timer 0 + timer_ll_set_clock_prescale(tg1, 0, 80); + timer_ll_set_count_direction(tg1, 0, GPTIMER_COUNT_UP); + timer_ll_enable_alarm(tg1, 0, true); // Timer 1 - timer_ll_set_clock_prescale(tg0, 1, 80); - timer_ll_set_count_direction(tg0, 1, GPTIMER_COUNT_UP); - timer_ll_enable_alarm(tg0, 1, true); + timer_ll_set_clock_prescale(tg1, 1, 80); + timer_ll_set_count_direction(tg1, 1, GPTIMER_COUNT_UP); + timer_ll_enable_alarm(tg1, 1, true); - // --- 2. Manual ISR Registration --- - // ESP_INTR_FLAG_IRAM ensures the ISR stays in IRAM for fast context switching. - timer_isr_register((timer_group_t)0, (timer_idx_t)0, onTimer1, NULL, ESP_INTR_FLAG_IRAM, NULL); - timer_isr_register((timer_group_t)0, (timer_idx_t)1, onTimer2, NULL, ESP_INTR_FLAG_IRAM, NULL); + // --- 3. Manual ISR Registration --- + esp_intr_alloc(ETS_TG1_T0_LEVEL_INTR_SOURCE, ESP_INTR_FLAG_IRAM, onTimer1, NULL, NULL); + esp_intr_alloc(ETS_TG1_T1_LEVEL_INTR_SOURCE, ESP_INTR_FLAG_IRAM, onTimer2, NULL, NULL); - // --- 3. Hardware Config for TG1 (Watchdog) --- - timer_ll_set_clock_prescale(tg1, 0, 80000); - timer_ll_set_count_direction(tg1, 0, GPTIMER_COUNT_UP); - tg1->hw_timer[0].loadhi.val = 0UL; - tg1->hw_timer[0].loadlo.val = 0UL; - tg1->hw_timer[0].load.val = 1UL; - timer_ll_enable_alarm(tg1, 0, false); // No ISR needed for watchdog - timer_ll_enable_counter(tg1, 0, true); + tg0->hw_timer[0].update.val = 1; + uint32_t startupTime = timer_ll_get_counter_value(tg0, 0); + + zcdACISRCount = 0; + zcdLoadISRCount = 0; + + // --- 4. Hardware Trigger ISR Registration --- + //attachInterrupt(PIN_ZCD_AC, zcdACISR, CHANGE); // Attach zero-cross detection ISR + //attachInterrupt(PIN_ZCD_LOAD, zcdLoadISR, CHANGE); // Attach zero-cross detection ISR + + // Attach Load ISR with higher priority + esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ESP_INTR_FLAG_LEVEL3, zcdLoadISR, NULL, NULL); + + // Attach AC ISR with normal/lower priority + esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, zcdACISR, NULL, NULL); +} + +void setACLoadStatus(uint32_t tNow) { + static uint32_t lastTick = 0; + // --- 1. Process AC/Load Window (Every 1s) --- + if (tNow - lastTick >= 9999) { + zcdACCount = zcdACISRCount; + zcdLoadCount = zcdLoadISRCount; + + zcdACISRCount = 0; + zcdLoadISRCount = 0; + lastTick = tNow; + } + + // Safety: If no ISR has fired in over 1.5 seconds, force count to 0 + if (tNow - lastTick > 15000) { + zcdACCount = 0; + zcdLoadCount = 0; + } + + // ZCD + status.zcdAC = zcdACCount; + status.zcdLoad = zcdLoadCount; + if (status.zcdAC < 119 || status.zcdAC > 121) { + status.nFlags |= FLAG_ZCD_AC; + } + else { + status.nFlags &= ~FLAG_ZCD_AC; + } + if (status.zcdLoad < 6 || status.zcdLoad > 181) { + status.nFlags |= FLAG_ZCD_LOAD; + } + else { + status.nFlags &= ~FLAG_ZCD_LOAD; + } } \ No newline at end of file diff --git a/zcd.h b/zcd.h index be8d297..4c7b89f 100644 --- a/zcd.h +++ b/zcd.h @@ -1,6 +1,5 @@ #ifndef __ZCD_H #define __ZCD_H -extern volatile uint8_t zcdACCount, zcdLoadCount; // ZCD void setupZCD();