Worked on ESP32 dimmer with Zero cross (#18481)

* Worked on ESP32 dimmer with Zero cross

Until now the ESP32 does not support zero-cross dimmer. I take a sneak how they did in in ESPhome and adapted the approach to TASMOTA. At the end it works that smooth that likely i will change ESP8266 either so we have a common code. Currently ESP8266 is not touched.
There is a minor issue with savedata == default. When changing the dimmer value the interrupts get stopped during write of the config data to flash.

* ESP8266 Dimmer added

Worked all so well and the code is much smaller. There is no need for reconfiguration on existing users. But there are settings not needed anymore. Will work on the documentation. Anyhow existing installations can upgrade without hickup

* Optimized endpoints at dimmer 0 and 100

* Removed debug stuff

* Fix Issue at dimmer = 0

* Small bugfix

* Final checked Version

* Update xsns_01_counter.ino

* Add missing func

* Update xsns_01_counter.ino

* Moved out of the house of counter and build my own one

* New ZeroCross Driver

* Update xdrv_91_zerocrossDimmer.ino

* evolving

* Delete xdrv_91_zerocrossDimmer.ino

* Add files via upload

* Changed drv number from 1 to 68

* Commit to merge
This commit is contained in:
stefanbode 2023-04-25 13:46:19 +02:00 committed by GitHub
parent fba15dea71
commit 39abde2583
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 280 additions and 134 deletions

View File

@ -45,6 +45,7 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack
extern "C" void resetPins();
extern "C" int startWaveformClockCycles(uint8_t pin, uint32_t highCcys, uint32_t lowCcys,
uint32_t runTimeCcys, int8_t alignPhase, uint32_t phaseOffsetCcys, bool autoPwm);
extern "C" void setTimer1Callback(uint32_t (*fn)());
#ifdef USE_SERIAL_BRIDGE
void SerialBridgePrintf(PGM_P formatP, ...);
#endif

View File

@ -40,7 +40,7 @@ const gamma_table_t ac_dimmer_table[] = { // don't put in PROGMEM for performa
{ 900, 704 },
{ 950, 748 },
{ 990, 850 },
{ 1024, 1024 },
{ 1023, 1023 },
{ 0xFFFF, 0xFFFF } // fail-safe if out of range
};

View File

@ -0,0 +1,276 @@
/*
xdrv_68_zerocrossdimmer.ino - Zero-Cross Dimmer support for Tasmota
Copyright (C) 2023 Stefan Bode
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_AC_ZERO_CROSS_DIMMER
/*********************************************************************************************\
* Zero-Cross AC Dimmer PMM 1..xx use
\*********************************************************************************************/
#define XDRV_68 68
static const uint32_t GATE_ENABLE_TIME = 100;
struct AC_ZERO_CROSS_DIMMER {
uint32_t cycle_time_us;
/// Time (in micros()) of last ZC signal
uint32_t crossed_zero_at;
/// Time since last ZC pulse to enable gate pin. 0 means not set.
bool timer_iterrupt_started = false;
bool dimmer_in_use = false;
// Check if 50µs timer is running.
uint32_t enable_time_us[MAX_PWMS];
/// Time since last ZC pulse to disable gate pin. 0 means no disable.
uint32_t disable_time_us[MAX_PWMS];
uint8_t current_state_in_phase[MAX_PWMS]; // 0=before fire HIGH, 1=HIGH, 2=after setting LOW, 3=before HIGH without setting LOW (POWER ON)
uint32_t lastlight[MAX_PWMS];
uint16_t detailpower[MAX_PWMS]; // replaces dimmer and light controll 0..10000. required savedata 0.
uint32_t intr_counter = 0;
} ac_zero_cross_dimmer;
#ifdef ESP32
static hw_timer_t *dimmer_timer = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
#endif
#define D_PRFX_ZCDIMMER "ZCDimmer"
#define D_CMND_DIMMERSET "Set"
const char kZCDimmerCommands[] PROGMEM = D_PRFX_ZCDIMMER "|" D_CMND_DIMMERSET;
void (* const ZCDimmerCommand[])(void) PROGMEM = {
&CmndZCDimmerSet
};
void IRAM_ATTR ACDimmerZeroCross(uint32_t time) {
ac_zero_cross_dimmer.dimmer_in_use = false;
ac_zero_cross_dimmer.cycle_time_us = time - ac_zero_cross_dimmer.crossed_zero_at;
ac_zero_cross_dimmer.crossed_zero_at = time;
for (uint8_t i=0; i < MAX_PWMS; i++) {
if (Pin(GPIO_PWM1, i) == -1) continue;
ac_zero_cross_dimmer.dimmer_in_use |= ac_zero_cross_dimmer.lastlight[i] > 0;
// Dimmer is physically off. Skip swich on
ac_zero_cross_dimmer.current_state_in_phase[i] = 0;
if (100 * ac_zero_cross_dimmer.enable_time_us[i] > 95 * ac_zero_cross_dimmer.cycle_time_us ) {
ac_zero_cross_dimmer.current_state_in_phase[i] = 1;
ac_zero_cross_dimmer.disable_time_us[i] = ac_zero_cross_dimmer.cycle_time_us / 2;
}
// If full cycle is required keep pin HIGH, skip LOW by skipping phase
if (100 * ac_zero_cross_dimmer.enable_time_us[i] < 15 * ac_zero_cross_dimmer.cycle_time_us) {
ac_zero_cross_dimmer.current_state_in_phase[i] = 3;
}
}
}
uint32_t IRAM_ATTR ACDimmerTimer_intr_ESP8266() {
//ACDimmerTimer_intr();
ACDimmerTimer_intr();
return 4000;
}
void ACDimmerInterruptDisable(bool disable)
{
AddLog(LOG_LEVEL_INFO, PSTR("ZCD: Zero-CrossDimmer enabled: %d"),!disable);
ac_zero_cross_dimmer.timer_iterrupt_started = !disable;
if (disable) {
//stop the interrupt
#ifdef ESP32
if (dimmer_timer != nullptr) {
timerAlarmDisable(dimmer_timer);
}
#endif
#ifdef ESP8266
//setTimer1Callback(NULL);
#endif
} else {
for (uint8_t i = 0 ; i < MAX_PWMS; i++) {
if (Pin(GPIO_PWM1, i) != -1) {
pinMode(Pin(GPIO_PWM1, i), OUTPUT);
AddLog(LOG_LEVEL_INFO, PSTR("ZCD: Zero-CrossDimmer Pin %d set"),Pin(GPIO_PWM1, i));
}
}
#ifdef ESP32
if (dimmer_timer == nullptr) {
// 80 Divider -> 1 count=1µs
dimmer_timer = timerBegin(0, 80, true);
timerAttachInterrupt(dimmer_timer, &ACDimmerTimer_intr, true);
// For ESP32, we can't use dynamic interval calculation because the timerX functions
// are not callable from ISR (placed in flash storage).
// Here we just use an interrupt firing every 75 µs.
if (Settings->save_data == 0) {
AddLog(LOG_LEVEL_INFO, PSTR("ZCD: Save disabled. High frequency scan enabled. DO NOT USE SAVEDATA if channel is on"));
timerAlarmWrite(dimmer_timer, 30, true);
} else {
AddLog(LOG_LEVEL_INFO, PSTR("ZCD: Save on. 75µs scan enabled"));
timerAlarmWrite(dimmer_timer, 75, true);
}
}
timerAlarmEnable(dimmer_timer);
#endif
#ifdef ESP8266
// Uses ESP8266 waveform (soft PWM) class
// PWM and AcDimmer can even run at the same time this way
//setTimer1Callback(&ACDimmerTimer_intr_ESP8266);
#endif
}
}
void IRAM_ATTR ACDimmerTimer_intr() {
// If no ZC signal received yet.
uint32_t now = micros();
ac_zero_cross_dimmer.intr_counter++;
if (ac_zero_cross_dimmer.crossed_zero_at == 0)
return;
uint32_t time_since_zc = now - ac_zero_cross_dimmer.crossed_zero_at;
if (time_since_zc > 10100) {
memset(&ac_zero_cross_dimmer.current_state_in_phase, 0x00, sizeof(ac_zero_cross_dimmer.current_state_in_phase));
ac_zero_cross_dimmer.crossed_zero_at += ac_zero_cross_dimmer.cycle_time_us;
time_since_zc = now - ac_zero_cross_dimmer.crossed_zero_at;
}
for (uint8_t i = 0 ; i < MAX_PWMS; i++ ) {
if (Pin(GPIO_PWM1, i) == -1) continue;
switch (ac_zero_cross_dimmer.current_state_in_phase[i]) {
case 1:
if (time_since_zc >= ac_zero_cross_dimmer.disable_time_us[i]) {
digitalWrite(Pin(GPIO_PWM1, i), LOW);
ac_zero_cross_dimmer.current_state_in_phase[i]++;
}
break;
case 0:
case 3:
if (time_since_zc >= ac_zero_cross_dimmer.enable_time_us[i]) {
digitalWrite(Pin(GPIO_PWM1, i), HIGH);
ac_zero_cross_dimmer.current_state_in_phase[i]++;
}
break;
}
}
}
void ACDimmerControllTrigger(void) {
if (ac_zero_cross_dimmer.timer_iterrupt_started != ac_zero_cross_dimmer.dimmer_in_use) {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ZCD: ZeroEnable %d --> %d ... change..."),ac_zero_cross_dimmer.timer_iterrupt_started, ac_zero_cross_dimmer.dimmer_in_use);
ACDimmerInterruptDisable(!ac_zero_cross_dimmer.dimmer_in_use);
}
for (uint8_t i = 0; i < MAX_PWMS; i++){
if (Pin(GPIO_PWM1, i) == -1) continue;
ac_zero_cross_dimmer.lastlight[i] = Light.fade_running ? Light.fade_cur_10[i] : Light.fade_start_10[i];
ac_zero_cross_dimmer.enable_time_us[i] = (ac_zero_cross_dimmer.cycle_time_us * (1023 - ac_zero_cross_power(ac_zero_cross_dimmer.lastlight[i]))) / 1023;
#ifdef ESP32
if (ac_zero_cross_dimmer.detailpower[i]){
float state = (float)(1 - (ac_zero_cross_dimmer.detailpower[i]/10000.0));
//state = std::acos(1 - (2 * state)) / 3.14159 * ac_zero_cross_dimmer.cycle_time_us;
state = std::acos(1 - (2 * state)) / 3.14159 * 10000;
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ZCD: Float2: %*_f"),0,&state);
ac_zero_cross_dimmer.enable_time_us[i] = (uint32_t)state;
ac_zero_cross_dimmer.lastlight[i] = 1;
}
#endif
ac_zero_cross_dimmer.disable_time_us[i] = ac_zero_cross_dimmer.enable_time_us[i] + GATE_ENABLE_TIME;
}
}
void ACDimmerLogging(void)
{
bool alarmEnabled = false;
uint32_t timercounter = ac_zero_cross_dimmer.intr_counter;
#ifdef ESP32
if (dimmer_timer != nullptr) {
alarmEnabled = timerAlarmEnabled(dimmer_timer);
timercounter = (uint32_t)timerRead(dimmer_timer);
}
#endif
AddLog(LOG_LEVEL_DEBUG, PSTR("ZCD: ZeroEnable %d -> %d, Alarm %d, intr: %ld, cycle time: %ld µs"),
ac_zero_cross_dimmer.dimmer_in_use, ac_zero_cross_dimmer.timer_iterrupt_started, alarmEnabled, timercounter, ac_zero_cross_dimmer.cycle_time_us
);
for (uint8_t i = 0; i < MAX_PWMS; i++){
if (Pin(GPIO_PWM1, i) == -1) continue;
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ZCD: PWM[%d] en: %ld µs, dis: %ld µs, state %d, fade: %d, cur: %d, end: %d, lastlight: %d"),
i+1, ac_zero_cross_dimmer.enable_time_us[i], ac_zero_cross_dimmer.disable_time_us[i],
ac_zero_cross_dimmer.current_state_in_phase[i], Light.fade_cur_10[i], Light.fade_start_10[i], Light.fade_end_10[i], ac_zero_cross_dimmer.lastlight[i]
);
}
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
void CmndZCDimmerSet(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
if (XdrvMailbox.data_len > 0) {
ac_zero_cross_dimmer.detailpower[XdrvMailbox.index-1] = (uint16_t)(100 * CharToFloat(XdrvMailbox.data));
}
ResponseCmndIdxFloat((float)(ac_zero_cross_dimmer.detailpower[XdrvMailbox.index-1]) / 100, 2);
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv68(uint32_t function)
{
bool result = false;
if (Settings->flag4.zerocross_dimmer) {
switch (function) {
case FUNC_INIT:
#ifdef ESP32
//ACDimmerInterruptDisable(false);
#endif
#ifdef ESP8266
setTimer1Callback(&ACDimmerTimer_intr_ESP8266);
#endif
break;
case FUNC_EVERY_SECOND:
ACDimmerLogging();
break;
case FUNC_EVERY_100_MSECOND:
ACDimmerControllTrigger();
break;
case FUNC_INTERRUPT_STOP:
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ZCD: FUNC_INTERRUPT_STOP"));
ACDimmerInterruptDisable(true);
break;
case FUNC_INTERRUPT_START:
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ZCD: FUNC_INTERRUPT_START"));
ACDimmerInterruptDisable(false);
break;
case FUNC_COMMAND:
result = DecodeCommand(kZCDimmerCommands, ZCDimmerCommand);
//result = DecodeCommand(kShutterCommands, ShutterCommand);
break;
}
}
return result;
}
#endif // USE_AC_ZERO_CROSS_DIMMER

View File

@ -2,7 +2,6 @@
xsns_01_counter.ino - Counter sensors (water meters, electricity meters etc.) sensor support for Tasmota
Copyright (C) 2021 Maarten Damen and Theo Arends
Stefan Bode (Zero-Cross Dimmer)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -48,22 +47,6 @@ struct COUNTER {
} Counter;
#ifdef USE_AC_ZERO_CROSS_DIMMER
struct AC_ZERO_CROSS_DIMMER {
bool startReSync = false; // set to TRUE if zero-cross event occurs
bool startMeasurePhase[MAX_COUNTERS] ; // set to TRUE if channel is ON and zero-cross occurs to initiate phase measure on channel
bool pwm_defined[MAX_COUNTERS]; // check if all GPIO are set and zerocross enabled. Then ADD dimmer.
bool PWM_ON[MAX_COUNTERS] ; // internal ON/OFF of the channel
uint32_t current_cycle_ClockCycles = 0; // amount of clock cycles between two zero-cross events.
uint32_t currentPWMCycleCount[MAX_COUNTERS] ; // clock cycle time of PWM channel, required to measure actual phase. [3] is phase of zero-cross
int16_t currentShiftClockCycle[MAX_COUNTERS]; // dynamic phase correction per channel in clock cycles
uint32_t tobe_cycle_timeClockCycles = 0; // clock cycles between zero-cross events. Depend on main frequency and CPU speed
uint32_t lastCycleCount = 0; // Last value of GetCycleCount during zero-cross sychronisation
uint32_t currentSteps = 100; // dynamic value of zero-crosses between two sychronisation intervalls (default=20 == 200ms at 100Hz)
uint32_t high; // cycle counts for PWM high vaule. needs long enough (4µs) to secure fire TRIAC
} ac_zero_cross_dimmer;
#endif //USE_AC_ZERO_CROSS_DIMMER
void IRAM_ATTR CounterIsrArg(void *arg) {
uint32_t index = *static_cast<uint8_t*>(arg);
@ -93,27 +76,7 @@ void IRAM_ATTR CounterIsrArg(void *arg) {
// restart PWM each second (german 50Hz has to up to 0.01% deviation)
// restart initiated by setting Counter.startReSync = true;
#ifdef USE_AC_ZERO_CROSS_DIMMER
// if zero-cross events occur ond channel is on. phase on PWM must be measured
if ( ac_zero_cross_dimmer.startMeasurePhase[index] == true ) {
ac_zero_cross_dimmer.currentPWMCycleCount[index] = ESP.getCycleCount();
ac_zero_cross_dimmer.startMeasurePhase[index] = false;
}
// if zero-cross event occurs (200ms window, 5-times a second) and device is online for >10sec
if (index == 3 && RtcSettings.pulse_counter[index]%(Settings->pwm_frequency / 5) == 0 && ac_zero_cross_dimmer.pwm_defined[index] && millis() > 10000) {
ac_zero_cross_dimmer.currentPWMCycleCount[index] = ESP.getCycleCount();
if (ac_zero_cross_dimmer.lastCycleCount > 0) {
// start phase measure on PWM channels and initiate phase sync with zero-cross.
ac_zero_cross_dimmer.startReSync = true;
for (uint8_t k=0; k < MAX_COUNTERS-1; k++ ) {
if (ac_zero_cross_dimmer.PWM_ON[k] == true) ac_zero_cross_dimmer.startMeasurePhase[k] = true;
}
ac_zero_cross_dimmer.currentSteps = (ac_zero_cross_dimmer.currentPWMCycleCount[index]-ac_zero_cross_dimmer.lastCycleCount+(ac_zero_cross_dimmer.tobe_cycle_timeClockCycles/2))/(ac_zero_cross_dimmer.tobe_cycle_timeClockCycles);
ac_zero_cross_dimmer.current_cycle_ClockCycles = (ac_zero_cross_dimmer.currentPWMCycleCount[index]-ac_zero_cross_dimmer.lastCycleCount)/ac_zero_cross_dimmer.currentSteps;
}
ac_zero_cross_dimmer.lastCycleCount = ac_zero_cross_dimmer.currentPWMCycleCount[index];
}
if (index == 3) ACDimmerZeroCross(time);
#endif //USE_AC_ZERO_CROSS_DIMMER
return;
}
@ -162,26 +125,9 @@ bool CounterPinState(void)
void CounterInit(void)
{
for (uint32_t i = 0; i < MAX_COUNTERS; i++) {
if (PinUsed(GPIO_CNTR1, i)) {
#ifdef USE_AC_ZERO_CROSS_DIMMER
if (Settings->flag4.zerocross_dimmer) {
ac_zero_cross_dimmer.current_cycle_ClockCycles = ac_zero_cross_dimmer.tobe_cycle_timeClockCycles = microsecondsToClockCycles(1000000 / Settings->pwm_frequency);
// short fire on PWM to ensure not to hit next sinus curve but trigger the TRIAC. 0.78% of duty cycle (10ms) ~4µs
ac_zero_cross_dimmer.high = ac_zero_cross_dimmer.current_cycle_ClockCycles / 256;
// Support for dimmer 1-3. Counter4 reseverd for zero-cross signal
if ((i < MAX_COUNTERS-1 && PinUsed(GPIO_PWM1, i)) || ( i == MAX_COUNTERS-1) ) {
ac_zero_cross_dimmer.pwm_defined[i] = true;
if (i == 3) {
AddLog(LOG_LEVEL_INFO, PSTR("ZeroCross initialized"));
} else {
AddLog(LOG_LEVEL_INFO, PSTR("Dimmer: [%d] initialized. READY. Dimmer %d"), i+1, Light.fade_running ? Light.fade_cur_10[i] : Light.fade_start_10[i]);
}
}
}
#endif //USE_AC_ZERO_CROSS_DIMMER
Counter.any_counter = true;
pinMode(Pin(GPIO_CNTR1, i), bitRead(Counter.no_pullup, i) ? INPUT : INPUT_PULLUP);
if ((0 == Settings->pulse_counter_debounce_low) && (0 == Settings->pulse_counter_debounce_high) && !Settings->flag4.zerocross_dimmer) {
@ -260,78 +206,6 @@ void CounterShow(bool json)
}
}
#ifdef USE_AC_ZERO_CROSS_DIMMER
void SyncACDimmer(void)
{
if (ac_zero_cross_dimmer.startReSync ) {
// currently only support one AC Dimmer PWM. Plan to support up to 4 Dimmer on same Phase.
for (uint32_t i = 0; i < MAX_COUNTERS-1; i++) {
if (Light.fade_start_10[i] == 0 && Light.fade_cur_10[i] == 0 && ac_zero_cross_dimmer.PWM_ON[i]==false ) continue;
if (ac_zero_cross_dimmer.pwm_defined[i] && (ac_zero_cross_dimmer.startMeasurePhase[i] == 0 || ac_zero_cross_dimmer.PWM_ON[i] == false ) )
{
uint32_t phaseStart_ActualClockCycles; // As-Is positon of PWM after Zero Cross
uint32_t phaseStart_ToBeClockCycles; // To be position after zero-cross to fire PWM start
int16_t phaseShift_ClockCycles; //
// reset trigger for PWM sync
ac_zero_cross_dimmer.startReSync = false;
// calculate timeoffset to fire PWM based on Dimmer
phaseStart_ToBeClockCycles = (ac_zero_cross_dimmer.tobe_cycle_timeClockCycles * (1024 - ac_zero_cross_power(Light.fade_running ? Light.fade_cur_10[i] : Light.fade_start_10[i]))) / 1024;
// Limit range to avoid overshoot and undershoot
phaseStart_ToBeClockCycles = tmin(tmax(phaseStart_ToBeClockCycles, 160000), 0.95* ac_zero_cross_dimmer.tobe_cycle_timeClockCycles);
// Switch OFF dimmer
if (Light.fade_start_10[i] == 0 && !Light.fade_running) {
ac_zero_cross_dimmer.PWM_ON[i]=false;
Light.fade_cur_10[i] = 0;
digitalWrite(Pin(GPIO_PWM1, i), LOW);
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("CNT2: [%d], curr: %d, final: %d, fading: %d, phase-shift: %d, ON/OFF: %d"),i, Light.fade_cur_10[i], Light.fade_start_10[i], Light.fade_running, phaseStart_ToBeClockCycles,ac_zero_cross_dimmer.PWM_ON[i]);
continue;
}
// Calculyte clockcycles between zero-cross [3] and start of the current PWM signal [i]
phaseStart_ActualClockCycles = ac_zero_cross_dimmer.currentPWMCycleCount[i]-ac_zero_cross_dimmer.currentPWMCycleCount[3];
// Calulate additional or less clockcycles to move current phase position to should be position
phaseShift_ClockCycles = (int32_t)((int32_t)phaseStart_ToBeClockCycles-(int32_t)phaseStart_ActualClockCycles)/100;
if ( ac_zero_cross_dimmer.PWM_ON[i] == 0 ) {
// because in LOOP calculate the timelag to fire PWM correctly with zero-cross
uint32_t timelag_ClockCycles = (ESP.getCycleCount() - ac_zero_cross_dimmer.currentPWMCycleCount[3])%ac_zero_cross_dimmer.tobe_cycle_timeClockCycles;
timelag_ClockCycles = ((phaseStart_ToBeClockCycles + ac_zero_cross_dimmer.tobe_cycle_timeClockCycles) - timelag_ClockCycles)%ac_zero_cross_dimmer.tobe_cycle_timeClockCycles;
delayMicroseconds(clockCyclesToMicroseconds(timelag_ClockCycles));
ac_zero_cross_dimmer.PWM_ON[i]=true;
pinMode(Pin(GPIO_PWM1, i), OUTPUT);
} else {
// currentShiftClockCycle is an I-Controller (not PID) to realign the phase. grace time are 5 clock cycles
ac_zero_cross_dimmer.currentShiftClockCycle[i] += phaseShift_ClockCycles > 5 ? 1 : (phaseShift_ClockCycles < -5 ? -1 : 0);
ac_zero_cross_dimmer.current_cycle_ClockCycles += ac_zero_cross_dimmer.currentShiftClockCycle[i]+phaseShift_ClockCycles;
}
#ifdef ESP8266
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t
startWaveformClockCycles(Pin(GPIO_PWM1, i), ac_zero_cross_dimmer.high, ac_zero_cross_dimmer.current_cycle_ClockCycles - ac_zero_cross_dimmer.high, 0, -1, 0, true);
#endif // ESP8266
#ifdef ESP32
// Under investigation. Still not working
double esp32freq = 1000000.0 / clockCyclesToMicroseconds(ac_zero_cross_dimmer.current_cycle_ClockCycles);
ledcSetup(i, esp32freq, 10);
ledcAttachPin(Pin(GPIO_PWM1, i), i);
ledcWrite(i, 5);
#endif // ESP32
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("CNT: [%d], shift: %d, dimm_time_CCs %d, phaseShift_CCs %d, currentPWMcylce: %lu, current_cycle_CC: %lu, lastcc %lu, currentSteps %lu, currDIM %lu, last delta:%lu"),
i, ac_zero_cross_dimmer.currentShiftClockCycle[i], phaseStart_ToBeClockCycles,phaseShift_ClockCycles,ac_zero_cross_dimmer.currentPWMCycleCount[i],ac_zero_cross_dimmer.current_cycle_ClockCycles , ac_zero_cross_dimmer.lastCycleCount, ac_zero_cross_dimmer.currentSteps, Light.fade_cur_10[i],phaseStart_ActualClockCycles); // Light fading
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("CNT: [%d], curr: %d, final: %d, fading: %d, phase-shift: %d, ON/OFF: %d"),i, Light.fade_cur_10[i], Light.fade_start_10[i], Light.fade_running, phaseStart_ToBeClockCycles,ac_zero_cross_dimmer.PWM_ON[i]);
} // do sync onchannel
} // loop on counter
} // zero cross detected
} // end SyncACDimmer
#endif //USE_AC_ZERO_CROSS_DIMMER
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
@ -406,11 +280,6 @@ bool Xsns01(uint32_t function)
case FUNC_JSON_APPEND:
CounterShow(1);
break;
#ifdef USE_AC_ZERO_CROSS_DIMMER
case FUNC_EVERY_50_MSECOND:
SyncACDimmer();
break;
#endif //USE_AC_ZERO_CROSS_DIMMER
#ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR:
CounterShow(0);