ZCD optimizations

This commit is contained in:
Heuideog Yi @ PC RnD1 2026-04-17 11:34:49 +09:00
parent f9745ed01c
commit 97e9e68d35
11 changed files with 230 additions and 122 deletions

View File

@ -1,3 +1,12 @@
// ====================================================================
//
// Tuya 1 MAC: 38:1F:8D:77:73:34
// Tuya 1 MAC: 38:1F:8D:CB:ED:78
// Xiami MAC: A4:C1:38:E7:58:CF
//
// ====================================================================
#include <NimBLEDevice.h> #include <NimBLEDevice.h>
#include <BLEScan.h> #include <BLEScan.h>
#include <WiFi.h> #include <WiFi.h>

View File

@ -59,7 +59,7 @@ void checkWiFi(unsigned long tickMillis) {
// Connecting // Connecting
if (bConnecting) { if (bConnecting) {
if (tickMillis - lastAttempt < 60000) { if (tickMillis - lastAttempt < 60000) {
// give 30 seconds for connection try // give 60 seconds for connection try
return; return;
} }

View File

@ -239,5 +239,5 @@ extern bool bShowSensor;
extern const char *COMPANY_NAME; extern const char *COMPANY_NAME;
extern const char *SERVICE_NAME; extern const char *SERVICE_NAME;
extern const char *HC__VERSION; extern const char *HC__VERSION;
extern volatile uint32_t g_millis;
#endif #endif

View File

@ -10,6 +10,7 @@
#include "OTA.h" #include "OTA.h"
#include "UI.h" #include "UI.h"
#include "BLEScan.h" #include "BLEScan.h"
#include "hal/timer_ll.h"
#if defined(ESP32) #if defined(ESP32)
#include "esp_wifi.h" #include "esp_wifi.h"
@ -20,6 +21,8 @@ STATUS_TYPE status;
// Time // Time
volatile unsigned short g_nYear, g_nMonth, g_nDay, g_nHour, g_nMinute, g_nSecond; 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;
// Environment // Environment
bool bShowSensor = false; bool bShowSensor = false;
@ -44,14 +47,14 @@ void controlLightDuty();
// //
// ================================================================================== // ==================================================================================
MY_IRAM_ATTR void loop() { MY_IRAM_ATTR void loop() {
static unsigned long lastTickSecond = 0; static unsigned long lastTickSecond = 0;
static uint8_t lastSecond = -1; static uint8_t lastSecond = -1;
unsigned long tickMillis = millis(); g_millis = (uint32_t)timer_ll_get_counter_value(tg1, 1);
unsigned long tickSecond = tickMillis / 1000; unsigned long tickMillis = g_millis;
unsigned long tickSecond = tickMillis / 1000;
// Un-Conditional Loop
// Un-Conditional Loop {
{
//ESP_LOGI(TAG_MAIN,"Checking WiFi2"); //ESP_LOGI(TAG_MAIN,"Checking WiFi2");
//checkWiFi(tickMillis); //checkWiFi(tickMillis);
@ -60,59 +63,59 @@ MY_IRAM_ATTR void loop() {
// UI Button Check // UI Button Check
ui.loopButton(tickMillis); ui.loopButton(tickMillis);
} }
// Every Second // Every Second
if (tickSecond != lastTickSecond) if (tickSecond != lastTickSecond)
{ {
// Time and ZCD // Time and ZCD
setZCD(); setZCD();
setTime(); setTime();
// Temperature and Humidity // Temperature and Humidity
readSensors(); readSensors();
//ble.loop(tickMillis); //ble.loop(tickMillis);
// Fan, Motor, Light Duties // Fan, Motor, Light Duties
controlFanDuty(); controlFanDuty();
controlMotorDuty(); controlMotorDuty();
controlLightDuty(); controlLightDuty();
// Add to History - every minutes // Add to History - every minutes
if (g_nSecond == 0 && lastSecond != g_nSecond) { if (g_nSecond == 0 && lastSecond != g_nSecond) {
history.add(status); history.add(status);
} }
lastSecond = g_nSecond; lastSecond = g_nSecond;
// Every 10 Second // Every 10 Second
switch(tickSecond % 10) { switch(tickSecond % 10) {
case 1: // Every 5 second - xx:xx-x7 case 1: // Every 5 second - xx:xx-x7
if (bShowSensor) { if (bShowSensor) {
ESP_LOGI(TAG_MAIN, "%s\n", printStatus(tickSecond, true)); ESP_LOGI(TAG_MAIN, "%s\n", printStatus(tickSecond, true));
} }
break; break;
case 2: // AC1 case 2: // AC1
controlAC1(status.nTemp1, tickSecond); controlAC1(status.nTemp1, tickSecond);
break; break;
case 3: // AC2 case 3: // AC2
controlAC2(status.nTemp1, tickSecond); controlAC2(status.nTemp1, tickSecond);
break; break;
case 4: // Mist case 4: // Mist
controlMist(status.nHumid1, tickSecond); controlMist(status.nHumid1, tickSecond);
break; break;
case 5: // Fan Control case 5: // Fan Control
controlFan(status.nTemp1, tickSecond); controlFan(status.nTemp1, tickSecond);
break; break;
case 6: // Motor Control case 6: // Motor Control
controlMotor(g_nHour, g_nMinute, tickSecond); controlMotor(g_nHour, g_nMinute, tickSecond);
break; break;
case 7: // Light Control case 7: // Light Control
controlLight(g_nHour, g_nMinute, tickSecond); controlLight(g_nHour, g_nMinute, tickSecond);
break; break;
default: default:
break; break;
} }
lastTickSecond = tickSecond; lastTickSecond = tickSecond;
} }
yield(); yield();
} }

View File

@ -69,7 +69,7 @@ void NTC_10K::setup(bool bNegativePolarity) {
_vRef = 3.3f; _vRef = 3.3f;
_RESO = 4095; _RESO = 4095;
m_nTemp = -9999; m_nTemp = -9999;
m_fTemp = -9999.0; m_fTemp = -9999.0f;
m_fLastTemp = 0.0f; m_fLastTemp = 0.0f;
pinMode(PIN_NTC, INPUT); // Set PIN_NTC as input pinMode(PIN_NTC, INPUT); // Set PIN_NTC as input
@ -125,8 +125,8 @@ void NTC_10K::readSensor() {
if (m_fTemp < -5000.0f) { if (m_fTemp < -5000.0f) {
m_fTemp = currentInstantTemp; m_fTemp = currentInstantTemp;
} else { } else {
// 0.01f Alpha: The 5°C PWM noise now only moves the buffer by 0.05°C per hit. // 0.005f Alpha: The 5°C PWM noise now only moves the buffer by 0.05°C per hit.
const float alpha = 0.05f; const float alpha = 0.005f;
m_fTemp = (currentInstantTemp * alpha) + (m_fTemp * (1.0f - alpha)); m_fTemp = (currentInstantTemp * alpha) + (m_fTemp * (1.0f - alpha));
} }

View File

@ -17,7 +17,7 @@
// OTA // OTA
// //
// ============================================================== // ==============================================================
const char *HC__VERSION = "20260415001"; const char *HC__VERSION = "20260416002";
#define UPDATE_PORT ((uint16_t) 443) #define UPDATE_PORT ((uint16_t) 443)
const char *url = "visionsoft.kr"; const char *url = "visionsoft.kr";
const char *uri = "/sc/pages/firmware_download.php"; const char *uri = "/sc/pages/firmware_download.php";

View File

@ -12,6 +12,7 @@
#include "BLEScan.h" #include "BLEScan.h"
#include <esp_wifi.h> #include <esp_wifi.h>
#include "esp_coexist.h" #include "esp_coexist.h"
#include "hal/timer_ll.h"
#define TAG_SETUP "TAG_SETUP" #define TAG_SETUP "TAG_SETUP"
// Task handle // Task handle
@ -22,6 +23,7 @@ bool g_bWiFiHasBeenConnected = false;
extern STATUS_TYPE status; extern STATUS_TYPE status;
extern CHistory history; extern CHistory history;
extern timg_dev_t *tg1;
void setupConfig(); void setupConfig();
void setupStatus(); void setupStatus();
@ -35,6 +37,14 @@ void setup_BLE();
void scanI2C(); void scanI2C();
void setup() { 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: // put your setup code here, to run once:
#ifdef DEBUG #ifdef DEBUG
Serial.begin(115200); Serial.begin(115200);
@ -171,7 +181,7 @@ void setupPostWiFi(bool bBoot = false) {
DPRINTLN(" Trying OTA"); DPRINTLN(" Trying OTA");
ui.message(2, (char *) "Update check..."); ui.message(2, (char *) "Update check...");
checkOTA(true); checkOTA(true);
ui.message(2, (char *) "Update check...OK!"); ui.message(2, (char *) "Update OK!");
DPRINTLN(" OTA Process completed!"); DPRINTLN(" OTA Process completed!");
DPRINTLN("===============================\n"); DPRINTLN("===============================\n");
} else { } else {

View File

@ -25,7 +25,7 @@ MY_IRAM_ATTR void core0Task(void *pvParameters) {
ESP_LOGI(TAG_TASK0,"Core 0 Task Started"); ESP_LOGI(TAG_TASK0,"Core 0 Task Started");
DPRINTLN("Core 0 Task Started"); DPRINTLN("Core 0 Task Started");
wl_status_t lastWiFiStatus = WL_DISCONNECTED; wl_status_t lastWiFiStatus = WL_DISCONNECTED;
unsigned long tickMillis = millis(); unsigned long tickMillis = g_millis;
unsigned long tickSecond; unsigned long tickSecond;
uint8_t slot; uint8_t slot;
uint8_t lastSlot = 255; uint8_t lastSlot = 255;
@ -36,7 +36,7 @@ MY_IRAM_ATTR void core0Task(void *pvParameters) {
while (true) { while (true) {
esp_task_wdt_reset(); esp_task_wdt_reset();
tickMillis = millis(); tickMillis = g_millis;
tickSecond = tickMillis / 1000; tickSecond = tickMillis / 1000;
slot = (tickMillis % 1000) / 50; slot = (tickMillis % 1000) / 50;

6
UI.cpp
View File

@ -1135,18 +1135,18 @@ void CUI::checkButtonStates(unsigned long currentMillis) {
// ISR for the Set button handling // ISR for the Set button handling
ARDUINO_ISR_ATTR void buttonSetISR() { ARDUINO_ISR_ATTR void buttonSetISR() {
// Record the time of the button interrupt and set a flag // Record the time of the button interrupt and set a flag
ui.buttonSetChangeTime = millis(); ui.buttonSetChangeTime = g_millis;
ui.bButtonSetChanged = true; // Flag for main loop to process ui.bButtonSetChanged = true; // Flag for main loop to process
} }
// ISR for the Up button handling // ISR for the Up button handling
ARDUINO_ISR_ATTR void buttonUpISR() { ARDUINO_ISR_ATTR void buttonUpISR() {
ui.buttonUpChangeTime = millis(); ui.buttonUpChangeTime = g_millis;
ui.bButtonUpChanged = true; // Flag for main loop to process ui.bButtonUpChanged = true; // Flag for main loop to process
} }
// ISR for the Down button handling // ISR for the Down button handling
ARDUINO_ISR_ATTR void buttonDownISR() { ARDUINO_ISR_ATTR void buttonDownISR() {
ui.buttonDownChangeTime = millis(); ui.buttonDownChangeTime = g_millis;
ui.bButtonDownChanged = true; // Flag for main loop to process ui.bButtonDownChanged = true; // Flag for main loop to process
} }

View File

@ -81,12 +81,12 @@ void CWiFiHost::Setup()
//sockfd = -1; //sockfd = -1;
//connectStartTime = 0; //connectStartTime = 0;
//isConnecting = false; //isConnecting = false;
// Operation // Operation
m_nMode = MODE_WAITING; m_nMode = MODE_WAITING;
m_bHelloSent = false; m_bHelloSent = false;
m_bSendHistoryPending = false; m_bSendHistoryPending = false;
m_nLastReceivedTime = m_nLastReceivedTime =
m_nLastHeartBeatSentTime = m_nLastHeartBeatSentTime =
m_nLastUDPBroadcastTime = millis(); m_nLastUDPBroadcastTime = millis();
@ -121,7 +121,6 @@ void CWiFiHost::Setup()
// Server // Server
wifiServer.begin(SERVER_PORT, 1); wifiServer.begin(SERVER_PORT, 1);
//wifiExternal.begin(m_nPublicPort, 1); //wifiExternal.begin(m_nPublicPort, 1);
m_nLastReceivedTime = millis();
m_bClientConnected = false; m_bClientConnected = false;
// UDP // UDP
@ -398,7 +397,7 @@ void CWiFiHost::ProcessPacket(TCP_PACKET& pkt)
{ {
// System // System
case CMD_HEARTBEAT: case CMD_HEARTBEAT:
m_nLastReceivedTime = millis(); m_nLastReceivedTime = g_millis;
//ESP_LOGI(TAG_WIFI_HOST,"H"); //ESP_LOGI(TAG_WIFI_HOST,"H");
break; break;
case CMD_HELLO: case CMD_HELLO:

207
zcd.cpp
View File

@ -6,11 +6,43 @@
#include <freertos/task.h> #include <freertos/task.h>
#include <driver/gptimer.h> #include <driver/gptimer.h>
#include "hal/timer_ll.h"
#include "hal/timer_types.h"
#include "driver/timer.h" // Needed for timer_isr_register
// 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); \
} 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); \
} while(0)
#define TAG_ZCD "ZCD" #define TAG_ZCD "ZCD"
// Constants // Constants
#define EFFECTIVE_POWER 0.86 #define EFFECTIVE_POWER 0.86
#define LEADING_TIME_RATIO 0.06 #define LEADING_TIME_RATIO 0.06
#define PHASE_CONTROL 0
#define ZCD_CONTROL 1
// ESP32 Clock Constants // ESP32 Clock Constants
const uint32_t AC_CYCLE_TIME_CLOCKS = 8333; // Half cycle of 60Hz AC in clock cycles const uint32_t AC_CYCLE_TIME_CLOCKS = 8333; // Half cycle of 60Hz AC in clock cycles
const uint32_t EFFECTIVE_HALF_CYCLE = EFFECTIVE_POWER * AC_CYCLE_TIME_CLOCKS; // Effective half cycle in clock cycles const uint32_t EFFECTIVE_HALF_CYCLE = EFFECTIVE_POWER * AC_CYCLE_TIME_CLOCKS; // Effective half cycle in clock cycles
@ -23,9 +55,31 @@ volatile uint32_t dutyHeater2; // Calculated timerZCD count for TRIAC firing
volatile uint8_t zcdACCount; volatile uint8_t zcdACCount;
volatile uint8_t zcdLoadCount; volatile uint8_t zcdLoadCount;
volatile uint8_t ac1ControlMode = PHASE_CONTROL;
volatile uint8_t ac2ControlMode = PHASE_CONTROL;
volatile uint8_t fireStatusTimer1 = 0;
volatile uint8_t fireStatusTimer2 = 0;
hw_timer_t *timerHeater1; hw_timer_t *timerHeater1;
hw_timer_t *timerHeater2; 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%
uint8_t seqStep = 0;
uint8_t dutyAC1 = 0;
uint8_t dutyAC2 = 0;
void setAC1ControlMode(uint8_t mode) { ac1ControlMode = mode; }
void setAC2ControlMode(uint8_t mode) { ac2ControlMode = mode; }
short getHeater1Duty() { short getHeater1Duty() {
if (dutyHeater1 == 0) return 0; if (dutyHeater1 == 0) return 0;
@ -41,25 +95,29 @@ short getHeater2Duty() {
// Function to set the duty based on percentage (0 to 10000) // Function to set the duty based on percentage (0 to 10000)
ARDUINO_ISR_ATTR void setHeater1Duty(short duty) { ARDUINO_ISR_ATTR void setHeater1Duty(short duty) {
if (duty <= 0) { if (ac1ControlMode == ZCD_CONTROL) {
dutyHeater1 = 0; // If 0% duty, no pulse (turn off TRIAC) dutyAC1 = (uint8_t)((duty + 10000/16)/1250);
} else if (duty >= 10000) {
// 100% duty corresponds to the leading pulse + full effective half cycle
dutyHeater1 = LEADING_PULSE_COUNT;
} else { } else {
// Map duty to power ratio (0 to 1) if (duty <= 0) {
float powerRatio = (float) duty / 10000.0f; dutyHeater1 = 0; // If 0% duty, no pulse (turn off TRIAC)
} else if (duty >= 10000) {
// 100% duty corresponds to the leading pulse + full effective half cycle
dutyHeater1 = 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 // Calculate the angle in radians using the inverse cosine directly
float angleRadians = acosf(1.0f - 2.0f * powerRatio); float angleRadians = acosf(1.0f - 2.0f * powerRatio);
// Convert angle to time delay (in clock cycles) // Convert angle to time delay (in clock cycles)
// Normalized angle (0 to PI) maps to half-cycle (0 to EFFECTIVE_HALF_CYCLE) // Normalized angle (0 to PI) maps to half-cycle (0 to EFFECTIVE_HALF_CYCLE)
uint32_t pulseCount = (angleRadians / M_PI) * EFFECTIVE_HALF_CYCLE; uint32_t pulseCount = (angleRadians / M_PI) * EFFECTIVE_HALF_CYCLE;
dutyHeater1 = LEADING_PULSE_COUNT + EFFECTIVE_HALF_CYCLE - pulseCount; dutyHeater1 = LEADING_PULSE_COUNT + EFFECTIVE_HALF_CYCLE - pulseCount;
}
} }
uint32_t nDuty = duty * PWM_FULL / 10000; uint32_t nDuty = duty * PWM_FULL / 10000;
ledcWrite(PIN_LED_HEATER1, PWM_FULL - nDuty); ledcWrite(PIN_LED_HEATER1, PWM_FULL - nDuty);
ESP_LOGD(TAG_ZCD,"Set Duty: %.2f%%, Timer Count: %u clock cycles", duty, dutyHeater1); ESP_LOGD(TAG_ZCD,"Set Duty: %.2f%%, Timer Count: %u clock cycles", duty, dutyHeater1);
@ -103,55 +161,76 @@ ARDUINO_ISR_ATTR void setHeater2Duty(short duty) {
} }
void ARDUINO_ISR_ATTR onTimer1() { void ARDUINO_ISR_ATTR onTimer1(void *) {
digitalWrite(PIN_HEATER1, HIGH); // Fire TRIAC if (fireStatusTimer1) {
delayMicroseconds(10); // Short pulse to trigger TRIAC REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER1 - 32))); // Clear (Low)
digitalWrite(PIN_HEATER1, LOW); // Turn off TRIAC trigger } else {
REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER1 - 32))); // Set (High)
fireStatusTimer1 = 1;
SET_TIMER_1(8); // 8 us
}
} }
void ARDUINO_ISR_ATTR onTimer2() { void ARDUINO_ISR_ATTR onTimer2(void *) {
digitalWrite(PIN_HEATER2, HIGH); // Fire TRIAC if (fireStatusTimer2) {
delayMicroseconds(10); // Short pulse to trigger TRIAC REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER2 - 32))); // Clear (Low)
digitalWrite(PIN_HEATER2, LOW); // Turn off TRIAC trigger } else {
REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER2 - 32))); // Set (High)
fireStatusTimer2 = 1;
SET_TIMER_2(8); // 8 us
}
} }
// Zero-Cross Detection Interrupt Service Routine // Zero-Cross Detection Interrupt Service Routine
void ARDUINO_ISR_ATTR zcdACISR() { void ARDUINO_ISR_ATTR zcdACISR() {
uint32_t clock = micros(); // 1. Check the dedicated Watchdog Timer (Group 1)
static uint32_t lastClock = 0l; uint32_t elapsed = timer_ll_get_counter_value(tg1, 0);
if (elapsed < 8000) return; // Reject noise based on absolute time since last ZCD
if (clock - lastClock < 8000) tg1->hw_timer[0].loadhi.val = 0UL;
return; tg1->hw_timer[0].loadlo.val = 0UL;
lastClock = clock; tg1->hw_timer[0].load.val = 1UL;
zcdACCount++; zcdACCount++;
fireStatusTimer1 = 0;
fireStatusTimer2 = 0;
// Heater 1 // Heater 1
if (dutyHeater1 == MAX_PULSE_COUNT) { if (ac1ControlMode == ZCD_CONTROL) {
onTimer1(); 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 } else {
timerStop(timerHeater1); // Stop any existing timer action if (dutyHeater1 >= LEADING_PULSE_COUNT && dutyHeater1 < MAX_PULSE_COUNT) {
timerWrite(timerHeater1, 0); // Reset counter to 0 // Stop the timer, configure new alarm, then explicitly start
timerAlarm(timerHeater1, dutyHeater1, false, 0); // Set alarm with updated duty SET_TIMER_1(dutyHeater1); // Set alarm with updated duty
timerStart(timerHeater1); // Start the timer explicitly }
else if (dutyHeater1 == MAX_PULSE_COUNT) {
onTimer1(NULL);
}
} }
// Heater 2 // Heater 2
if (dutyHeater2 == MAX_PULSE_COUNT) { if (ac2ControlMode == ZCD_CONTROL) {
onTimer2(); if (fireTable[dutyAC2][seqStep]) {
onTimer2(NULL);
}
} }
else if (dutyHeater2 >= LEADING_PULSE_COUNT && dutyHeater2 < MAX_PULSE_COUNT) { else {
// Stop the timer, configure new alarm, then explicitly start if (dutyHeater2 >= LEADING_PULSE_COUNT && dutyHeater2 < MAX_PULSE_COUNT) {
timerStop(timerHeater2); // Stop any existing timer action // Stop the timer, configure new alarm, then explicitly start
timerWrite(timerHeater2, 0); // Reset counter to 0 SET_TIMER_2(dutyHeater2); // Set alarm with updated duty
timerAlarm(timerHeater2, dutyHeater2, false, 0); // Set alarm with updated duty }
timerStart(timerHeater2); // Start the timer explicitly else if (dutyHeater2 == MAX_PULSE_COUNT) {
onTimer2(NULL);
}
} }
seqStep = ++seqStep & 0x07;
} }
void ARDUINO_ISR_ATTR zcdLoadISR() { void ARDUINO_ISR_ATTR zcdLoadISR() {
zcdLoadCount++; ++zcdLoadCount;
} }
void setupZCD() { void setupZCD() {
@ -166,20 +245,28 @@ void setupZCD() {
zcdLoadCount = 0; zcdLoadCount = 0;
timerHeater1 = NULL; timerHeater1 = NULL;
attachInterrupt(PIN_ZCD_AC, zcdACISR, CHANGE); // Attach zero-cross detection ISR // --- 1. Basic Hardware Config for TG0 (Heaters) ---
attachInterrupt(PIN_ZCD_LOAD, zcdLoadISR, CHANGE); // Attach zero-cross detection ISR // Timer 0
timer_ll_set_clock_prescale(tg0, 0, 80);
timer_ll_set_count_direction(tg0, 0, GPTIMER_COUNT_UP);
timer_ll_enable_alarm(tg0, 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);
// Initialize and configure the timer // --- 2. Manual ISR Registration ---
if ((timerHeater1 = timerBegin(1000000)) != NULL) { // ESP_INTR_FLAG_IRAM ensures the ISR stays in IRAM for fast context switching.
timerAttachInterrupt(timerHeater1, &onTimer1); // Attach TRIAC firing routine timer_isr_register((timer_group_t)0, (timer_idx_t)0, onTimer1, NULL, ESP_INTR_FLAG_IRAM, NULL);
timerStop(timerHeater1); // Ensure timer is stopped initially timer_isr_register((timer_group_t)0, (timer_idx_t)1, onTimer2, NULL, ESP_INTR_FLAG_IRAM, NULL);
timerStart(timerHeater1); // Explicitly start the timer after setup
} // --- 3. Hardware Config for TG1 (Watchdog) ---
timer_ll_set_clock_prescale(tg1, 0, 80000);
if ((timerHeater2 = timerBegin(1000000)) != NULL) { timer_ll_set_count_direction(tg1, 0, GPTIMER_COUNT_UP);
timerAttachInterrupt(timerHeater2, &onTimer2); // Attach TRIAC firing routine tg1->hw_timer[0].loadhi.val = 0UL;
timerStop(timerHeater2); // Ensure timer is stopped initially tg1->hw_timer[0].loadlo.val = 0UL;
timerStart(timerHeater2); // Explicitly start the timer after setup 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);
} }