ZCD fix - working code

This commit is contained in:
Heuideog Yi @ PC RnD1 2026-04-19 16:50:40 +09:00
parent 394ba748f5
commit 3eeeb8304d
11 changed files with 334 additions and 191 deletions

View File

@ -20,7 +20,7 @@
#ifndef DEBUG
#define DEBUG 1 // Set to 0 to disable debug output
#endif
#undef DEBUG
//#undef DEBUG
//#define BLE_DEBUG

View File

@ -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();
}

View File

@ -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;

View File

@ -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";

192
Setup.cpp
View File

@ -13,6 +13,11 @@
#include <esp_wifi.h>
#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(" **********************");
DPRINTLN("**********************");
DPRINTF(" SETUP - Start - ver. %s type: %d\n", HC__VERSION, THIS_DEVICE_TYPE);
DPRINTLN(" **********************");
DPRINTLN("**********************");
g_bWiFiHasBeenConnected = false;
g_bWiFiHasBeenConnected = false;
g_nYear = 2024;
@ -58,13 +68,15 @@ 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()) {
@ -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);

29
UI.cpp
View File

@ -11,6 +11,8 @@
#include <Fonts/FreeSans12pt7b.h>
#include <Fonts/FreeSans9pt7b.h>
#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
}

10
UI.h
View File

@ -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

View File

@ -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;
}

View File

@ -27,6 +27,8 @@
#include "mbedtls/aes.h"
#include <WiFi.h>
#define TAG_FW "FW Update"
// GPIO Headers
#include "driver/gpio.h"
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
@ -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()) {

229
zcd.cpp
View File

@ -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
#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 {
// Second Trigger: Turn OFF
REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER1 - 32)));
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);
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 {
REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER2 - 32)));
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);
} else if (dutyHeater2 >= LEADING_PULSE_COUNT) {
SET_TIMER_2_SAFE(dutyHeater2);
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) {
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) {

10
zcd.h
View File

@ -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