From 3eeeb8304d646eebc9c55c42904c77a220c8ea14 Mon Sep 17 00:00:00 2001 From: RnD1 Date: Sun, 19 Apr 2026 16:50:40 +0900 Subject: [PATCH] ZCD fix - working code --- HermitCrab.h | 2 +- HermitCrab.ino | 9 +- NTC_10K.cpp | 9 +- OTA.cpp | 2 +- Setup.cpp | 210 ++++++++++++++++++++++++++++++++++++----- UI.cpp | 29 ++---- UI.h | 10 +- WiFiHost.cpp | 3 - src/ESPUpdate.cpp | 10 +- zcd.cpp | 231 +++++++++++++++++++++------------------------- zcd.h | 10 ++ 11 files changed, 334 insertions(+), 191 deletions(-) diff --git a/HermitCrab.h b/HermitCrab.h index 8f5de33..b14c517 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 c790f32..8a89a8e 100644 --- a/HermitCrab.ino +++ b/HermitCrab.ino @@ -10,7 +10,9 @@ #include "OTA.h" #include "UI.h" #include "BLEScan.h" + #include "hal/timer_ll.h" +#include "hal/timer_types.h" #if defined(ESP32) @@ -54,8 +56,8 @@ MY_IRAM_ATTR void loop() { static uint8_t lastSecond = -1; // Read timer from TG0-Timer0 - tg0->hw_timer[0].update.val = 1; - uint32_t tNow = tg0->hw_timer[0].lo.val; + tg0->hw_timer[1].update.val = 1; + uint32_t tNow = (uint32_t)timer_ll_get_counter_value(tg0, 1); g_millis = (uint32_t) (tNow / 10); unsigned long tickMillis = g_millis; @@ -69,6 +71,8 @@ MY_IRAM_ATTR void loop() { // Every Second if (tickSecond != lastTickSecond) { + lastTickSecond = tickSecond; + // Time and ZCD setACLoadStatus(tNow); setTime(); @@ -115,7 +119,6 @@ MY_IRAM_ATTR void loop() { default: break; } - lastTickSecond = tickSecond; } yield(); } diff --git a/NTC_10K.cpp b/NTC_10K.cpp index 5a8b4aa..fb2d515 100644 --- a/NTC_10K.cpp +++ b/NTC_10K.cpp @@ -4,6 +4,9 @@ #include "NTC_10K.h" #include "Config.h" +#include "driver/gpio.h" +#include "driver/adc.h" + const float resistance[] = { 3360850.37, // -40°C 1973470.32, // -35°C @@ -71,10 +74,6 @@ void NTC_10K::setup(bool bNegativePolarity) { m_nTemp = -9999; m_fTemp = -9999.0f; m_fLastTemp = 0.0f; - - pinMode(PIN_NTC, INPUT); // Set PIN_NTC as input - analogReadResolution(12); // Set ADC resolution to 12 bits (0-4095) - analogSetAttenuation(ADC_11db); // Set attenuation for full-scale 3.3V } /** @@ -91,7 +90,7 @@ void NTC_10K::readSensor() { float currentInstantTemp; // High-precision intermediate // 1. Hardware Acquisition - int adcValue = constrain(analogRead(PIN_NTC), 1, 4094); + int adcValue = constrain(adc1_get_raw(ADC1_CHANNEL_3), 1, 4094); // 2. Voltage and Resistance Calculation Vin = (float)adcValue * _vRef / _RESO; diff --git a/OTA.cpp b/OTA.cpp index 6278873..b6f8584 100644 --- a/OTA.cpp +++ b/OTA.cpp @@ -17,7 +17,7 @@ // OTA // // ============================================================== -const char *HC__VERSION = "20260418036"; +const char *HC__VERSION = "20260419022"; #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 9b2127d..f4e9dda 100644 --- a/Setup.cpp +++ b/Setup.cpp @@ -13,6 +13,11 @@ #include #include "esp_coexist.h" +// GPIO Headers +#include "driver/gpio.h" +#include "driver/timer.h" +#include "driver/adc.h" + #define TAG_SETUP "TAG_SETUP" // Task handle @@ -24,14 +29,19 @@ bool g_bWiFiHasBeenConnected = false; extern STATUS_TYPE status; extern CHistory history; +// Hardware First +void setupGPIO1(); +void setupGPIO2(); +void setupPWM(); +void setupZCD(); +void setupTimers(); + void setupConfig(); void setupStatus(); void restoreStatus(); void setupWiFi(); void setupPostWiFi(bool bBoot); -void setupPins(); void setupSensor(); -void setupZCD(); void setup_BLE(); void scanI2C(); @@ -44,9 +54,9 @@ void setup() { //esp_log_level_set("BLE_POLL", ESP_LOG_INFO); // Module-specific level //esp_coex_preference_set(ESP_COEX_PREFER_BT); - DPRINTLN(" **********************"); - DPRINTF(" SETUP - Start - ver. %s type: %d\n", HC__VERSION, THIS_DEVICE_TYPE); - DPRINTLN(" **********************"); + DPRINTLN("**********************"); + DPRINTF(" SETUP - Start - ver. %s type: %d\n", HC__VERSION, THIS_DEVICE_TYPE); + DPRINTLN("**********************"); g_bWiFiHasBeenConnected = false; g_bWiFiHasBeenConnected = false; g_nYear = 2024; @@ -58,33 +68,35 @@ void setup() { bShowSensor = false; + // Hardware + setupPWM(); + setupGPIO1(); + setupConfig(); setupStatus(); - setupPins(); scanI2C(); setupSensor(); ui.setup(); - ui.message(0, (char *) "WiFi..."); setupWiFi(); - + if (aht25.sensor() || aht10_0x39.sensor()) { - ui.message(4, (char *) "Sensor... OK!"); + ui.message(4, (char *) "Sensor... OK!"); } else { - ui.message(4, (char *) "Sensor... None!"); + ui.message(4, (char *) "Sensor... None!"); } - + ui.message(5, (char *) "ZCD..."); setupZCD(); ui.message(5, (char *) "ZCD... OK!"); - + ui.message(6, (char *) "Setup OK!"); //if (!isWiFiConnected) delay(3000); ble.setupConnect(config.nBLESensorAddr, config.nBLESensorAddr2); - + // Restore Status restoreStatus(); - - + + // Create a task pinned to core 0 xTaskCreatePinnedToCore( core0Task, // Function to run as a task @@ -95,6 +107,8 @@ void setup() { &TaskHandle_0, // Task handle 0 // Core 0 ); + setupTimers(); + setupGPIO2(); DPRINTLN("Setup Completed\n========================\n"); } @@ -104,6 +118,160 @@ void setup() { // Setup // // ====================================================================== + +void setupGPIO1() { + // Set PIN Direction & Status + // ========================= + // 1. NTC (ADC 설정) + // ========================= + // adc1_config_channel_atten에서 내부적으로 핀 설정을 하므로 방향 설정은 생략 가능합니다. + adc1_config_width(ADC_WIDTH_BIT_12); // 0~4095 + adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11); + + // ========================= + // 2. UI Buttons 설정 + // ========================= + gpio_config_t io_conf_ui = {}; + io_conf_ui.intr_type = GPIO_INTR_ANYEDGE; + io_conf_ui.mode = GPIO_MODE_INPUT; + io_conf_ui.pin_bit_mask = (1ULL << PIN_SW_SET) | + (1ULL << PIN_SW_UP) | + (1ULL << PIN_SW_DOWN); + io_conf_ui.pull_up_en = GPIO_PULLUP_ENABLE; + io_conf_ui.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_config(&io_conf_ui); + + // ========================= + // 3. ZCD Inputs 설정 + // ========================= + gpio_config_t io_conf_zcd = {}; + io_conf_zcd.intr_type = GPIO_INTR_ANYEDGE; + io_conf_zcd.mode = GPIO_MODE_INPUT; + io_conf_zcd.pin_bit_mask = (1ULL << PIN_ZCD_AC) | (1ULL << PIN_ZCD_LOAD); + io_conf_zcd.pull_up_en = GPIO_PULLUP_DISABLE; + io_conf_zcd.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_config(&io_conf_zcd); + + // ========================= + // 4. Heater Outputs 설정 + // ========================= + gpio_config_t io_conf_heater = {}; + io_conf_heater.intr_type = GPIO_INTR_DISABLE; + io_conf_heater.mode = GPIO_MODE_OUTPUT; + io_conf_heater.pin_bit_mask = (1ULL << PIN_HEATER1) | (1ULL << PIN_HEATER2); + io_conf_heater.pull_up_en = GPIO_PULLUP_DISABLE; + io_conf_heater.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_config(&io_conf_heater); + + // 초기 상태 OFF 설정 + gpio_set_level((gpio_num_t)PIN_HEATER1, HEATER_OFF); + gpio_set_level((gpio_num_t)PIN_HEATER2, HEATER_OFF); +} + +void setupGPIO2() { + // ========================= + // ISR 서비스 및 핸들러 등록 + // ========================= + // LEVEL2 플래그를 사용하여 타이밍 정밀도를 높입니다. + esp_err_t err = gpio_install_isr_service(ESP_INTR_FLAG_IRAM); + if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) { + DPRINTLN("[GPIO] Error on gpio_install_isr_service"); + } + + // 버튼 핸들러 + gpio_isr_handler_add((gpio_num_t)PIN_SW_SET, buttonSetISR, NULL); + gpio_isr_handler_add((gpio_num_t)PIN_SW_UP, buttonUpISR, NULL); + gpio_isr_handler_add((gpio_num_t)PIN_SW_DOWN, buttonDownISR, NULL); + + // ZCD 핸들러 (이제 LEVEL2 우선순위로 동작) + gpio_isr_handler_add((gpio_num_t)PIN_ZCD_AC, zcdACISR, NULL); + gpio_isr_handler_add((gpio_num_t)PIN_ZCD_LOAD, zcdLoadISR, NULL); +} + +void setupTimers() { + + //=============================================================================== + // + // TIMER 설정 구조체 준비 + // + static timer_config_t tcfg0t1 = { + .alarm_en = TIMER_ALARM_DIS, + .counter_en = TIMER_START, + .intr_type = TIMER_INTR_LEVEL, + .counter_dir = TIMER_COUNT_UP, + .auto_reload = (timer_autoreload_t) TIMER_AUTORELOAD_DIS, + .divider = 8000 // 10KHz (100us tick) + }; + + esp_err_t err; + #ifdef DEBUG + bool bErr = false; + #endif + + // ========================= + // TG0 TIMER1 (millis replacement) + // ========================= + if ((err = timer_init(TIMER_GROUP_0, TIMER_1, &tcfg0t1)) == ESP_OK ) { + timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0); // init counter value + timer_start(TIMER_GROUP_0, TIMER_1); + } + #ifdef DEBUG + else { + DPRINTLN("[Timer] Failed to init timer TG0 Timer1"); + bErr = true; + } + #endif + + static timer_config_t tcfg1 = { + .alarm_en = TIMER_ALARM_EN, + .counter_en = TIMER_START, + .intr_type = TIMER_INTR_LEVEL, + .counter_dir = TIMER_COUNT_UP, + .auto_reload = (timer_autoreload_t) TIMER_AUTORELOAD_EN, + .divider = 80 // 1MHz (1us tick) + }; + + // ========================= + // TG1 TIMER0 (heater1) + // ========================= + if ((err = timer_init(TIMER_GROUP_1, TIMER_0, &tcfg1)) == ESP_OK ) { + timer_set_counter_value(TIMER_GROUP_1, TIMER_0, 0); + timer_set_alarm_value(TIMER_GROUP_1, TIMER_0, (uint64_t) 0xFFFFFFF0); + err = timer_isr_register(TIMER_GROUP_1, TIMER_0, timer0ISR, NULL, ESP_INTR_FLAG_IRAM, NULL ); + DPRINTF("TimerG1T0 ISR Register Result: %d\n", err); + timer_enable_intr(TIMER_GROUP_1, TIMER_0); + timer_start(TIMER_GROUP_1, TIMER_0); + } + #ifdef DEBUG + else { + DPRINTLN("[Timer] Failed to init timer TG1 Timer0"); + bErr = true; + } + #endif + + // ========================= + // TG1 TIMER1 (heater2) + // ========================= + if ((err = timer_init(TIMER_GROUP_1, TIMER_1, &tcfg1)) == ESP_OK ) { + timer_set_counter_value(TIMER_GROUP_1, TIMER_1, 0); + timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, (uint64_t) 0xFFFFFFF0); + err = timer_isr_register(TIMER_GROUP_1, TIMER_1, timer1ISR, NULL, ESP_INTR_FLAG_IRAM, NULL ); + DPRINTF("TimerG1T1 ISR Register Result: %d\n", err); + timer_enable_intr(TIMER_GROUP_1, TIMER_1); + timer_start(TIMER_GROUP_1, TIMER_1); + } + #ifdef DEBUG + else { + DPRINTLN("[Timer] Failed to init timer TG1 Timer1"); + bErr = true; + } + + if (bErr == false) { + DPRINTLN("[Timer] All Timers create and registered successfully!"); + } + #endif +} + void setupConfig() { config.load(); history.loadPID(); @@ -118,7 +286,7 @@ void setupWiFi() { // Connect WiFi for OTA if (config.ssid[0] && config.pw[0]) { esp_wifi_set_max_tx_power(74); - + ui.message(0, (char *) "WiFi..."); DPRINTF("BOOT: Connecting to WiFi: SSID: '%s', PW: '%s'\n", config.ssid, config.pw); WiFi.mode(WIFI_STA); WiFi.begin(config.ssid, config.pw); @@ -163,7 +331,7 @@ 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..."); ledcWrite(PIN_LED_WIFI, PWM_FULL / 20); checkOTA(true); ledcWrite(PIN_LED_WIFI, PWM_FULL * 39 / 40); @@ -185,13 +353,7 @@ void setupPostWiFi(bool bBoot = false) { } } -void setupPins() { - // --- Basic Digital Pin Initialization --- - pinMode(PIN_HEATER1, OUTPUT); - pinMode(PIN_HEATER2, OUTPUT); - digitalWrite(PIN_HEATER1, HEATER_OFF); - digitalWrite(PIN_HEATER2, HEATER_OFF); - +void setupPWM() { // --- 1. High Speed Group: Motor and Fan (~26kHz) --- // Core 2.0.17 uses APB (80MHz). 80MHz / (3 * 1024) ≈ 26kHz. ledcAttachChannel(PIN_MOTOR, PWM_26KHZ_FREQ, PWM_RESOLUTION, PWM_MOTOR_CHANNEL); diff --git a/UI.cpp b/UI.cpp index 601e008..10f8b7e 100644 --- a/UI.cpp +++ b/UI.cpp @@ -11,6 +11,8 @@ #include #include +#include "driver/gpio.h" + #define TAG_UI "UI" // Buttons #define DEBOUNCE_DELAY 100 @@ -210,12 +212,6 @@ const bool fineControl[] = { true }; -// -// Buttons -// -void buttonSetISR(); -void buttonUpISR(); -void buttonDownISR(); // Constructor for CUI class @@ -294,16 +290,7 @@ void CUI::setup() { boxD1 = {POS_X_D1, POS_Y_BOTTOM - HEIGHT_D1, WIDTH_D1, HEIGHT_D1}; // 17 + 2 boxD0 = {POS_X_D0, POS_Y_BOTTOM - HEIGHT_D0, WIDTH_D0, HEIGHT_D0}; // 17 + 2 - - // // Buttons - // - pinMode(PIN_SW_SET, INPUT_PULLUP); - pinMode(PIN_SW_UP, INPUT_PULLUP); - pinMode(PIN_SW_DOWN, INPUT_PULLUP); - attachInterrupt(digitalPinToInterrupt(PIN_SW_SET), buttonSetISR, CHANGE); - attachInterrupt(digitalPinToInterrupt(PIN_SW_UP), buttonUpISR, CHANGE); - attachInterrupt(digitalPinToInterrupt(PIN_SW_DOWN), buttonDownISR, CHANGE); initButtonState(); } @@ -1071,7 +1058,7 @@ void CUI::checkButtonStates(unsigned long currentMillis) { if (bButtonSetChanged) { // Compare with the last interrupt time to ensure debounce delay if (currentMillis - buttonSetChangeTime > DEBOUNCE_DELAY) { - if (digitalRead(PIN_SW_SET) == LOW) { + if (gpio_get_level((gpio_num_t)PIN_SW_SET) == LOW) { // Button pressed buttonSetDownTime = buttonSetChangeTime; bButtonSetDown = true; @@ -1092,7 +1079,7 @@ void CUI::checkButtonStates(unsigned long currentMillis) { if (bButtonUpChanged) { // Compare with the last interrupt time to ensure debounce delay if (currentMillis - buttonUpChangeTime > DEBOUNCE_DELAY) { - if (digitalRead(PIN_SW_UP) == LOW) { + if (gpio_get_level((gpio_num_t)PIN_SW_UP) == LOW) { // Button pressed buttonUpDownTime = buttonUpChangeTime; bButtonUpDown = true; @@ -1113,7 +1100,7 @@ void CUI::checkButtonStates(unsigned long currentMillis) { if (bButtonDownChanged) { // Compare with the last interrupt time to ensure debounce delay if (currentMillis - buttonDownChangeTime > DEBOUNCE_DELAY) { - if (digitalRead(PIN_SW_DOWN) == LOW) { + if (gpio_get_level((gpio_num_t)PIN_SW_DOWN) == LOW) { // Button pressed buttonDownDownTime = buttonDownChangeTime; bButtonDownDown = true; @@ -1133,20 +1120,20 @@ void CUI::checkButtonStates(unsigned long currentMillis) { } // ISR for the Set button handling -ARDUINO_ISR_ATTR void buttonSetISR() { +void IRAM_ATTR buttonSetISR(void *) { // Record the time of the button interrupt and set a flag ui.buttonSetChangeTime = millis(); ui.bButtonSetChanged = true; // Flag for main loop to process } // ISR for the Up button handling -ARDUINO_ISR_ATTR void buttonUpISR() { +void IRAM_ATTR buttonUpISR(void *) { ui.buttonUpChangeTime = millis(); ui.bButtonUpChanged = true; // Flag for main loop to process } // ISR for the Down button handling -ARDUINO_ISR_ATTR void buttonDownISR() { +void IRAM_ATTR buttonDownISR(void *) { ui.buttonDownChangeTime = millis(); ui.bButtonDownChanged = true; // Flag for main loop to process } \ No newline at end of file diff --git a/UI.h b/UI.h index 82f2883..0738f45 100644 --- a/UI.h +++ b/UI.h @@ -98,6 +98,14 @@ private: void checkButtonStates(unsigned long tickMillis); }; -#endif + +// +// Button ISR's +// +void IRAM_ATTR buttonSetISR(void *); +void IRAM_ATTR buttonUpISR(void *); +void IRAM_ATTR buttonDownISR(void *); extern CUI ui; +#endif + diff --git a/WiFiHost.cpp b/WiFiHost.cpp index 25e6492..aa01806 100644 --- a/WiFiHost.cpp +++ b/WiFiHost.cpp @@ -773,9 +773,6 @@ size_t CWiFiHost::ReceiveData(uint8_t* data, size_t size) m_pDataReceive_data = (char *) data; m_nDataReceive_size = size; m_nDataReceive_received = 0; -#ifdef ESP8266 - digitalWrite(PIN_EXTRA, LED_ON); -#endif return size; } diff --git a/src/ESPUpdate.cpp b/src/ESPUpdate.cpp index 7dbc3bf..81c7cd5 100644 --- a/src/ESPUpdate.cpp +++ b/src/ESPUpdate.cpp @@ -27,6 +27,8 @@ #include "mbedtls/aes.h" #include #define TAG_FW "FW Update" + // GPIO Headers + #include "driver/gpio.h" #elif defined(ESP8266) #include #include @@ -348,7 +350,7 @@ void ESPUpdateClass::_reset() { _command = U_FLASH; if (_ledPin != -1) { - digitalWrite(_ledPin, !_ledOn); + gpio_set_level((gpio_num_t)_ledPin, !_ledOn); } } @@ -775,12 +777,12 @@ size_t ESPUpdateClass::writeStream(Stream &data) { } if (_ledPin != -1) { - pinMode(_ledPin, OUTPUT); + gpio_set_direction((gpio_num_t)_ledPin, GPIO_MODE_OUTPUT); } while (remaining()) { if (_ledPin != -1) { - digitalWrite(_ledPin, _ledOn); + gpio_set_level((gpio_num_t)_ledPin, !_ledOn); } size_t bytesToRead = SPI_FLASH_SEC_SIZE - _bufferLen; if (bytesToRead > remaining()) { @@ -802,7 +804,7 @@ size_t ESPUpdateClass::writeStream(Stream &data) { } if (_ledPin != -1) { - digitalWrite(_ledPin, !_ledOn); + gpio_set_level((gpio_num_t)_ledPin, !_ledOn); } _bufferLen += toRead; if ((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer()) { diff --git a/zcd.cpp b/zcd.cpp index d8630f9..e1d4d4d 100644 --- a/zcd.cpp +++ b/zcd.cpp @@ -8,48 +8,15 @@ // 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" + +// GPIO Headers #include "driver/gpio.h" -#include "driver/periph_ctrl.h" +#include "driver/timer.h" +//#include "driver/timer_types_legacy.h" +//#include "esp_intr_alloc.h" -timg_dev_t *tg0 = &TIMERG0; -timg_dev_t *tg1 = &TIMERG1; - -#define SET_TIMER_1_SAFE(duty) do { \ - timerWrite(timerHeater1, 0); \ - timerAlarm(timerHeater1, duty, false, 0); \ -} while(0) - -#define SET_TIMER_2_SAFE(duty) do { \ - timerWrite(timerHeater2, 0); \ - timerAlarm(timerHeater2, duty, false, 0); \ -} while(0) - -#define SET_TIMER_1(duty) do { \ - 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); \ - \ - tg1->int_clr_timers.t0_int_clr = 1; \ - \ - tg1->hw_timer[0].update.val = 1; \ -} while(0) - -#define SET_TIMER_2(duty) do { \ - 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); \ - \ - tg1->int_clr_timers.t1_int_clr = 1; \ - \ - tg1->hw_timer[1].update.val = 1; \ -} while(0) #define ESP_INTR_FLAG_LEVEL3 (1<<3) #define ESP_INTR_FLAG_LEVEL1 (1<<1) @@ -75,17 +42,19 @@ volatile uint32_t dutyHeater2; // Calculated timerZCD count for TRIAC firing volatile uint8_t zcdACCount; volatile uint8_t zcdLoadCount; -volatile uint8_t ac1ControlMode = PHASE_CONTROL; -volatile uint8_t ac2ControlMode = PHASE_CONTROL; +volatile uint8_t ac1ControlMode; +volatile uint8_t ac2ControlMode; -volatile uint8_t fireStatusTimer1 = 0; -volatile uint8_t fireStatusTimer2 = 0; +volatile uint8_t fireStatusTimer0; +volatile uint8_t fireStatusTimer1; +timg_dev_t *tg0; +timg_dev_t *tg1; -hw_timer_t *timer10K; -hw_timer_t *timerDummy; -hw_timer_t *timerHeater1; -hw_timer_t *timerHeater2; +//hw_timer_t *timer10K; +//hw_timer_t *timerDummy; +//hw_timer_t *timerHeater1; +//hw_timer_t *timerHeater2; const char fireTable[17][16] { {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}, // 0 0% @@ -115,6 +84,9 @@ volatile uint8_t dutyAC2TableIndex = 0; volatile uint8_t zcdACISRCount = 0; volatile uint8_t zcdLoadISRCount = 0; +volatile bool fire_enable_1 = false; +volatile bool fire_enable_2 = false; + void setAC1ControlMode(uint8_t mode) { ac1ControlMode = mode; } void setAC2ControlMode(uint8_t mode) { ac2ControlMode = mode; } @@ -131,7 +103,7 @@ short getHeater2Duty() { } // Function to set the duty based on percentage (0 to 10000) -ARDUINO_ISR_ATTR void setHeater1Duty(short duty) { +void IRAM_ATTR setHeater1Duty(short duty) { if (ac1ControlMode == ZCD_CONTROL) { if (duty > 10000) duty = 10000; dutyAC1TableIndex = (uint8_t)((duty + 10000/32)/625); @@ -162,16 +134,15 @@ ARDUINO_ISR_ATTR void setHeater1Duty(short duty) { } // Function to set the duty based on percentage (0 to 10000) -ARDUINO_ISR_ATTR void setHeater2Duty(short duty) { +void IRAM_ATTR setHeater2Duty(short duty) { if (config.bAC2_OnOff) { if (duty >= 10000) { - digitalWrite(PIN_HEATER2, HEATER_ON); duty = 10000; + dutyHeater2 = LEADING_PULSE_COUNT; } else { - digitalWrite(PIN_HEATER2, HEATER_OFF); duty = 0; + dutyHeater2 = 0; // If 0% duty, no pulse (turn off TRIAC) } - dutyHeater2 = 0; } else { if (ac2ControlMode == ZCD_CONTROL) { if (duty > 10000) duty = 10000; @@ -203,124 +174,128 @@ ARDUINO_ISR_ATTR void setHeater2Duty(short duty) { ESP_LOGD(TAG_ZCD,"Set Duty: %.2f%%, Timer Count: %u clock cycles\n", duty, dutyHeater2); } +#define SET_TIMER_0_SAFE(duty) do { \ + timerWrite(timerHeater1, 0); \ + timerAlarm(timerHeater1, duty, false, 0); \ +} while(0) -void ARDUINO_ISR_ATTR onTimer1() { - if (fireStatusTimer1 == 0) { - // First Trigger: Turn ON - REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER1 - 32))); - fireStatusTimer1 = 1; - SET_TIMER_1_SAFE(18); // Schedule OFF pulse 8us later - } else { - // Second Trigger: Turn OFF - REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER1 - 32))); +#define SET_TIMER_1_SAFE(duty) do { \ + timerWrite(timerHeater2, 0); \ + timerAlarm(timerHeater2, duty, false, 0); \ +} while(0) + +void IRAM_ATTR timer0ISR(void *) { + #ifdef DEBUG_ZCD + zcdLoadISRCount++; + #endif + //timer_group_clr_intr_status_in_isr(TIMER_GROUP_1, TIMER_0); + TIMERG1.int_clr_timers.t0_int_clr = 1; + if (fire_enable_1) { + if (fireStatusTimer0 == 0) { + gpio_set_level((gpio_num_t)PIN_HEATER1, 1); + fireStatusTimer0 = 1; + + // Set next timer + timer_set_counter_value(TIMER_GROUP_1, TIMER_0, 0); + timer_set_alarm_value(TIMER_GROUP_1, TIMER_0, 18); + timer_set_alarm(TIMER_GROUP_1, TIMER_0, TIMER_ALARM_EN); + } else { + gpio_set_level((gpio_num_t)PIN_HEATER1, 0); + + // Suspend Timer until next zcdACISR + fire_enable_1 = false; + } } } -void ARDUINO_ISR_ATTR onTimer2() { - if (fireStatusTimer2 == 0) { - REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER2 - 32))); - fireStatusTimer2 = 1; - SET_TIMER_2_SAFE(18); - } else { - REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER2 - 32))); +void IRAM_ATTR timer1ISR(void *) +{ + //timer_group_clr_intr_status_in_isr(TIMER_GROUP_1, TIMER_1); + TIMERG1.int_clr_timers.t1_int_clr = 1; + if (fire_enable_2) { + if (fireStatusTimer1 == 0) { + gpio_set_level((gpio_num_t)PIN_HEATER2, 1); + fireStatusTimer1 = 1; + + // Set next timer + timer_set_counter_value(TIMER_GROUP_1, TIMER_1, 0); + timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, 18); + timer_set_alarm(TIMER_GROUP_1, TIMER_1, TIMER_ALARM_EN); + } else { + gpio_set_level((gpio_num_t)PIN_HEATER2, 0); + + // Suspend Timer until next zcdACISR + fire_enable_2 = false; + } } } // Zero-Cross Detection Interrupt Service Routine -void ARDUINO_ISR_ATTR zcdACISR() { +void IRAM_ATTR zcdACISR(void *) { // 1. Power side AC ZCD Count zcdACISRCount++; + fireStatusTimer0 = 0; fireStatusTimer1 = 0; - fireStatusTimer2 = 0; // 3. Heater 1 if (ac1ControlMode == ZCD_CONTROL) { - if (fireTable[dutyAC1TableIndex][seqStep]) SET_TIMER_1_SAFE(LEADING_ZCD_COUNT); + if (fireTable[dutyAC1TableIndex][seqStep]) { + timer_set_counter_value(TIMER_GROUP_1, TIMER_0, 0); + timer_set_alarm_value(TIMER_GROUP_1, TIMER_0, (uint64_t) LEADING_ZCD_COUNT); + timer_set_alarm(TIMER_GROUP_1, TIMER_0, TIMER_ALARM_EN); + fire_enable_1 = true; + } } else if ( dutyHeater1 >= LEADING_PULSE_COUNT){ - SET_TIMER_1_SAFE(dutyHeater1); + timer_set_counter_value(TIMER_GROUP_1, TIMER_0, 0); + timer_set_alarm_value(TIMER_GROUP_1, TIMER_0, (uint64_t) dutyHeater1); + timer_set_alarm(TIMER_GROUP_1, TIMER_0, TIMER_ALARM_EN); + fire_enable_1 = true; } // 4. Heater 2 if (ac2ControlMode == ZCD_CONTROL) { - if (fireTable[dutyAC2TableIndex][seqStep]) SET_TIMER_2_SAFE(LEADING_ZCD_COUNT); + if (fireTable[dutyAC2TableIndex][seqStep]) { + timer_set_counter_value(TIMER_GROUP_1, TIMER_1, 0); + timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, (uint64_t)LEADING_ZCD_COUNT); + timer_set_alarm(TIMER_GROUP_1, TIMER_1, TIMER_ALARM_EN); + fire_enable_2 = true; + } } else if (dutyHeater2 >= LEADING_PULSE_COUNT) { - SET_TIMER_2_SAFE(dutyHeater2); + timer_set_counter_value(TIMER_GROUP_1, TIMER_1, 0); + timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, (uint64_t)dutyHeater2); + timer_set_alarm(TIMER_GROUP_1, TIMER_1, TIMER_ALARM_EN); + fire_enable_2 = true; } - seqStep = ++seqStep & 0x0F; } -void ARDUINO_ISR_ATTR zcdLoadISR() { +void IRAM_ATTR zcdLoadISR(void *) { // Load side AC ZCD Count + #ifndef DEBUG_ZCD zcdLoadISRCount++; + #endif } void setupZCD() { - periph_module_enable(PERIPH_TIMG0_MODULE); - periph_module_enable(PERIPH_TIMG1_MODULE); - pinMode(PIN_ZCD_AC, INPUT); - pinMode(PIN_ZCD_LOAD, INPUT); - pinMode(PIN_HEATER1, OUTPUT); - pinMode(PIN_HEATER2, OUTPUT); - digitalWrite(PIN_HEATER1, HEATER_OFF); - digitalWrite(PIN_HEATER2, HEATER_OFF); - + //=============================================================================== + // Initialize variables dutyHeater1 = 0; // Calculated timerHeater1 count for TRIAC firing dutyHeater2 = 0; // Calculated timerZCD count for TRIAC firing zcdACCount = 0; zcdLoadCount = 0; - timerHeater1 = NULL; // Test config.ac1ControlMode = PHASE_CONTROL; config.ac2ControlMode = PHASE_CONTROL; + fireStatusTimer0 = 0; + fireStatusTimer1 = 0; + + tg0 = &TIMERG0; + tg1 = &TIMERG1; 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); - 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); - - attachInterrupt(PIN_ZCD_AC, zcdACISR, CHANGE); // Attach zero-cross detection ISR - attachInterrupt(PIN_ZCD_LOAD, zcdLoadISR, CHANGE); // Attach zero-cross detection ISR - - // Initialize and configure the timer - if ((timer10K = timerBegin(10000)) != NULL) { - // TG0-Timer0 - timerStop(timer10K); // Ensure timer is stopped initially - timerStart(timer10K); // Explicitly start the timer after setup - - } - - if ((timerDummy = timerBegin(1000000)) != NULL) { - // TG0-Timer1 - timerStop(timerDummy); // Ensure timer is stopped initially - timerStart(timerDummy); // Explicitly start the timer after setup - } - - if ((timerHeater1 = timerBegin(1000000)) != NULL) { - // TG1-Timer0 - timerAttachInterrupt(timerHeater1, &onTimer1); // Attach TRIAC firing routine - timerStop(timerHeater1); // Ensure timer is stopped initially - timerStart(timerHeater1); // Explicitly start the timer after setup - - } - - if ((timerHeater2 = timerBegin(1000000)) != NULL) { - // TG1-Timer1 - timerAttachInterrupt(timerHeater2, &onTimer2); // Attach TRIAC firing routine - timerStop(timerHeater2); // Ensure timer is stopped initially - timerStart(timerHeater2); // Explicitly start the timer after setup - } } void setACLoadStatus(uint32_t tNow) { diff --git a/zcd.h b/zcd.h index 4c7b89f..0ce9847 100644 --- a/zcd.h +++ b/zcd.h @@ -6,7 +6,17 @@ void setupZCD(); void setHeater1Duty(short duty); void setHeater2Duty(short duty); short getHeater1Duty(); + +void IRAM_ATTR zcdACISR(void *); +void IRAM_ATTR zcdLoadISR(void *); +void IRAM_ATTR timer0ISR(void *); +void IRAM_ATTR timer1ISR(void *); + +#define DEBUG_ZCD +#define ENABLE_TIMERS + #if defined(ESP8266) void setMistDuty(short duty); #endif + #endif \ No newline at end of file