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 #ifndef DEBUG
#define DEBUG 1 // Set to 0 to disable debug output #define DEBUG 1 // Set to 0 to disable debug output
#endif #endif
#undef DEBUG //#undef DEBUG
//#define BLE_DEBUG //#define BLE_DEBUG

View File

@ -10,7 +10,9 @@
#include "OTA.h" #include "OTA.h"
#include "UI.h" #include "UI.h"
#include "BLEScan.h" #include "BLEScan.h"
#include "hal/timer_ll.h" #include "hal/timer_ll.h"
#include "hal/timer_types.h"
#if defined(ESP32) #if defined(ESP32)
@ -54,8 +56,8 @@ MY_IRAM_ATTR void loop() {
static uint8_t lastSecond = -1; static uint8_t lastSecond = -1;
// Read timer from TG0-Timer0 // Read timer from TG0-Timer0
tg0->hw_timer[0].update.val = 1; tg0->hw_timer[1].update.val = 1;
uint32_t tNow = tg0->hw_timer[0].lo.val; uint32_t tNow = (uint32_t)timer_ll_get_counter_value(tg0, 1);
g_millis = (uint32_t) (tNow / 10); g_millis = (uint32_t) (tNow / 10);
unsigned long tickMillis = g_millis; unsigned long tickMillis = g_millis;
@ -69,6 +71,8 @@ MY_IRAM_ATTR void loop() {
// Every Second // Every Second
if (tickSecond != lastTickSecond) if (tickSecond != lastTickSecond)
{ {
lastTickSecond = tickSecond;
// Time and ZCD // Time and ZCD
setACLoadStatus(tNow); setACLoadStatus(tNow);
setTime(); setTime();
@ -115,7 +119,6 @@ MY_IRAM_ATTR void loop() {
default: default:
break; break;
} }
lastTickSecond = tickSecond;
} }
yield(); yield();
} }

View File

@ -4,6 +4,9 @@
#include "NTC_10K.h" #include "NTC_10K.h"
#include "Config.h" #include "Config.h"
#include "driver/gpio.h"
#include "driver/adc.h"
const float resistance[] = { const float resistance[] = {
3360850.37, // -40°C 3360850.37, // -40°C
1973470.32, // -35°C 1973470.32, // -35°C
@ -71,10 +74,6 @@ void NTC_10K::setup(bool bNegativePolarity) {
m_nTemp = -9999; m_nTemp = -9999;
m_fTemp = -9999.0f; m_fTemp = -9999.0f;
m_fLastTemp = 0.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 float currentInstantTemp; // High-precision intermediate
// 1. Hardware Acquisition // 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 // 2. Voltage and Resistance Calculation
Vin = (float)adcValue * _vRef / _RESO; Vin = (float)adcValue * _vRef / _RESO;

View File

@ -17,7 +17,7 @@
// OTA // OTA
// //
// ============================================================== // ==============================================================
const char *HC__VERSION = "20260418036"; const char *HC__VERSION = "20260419022";
#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";

210
Setup.cpp
View File

@ -13,6 +13,11 @@
#include <esp_wifi.h> #include <esp_wifi.h>
#include "esp_coexist.h" #include "esp_coexist.h"
// GPIO Headers
#include "driver/gpio.h"
#include "driver/timer.h"
#include "driver/adc.h"
#define TAG_SETUP "TAG_SETUP" #define TAG_SETUP "TAG_SETUP"
// Task handle // Task handle
@ -24,14 +29,19 @@ bool g_bWiFiHasBeenConnected = false;
extern STATUS_TYPE status; extern STATUS_TYPE status;
extern CHistory history; extern CHistory history;
// Hardware First
void setupGPIO1();
void setupGPIO2();
void setupPWM();
void setupZCD();
void setupTimers();
void setupConfig(); void setupConfig();
void setupStatus(); void setupStatus();
void restoreStatus(); void restoreStatus();
void setupWiFi(); void setupWiFi();
void setupPostWiFi(bool bBoot); void setupPostWiFi(bool bBoot);
void setupPins();
void setupSensor(); void setupSensor();
void setupZCD();
void setup_BLE(); void setup_BLE();
void scanI2C(); void scanI2C();
@ -44,9 +54,9 @@ void setup() {
//esp_log_level_set("BLE_POLL", ESP_LOG_INFO); // Module-specific level //esp_log_level_set("BLE_POLL", ESP_LOG_INFO); // Module-specific level
//esp_coex_preference_set(ESP_COEX_PREFER_BT); //esp_coex_preference_set(ESP_COEX_PREFER_BT);
DPRINTLN(" **********************"); DPRINTLN("**********************");
DPRINTF(" SETUP - Start - ver. %s type: %d\n", HC__VERSION, THIS_DEVICE_TYPE); DPRINTF(" SETUP - Start - ver. %s type: %d\n", HC__VERSION, THIS_DEVICE_TYPE);
DPRINTLN(" **********************"); DPRINTLN("**********************");
g_bWiFiHasBeenConnected = false; g_bWiFiHasBeenConnected = false;
g_bWiFiHasBeenConnected = false; g_bWiFiHasBeenConnected = false;
g_nYear = 2024; g_nYear = 2024;
@ -58,33 +68,35 @@ void setup() {
bShowSensor = false; bShowSensor = false;
// Hardware
setupPWM();
setupGPIO1();
setupConfig(); setupConfig();
setupStatus(); setupStatus();
setupPins();
scanI2C(); scanI2C();
setupSensor(); setupSensor();
ui.setup(); ui.setup();
ui.message(0, (char *) "WiFi...");
setupWiFi(); setupWiFi();
if (aht25.sensor() || aht10_0x39.sensor()) { if (aht25.sensor() || aht10_0x39.sensor()) {
ui.message(4, (char *) "Sensor... OK!"); ui.message(4, (char *) "Sensor... OK!");
} else { } else {
ui.message(4, (char *) "Sensor... None!"); ui.message(4, (char *) "Sensor... None!");
} }
ui.message(5, (char *) "ZCD..."); ui.message(5, (char *) "ZCD...");
setupZCD(); setupZCD();
ui.message(5, (char *) "ZCD... OK!"); ui.message(5, (char *) "ZCD... OK!");
ui.message(6, (char *) "Setup OK!"); ui.message(6, (char *) "Setup OK!");
//if (!isWiFiConnected) delay(3000); //if (!isWiFiConnected) delay(3000);
ble.setupConnect(config.nBLESensorAddr, config.nBLESensorAddr2); ble.setupConnect(config.nBLESensorAddr, config.nBLESensorAddr2);
// Restore Status // Restore Status
restoreStatus(); restoreStatus();
// Create a task pinned to core 0 // Create a task pinned to core 0
xTaskCreatePinnedToCore( xTaskCreatePinnedToCore(
core0Task, // Function to run as a task core0Task, // Function to run as a task
@ -95,6 +107,8 @@ void setup() {
&TaskHandle_0, // Task handle &TaskHandle_0, // Task handle
0 // Core 0 0 // Core 0
); );
setupTimers();
setupGPIO2();
DPRINTLN("Setup Completed\n========================\n"); DPRINTLN("Setup Completed\n========================\n");
} }
@ -104,6 +118,160 @@ void setup() {
// 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() { void setupConfig() {
config.load(); config.load();
history.loadPID(); history.loadPID();
@ -118,7 +286,7 @@ void setupWiFi() {
// Connect WiFi for OTA // Connect WiFi for OTA
if (config.ssid[0] && config.pw[0]) { if (config.ssid[0] && config.pw[0]) {
esp_wifi_set_max_tx_power(74); 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); DPRINTF("BOOT: Connecting to WiFi: SSID: '%s', PW: '%s'\n", config.ssid, config.pw);
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.begin(config.ssid, config.pw); WiFi.begin(config.ssid, config.pw);
@ -163,7 +331,7 @@ void setupPostWiFi(bool bBoot = false) {
DPRINTLN("Setup - TimeManager.begin()"); DPRINTLN("Setup - TimeManager.begin()");
DPRINTLN("\n===============================\n"); DPRINTLN("\n===============================\n");
DPRINTLN(" Trying OTA"); DPRINTLN(" Trying OTA");
ui.message(2, (char *) "Update check..."); ui.message(2, (char *) "Update...");
ledcWrite(PIN_LED_WIFI, PWM_FULL / 20); ledcWrite(PIN_LED_WIFI, PWM_FULL / 20);
checkOTA(true); checkOTA(true);
ledcWrite(PIN_LED_WIFI, PWM_FULL * 39 / 40); ledcWrite(PIN_LED_WIFI, PWM_FULL * 39 / 40);
@ -185,13 +353,7 @@ void setupPostWiFi(bool bBoot = false) {
} }
} }
void setupPins() { void setupPWM() {
// --- Basic Digital Pin Initialization ---
pinMode(PIN_HEATER1, OUTPUT);
pinMode(PIN_HEATER2, OUTPUT);
digitalWrite(PIN_HEATER1, HEATER_OFF);
digitalWrite(PIN_HEATER2, HEATER_OFF);
// --- 1. High Speed Group: Motor and Fan (~26kHz) --- // --- 1. High Speed Group: Motor and Fan (~26kHz) ---
// Core 2.0.17 uses APB (80MHz). 80MHz / (3 * 1024) ≈ 26kHz. // Core 2.0.17 uses APB (80MHz). 80MHz / (3 * 1024) ≈ 26kHz.
ledcAttachChannel(PIN_MOTOR, PWM_26KHZ_FREQ, PWM_RESOLUTION, PWM_MOTOR_CHANNEL); 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/FreeSans12pt7b.h>
#include <Fonts/FreeSans9pt7b.h> #include <Fonts/FreeSans9pt7b.h>
#include "driver/gpio.h"
#define TAG_UI "UI" #define TAG_UI "UI"
// Buttons // Buttons
#define DEBOUNCE_DELAY 100 #define DEBOUNCE_DELAY 100
@ -210,12 +212,6 @@ const bool fineControl[] = {
true }; true };
//
// Buttons
//
void buttonSetISR();
void buttonUpISR();
void buttonDownISR();
// Constructor for CUI class // 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 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 boxD0 = {POS_X_D0, POS_Y_BOTTOM - HEIGHT_D0, WIDTH_D0, HEIGHT_D0}; // 17 + 2
//
// Buttons // 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(); initButtonState();
} }
@ -1071,7 +1058,7 @@ void CUI::checkButtonStates(unsigned long currentMillis) {
if (bButtonSetChanged) { if (bButtonSetChanged) {
// Compare with the last interrupt time to ensure debounce delay // Compare with the last interrupt time to ensure debounce delay
if (currentMillis - buttonSetChangeTime > 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 // Button pressed
buttonSetDownTime = buttonSetChangeTime; buttonSetDownTime = buttonSetChangeTime;
bButtonSetDown = true; bButtonSetDown = true;
@ -1092,7 +1079,7 @@ void CUI::checkButtonStates(unsigned long currentMillis) {
if (bButtonUpChanged) { if (bButtonUpChanged) {
// Compare with the last interrupt time to ensure debounce delay // Compare with the last interrupt time to ensure debounce delay
if (currentMillis - buttonUpChangeTime > 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 // Button pressed
buttonUpDownTime = buttonUpChangeTime; buttonUpDownTime = buttonUpChangeTime;
bButtonUpDown = true; bButtonUpDown = true;
@ -1113,7 +1100,7 @@ void CUI::checkButtonStates(unsigned long currentMillis) {
if (bButtonDownChanged) { if (bButtonDownChanged) {
// Compare with the last interrupt time to ensure debounce delay // Compare with the last interrupt time to ensure debounce delay
if (currentMillis - buttonDownChangeTime > 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 // Button pressed
buttonDownDownTime = buttonDownChangeTime; buttonDownDownTime = buttonDownChangeTime;
bButtonDownDown = true; bButtonDownDown = true;
@ -1133,20 +1120,20 @@ void CUI::checkButtonStates(unsigned long currentMillis) {
} }
// ISR for the Set button handling // 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 // Record the time of the button interrupt and set a flag
ui.buttonSetChangeTime = millis(); ui.buttonSetChangeTime = 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() { void IRAM_ATTR buttonUpISR(void *) {
ui.buttonUpChangeTime = millis(); ui.buttonUpChangeTime = 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() { void IRAM_ATTR buttonDownISR(void *) {
ui.buttonDownChangeTime = millis(); ui.buttonDownChangeTime = millis();
ui.bButtonDownChanged = true; // Flag for main loop to process ui.bButtonDownChanged = true; // Flag for main loop to process
} }

10
UI.h
View File

@ -98,6 +98,14 @@ private:
void checkButtonStates(unsigned long tickMillis); 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; 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_pDataReceive_data = (char *) data;
m_nDataReceive_size = size; m_nDataReceive_size = size;
m_nDataReceive_received = 0; m_nDataReceive_received = 0;
#ifdef ESP8266
digitalWrite(PIN_EXTRA, LED_ON);
#endif
return size; return size;
} }

View File

@ -27,6 +27,8 @@
#include "mbedtls/aes.h" #include "mbedtls/aes.h"
#include <WiFi.h> #include <WiFi.h>
#define TAG_FW "FW Update" #define TAG_FW "FW Update"
// GPIO Headers
#include "driver/gpio.h"
#elif defined(ESP8266) #elif defined(ESP8266)
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
@ -348,7 +350,7 @@ void ESPUpdateClass::_reset() {
_command = U_FLASH; _command = U_FLASH;
if (_ledPin != -1) { 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) { if (_ledPin != -1) {
pinMode(_ledPin, OUTPUT); gpio_set_direction((gpio_num_t)_ledPin, GPIO_MODE_OUTPUT);
} }
while (remaining()) { while (remaining()) {
if (_ledPin != -1) { if (_ledPin != -1) {
digitalWrite(_ledPin, _ledOn); gpio_set_level((gpio_num_t)_ledPin, !_ledOn);
} }
size_t bytesToRead = SPI_FLASH_SEC_SIZE - _bufferLen; size_t bytesToRead = SPI_FLASH_SEC_SIZE - _bufferLen;
if (bytesToRead > remaining()) { if (bytesToRead > remaining()) {
@ -802,7 +804,7 @@ size_t ESPUpdateClass::writeStream(Stream &data) {
} }
if (_ledPin != -1) { if (_ledPin != -1) {
digitalWrite(_ledPin, !_ledOn); gpio_set_level((gpio_num_t)_ledPin, !_ledOn);
} }
_bufferLen += toRead; _bufferLen += toRead;
if ((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer()) { if ((_bufferLen == remaining() || _bufferLen == SPI_FLASH_SEC_SIZE) && !_writeBuffer()) {

231
zcd.cpp
View File

@ -8,48 +8,15 @@
// Timer Headers // Timer Headers
#include "hal/timer_ll.h" #include "hal/timer_ll.h"
#include "hal/timer_types.h" #include "hal/timer_types.h"
#include "driver/timer.h" // Needed for timer_isr_register
#include "rom/ets_sys.h" #include "rom/ets_sys.h"
// GPIO Headers
#include "driver/gpio.h" #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_LEVEL3 (1<<3)
#define ESP_INTR_FLAG_LEVEL1 (1<<1) #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 zcdACCount;
volatile uint8_t zcdLoadCount; volatile uint8_t zcdLoadCount;
volatile uint8_t ac1ControlMode = PHASE_CONTROL; volatile uint8_t ac1ControlMode;
volatile uint8_t ac2ControlMode = PHASE_CONTROL; volatile uint8_t ac2ControlMode;
volatile uint8_t fireStatusTimer1 = 0; volatile uint8_t fireStatusTimer0;
volatile uint8_t fireStatusTimer2 = 0; volatile uint8_t fireStatusTimer1;
timg_dev_t *tg0;
timg_dev_t *tg1;
hw_timer_t *timer10K; //hw_timer_t *timer10K;
hw_timer_t *timerDummy; //hw_timer_t *timerDummy;
hw_timer_t *timerHeater1; //hw_timer_t *timerHeater1;
hw_timer_t *timerHeater2; //hw_timer_t *timerHeater2;
const char fireTable[17][16] { const char fireTable[17][16] {
{0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}, // 0 0% {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 zcdACISRCount = 0;
volatile uint8_t zcdLoadISRCount = 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 setAC1ControlMode(uint8_t mode) { ac1ControlMode = mode; }
void setAC2ControlMode(uint8_t mode) { ac2ControlMode = 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) // 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 (ac1ControlMode == ZCD_CONTROL) {
if (duty > 10000) duty = 10000; if (duty > 10000) duty = 10000;
dutyAC1TableIndex = (uint8_t)((duty + 10000/32)/625); 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) // 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 (config.bAC2_OnOff) {
if (duty >= 10000) { if (duty >= 10000) {
digitalWrite(PIN_HEATER2, HEATER_ON);
duty = 10000; duty = 10000;
dutyHeater2 = LEADING_PULSE_COUNT;
} else { } else {
digitalWrite(PIN_HEATER2, HEATER_OFF);
duty = 0; duty = 0;
dutyHeater2 = 0; // If 0% duty, no pulse (turn off TRIAC)
} }
dutyHeater2 = 0;
} else { } else {
if (ac2ControlMode == ZCD_CONTROL) { if (ac2ControlMode == ZCD_CONTROL) {
if (duty > 10000) duty = 10000; 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); 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() { #define SET_TIMER_1_SAFE(duty) do { \
if (fireStatusTimer1 == 0) { timerWrite(timerHeater2, 0); \
// First Trigger: Turn ON timerAlarm(timerHeater2, duty, false, 0); \
REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER1 - 32))); } while(0)
fireStatusTimer1 = 1;
SET_TIMER_1_SAFE(18); // Schedule OFF pulse 8us later void IRAM_ATTR timer0ISR(void *) {
} else { #ifdef DEBUG_ZCD
// Second Trigger: Turn OFF zcdLoadISRCount++;
REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER1 - 32))); #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() { void IRAM_ATTR timer1ISR(void *)
if (fireStatusTimer2 == 0) { {
REG_WRITE(GPIO_OUT1_W1TS_REG, (1UL << (PIN_HEATER2 - 32))); //timer_group_clr_intr_status_in_isr(TIMER_GROUP_1, TIMER_1);
fireStatusTimer2 = 1; TIMERG1.int_clr_timers.t1_int_clr = 1;
SET_TIMER_2_SAFE(18); if (fire_enable_2) {
} else { if (fireStatusTimer1 == 0) {
REG_WRITE(GPIO_OUT1_W1TC_REG, (1UL << (PIN_HEATER2 - 32))); 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 // Zero-Cross Detection Interrupt Service Routine
void ARDUINO_ISR_ATTR zcdACISR() { void IRAM_ATTR zcdACISR(void *) {
// 1. Power side AC ZCD Count // 1. Power side AC ZCD Count
zcdACISRCount++; zcdACISRCount++;
fireStatusTimer0 = 0;
fireStatusTimer1 = 0; fireStatusTimer1 = 0;
fireStatusTimer2 = 0;
// 3. Heater 1 // 3. Heater 1
if (ac1ControlMode == ZCD_CONTROL) { 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){ } 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 // 4. Heater 2
if (ac2ControlMode == ZCD_CONTROL) { 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) { } 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; seqStep = ++seqStep & 0x0F;
} }
void ARDUINO_ISR_ATTR zcdLoadISR() { void IRAM_ATTR zcdLoadISR(void *) {
// Load side AC ZCD Count // Load side AC ZCD Count
#ifndef DEBUG_ZCD
zcdLoadISRCount++; zcdLoadISRCount++;
#endif
} }
void setupZCD() { void setupZCD() {
periph_module_enable(PERIPH_TIMG0_MODULE); //===============================================================================
periph_module_enable(PERIPH_TIMG1_MODULE); // Initialize variables
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);
dutyHeater1 = 0; // Calculated timerHeater1 count for TRIAC firing dutyHeater1 = 0; // Calculated timerHeater1 count for TRIAC firing
dutyHeater2 = 0; // Calculated timerZCD count for TRIAC firing dutyHeater2 = 0; // Calculated timerZCD count for TRIAC firing
zcdACCount = 0; zcdACCount = 0;
zcdLoadCount = 0; zcdLoadCount = 0;
timerHeater1 = NULL;
// Test // Test
config.ac1ControlMode = PHASE_CONTROL; config.ac1ControlMode = PHASE_CONTROL;
config.ac2ControlMode = PHASE_CONTROL; config.ac2ControlMode = PHASE_CONTROL;
fireStatusTimer0 = 0;
fireStatusTimer1 = 0;
tg0 = &TIMERG0;
tg1 = &TIMERG1;
ac1ControlMode = config.ac1ControlMode; ac1ControlMode = config.ac1ControlMode;
ac2ControlMode = config.ac2ControlMode; 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) { void setACLoadStatus(uint32_t tNow) {

10
zcd.h
View File

@ -6,7 +6,17 @@ void setupZCD();
void setHeater1Duty(short duty); void setHeater1Duty(short duty);
void setHeater2Duty(short duty); void setHeater2Duty(short duty);
short getHeater1Duty(); 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) #if defined(ESP8266)
void setMistDuty(short duty); void setMistDuty(short duty);
#endif #endif
#endif #endif