mirror of https://github.com/arendst/Tasmota.git
AC-Zero-Cross Dimmer Enhancements
- Separated PWM control from the interrupt handler - #9040 , #9041 fixed no restart or watchdog seen anymore - enable FADE ON/OFF support (not the smoothest but best it can be) - preparation for Setoption 68 1 to use up to 5 Dimmer on one Phase (currently not working) - Introduced USE_AC_ZERO_CROSS_DIMMER compiler option if someone needs every byte
This commit is contained in:
parent
21f7056fce
commit
9c458c9ad8
|
@ -24,6 +24,8 @@
|
|||
|
||||
#define XSNS_01 1
|
||||
|
||||
#define USE_AC_ZERO_CROSS_DIMMER 1
|
||||
|
||||
#define D_PRFX_COUNTER "Counter"
|
||||
#define D_CMND_COUNTERTYPE "Type"
|
||||
#define D_CMND_COUNTERDEBOUNCE "Debounce"
|
||||
|
@ -44,10 +46,20 @@ struct COUNTER {
|
|||
uint8_t no_pullup = 0; // Counter input pullup flag (1 = No pullup)
|
||||
uint8_t pin_state = 0; // LSB0..3 Last state of counter pin; LSB7==0 IRQ is FALLING, LSB7==1 IRQ is CHANGE
|
||||
bool any_counter = false;
|
||||
|
||||
} Counter;
|
||||
|
||||
uint32_t last_cycle;
|
||||
uint32_t cycle_time;
|
||||
#ifdef USE_AC_ZERO_CROSS_DIMMER
|
||||
struct AC_ZERO_CROSS_DIMMER {
|
||||
bool startReSync = false;
|
||||
uint32_t current_cycle_ClockCycles = 0;
|
||||
uint32_t dimm_timeClockCycles = 0;
|
||||
uint32_t currentCycleCount = 0;
|
||||
uint32_t tobe_cycle_timeClockCycles = 0;
|
||||
uint32_t lastCycleCount = 0;
|
||||
uint32_t currentSteps = 100;
|
||||
} ac_zero_cross_dimmer;
|
||||
#endif
|
||||
|
||||
void ICACHE_RAM_ATTR CounterIsrArg(void *arg) {
|
||||
uint32_t index = *static_cast<uint8_t*>(arg);
|
||||
|
@ -76,35 +88,20 @@ void ICACHE_RAM_ATTR CounterIsrArg(void *arg) {
|
|||
if bitRead(Counter.pin_state, index) {
|
||||
// PWMfrequency 100
|
||||
// restart PWM each second (german 50Hz has to up to 0.01% deviation)
|
||||
// Zero-HIGH is typical 2ms
|
||||
if (RtcSettings.pulse_counter[index]%100 == 0 && PinUsed(GPIO_PWM1, index) && Settings.flag4.zerocross_dimmer) {
|
||||
const uint32_t current_cycle = ESP.getCycleCount();
|
||||
// stop pwm on PIN to start in Sync with rising edge
|
||||
// calculate timeoffset to fire PWM
|
||||
uint16_t cur_col = Light.fade_start_10[0 + Light.pwm_offset];
|
||||
uint32_t dimm_time= 1000000 / Settings.pwm_frequency * (1024 - cur_col) / 1024;
|
||||
digitalWrite(Pin(GPIO_PWM1, index), LOW);
|
||||
// restart initiated by setting Counter.startReSync = true;
|
||||
#ifdef USE_AC_ZERO_CROSS_DIMMER
|
||||
if (RtcSettings.pulse_counter[index]%(Settings.pwm_frequency / (Light.fade_running ? 10:1))== 0 && PinUsed(GPIO_PWM1, index) && Settings.flag4.zerocross_dimmer) {
|
||||
ac_zero_cross_dimmer.currentCycleCount = ESP.getCycleCount();
|
||||
|
||||
// 1000µs to ensure not to fire on the next sinus wave
|
||||
if (dimm_time < (1000000 / Settings.pwm_frequency)-1000) {
|
||||
delayMicroseconds(dimm_time);
|
||||
// fire small PWM signal to start TRIAC/SSR. Kill on next
|
||||
// zero phase automatic.
|
||||
// calculate actual cycle time and adapt frequency im milli Hz steps
|
||||
// add 100.000 cpu ticks to ensure right step calculation
|
||||
uint32_t steps = (current_cycle-last_cycle+100000)/(clockCyclesPerMicrosecond() * 10000);
|
||||
cycle_time = (current_cycle-last_cycle)/steps;
|
||||
#ifdef ESP8266
|
||||
pinMode(Pin(GPIO_PWM1, index), OUTPUT);
|
||||
uint32_t high = (cycle_time * 5) / 1023;
|
||||
uint32_t low = cycle_time - high;
|
||||
// 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, index), high, low, 0, -1, 0, true);
|
||||
#else // ESP32
|
||||
analogWrite(Pin(GPIO_PWM1, index), 5);
|
||||
#endif // ESP8266 - ESP32
|
||||
if (ac_zero_cross_dimmer.lastCycleCount>0) {
|
||||
ac_zero_cross_dimmer.startReSync = true;
|
||||
ac_zero_cross_dimmer.currentSteps = (ac_zero_cross_dimmer.currentCycleCount-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.currentCycleCount-ac_zero_cross_dimmer.lastCycleCount)/ac_zero_cross_dimmer.currentSteps;
|
||||
}
|
||||
last_cycle = current_cycle;
|
||||
ac_zero_cross_dimmer.lastCycleCount = ac_zero_cross_dimmer.currentCycleCount;
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +150,9 @@ void CounterInit(void)
|
|||
{
|
||||
for (uint32_t i = 0; i < MAX_COUNTERS; i++) {
|
||||
if (PinUsed(GPIO_CNTR1, i)) {
|
||||
#ifdef USE_AC_ZERO_CROSS_DIMMER
|
||||
ac_zero_cross_dimmer.tobe_cycle_timeClockCycles = microsecondsToClockCycles(1000000 / Settings.pwm_frequency);
|
||||
#endif
|
||||
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) {
|
||||
|
@ -231,6 +231,45 @@ 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 < 1; i++) {
|
||||
if (PinUsed(GPIO_PWM1, i) && PinUsed(GPIO_CNTR1, i))
|
||||
{
|
||||
// get current time because undefined through FUNC_LOOP process.
|
||||
const uint32_t current_cycle = ESP.getCycleCount();
|
||||
digitalWrite(Pin(GPIO_PWM1, i), LOW);
|
||||
// reset trigger for PWM sync
|
||||
ac_zero_cross_dimmer.startReSync = false;
|
||||
// calculate timeoffset to fire PWM
|
||||
|
||||
ac_zero_cross_dimmer.dimm_timeClockCycles = (ac_zero_cross_dimmer.tobe_cycle_timeClockCycles * (1024 - (Light.fade_running ? Light.fade_cur_10[i] : Light.fade_start_10[i]))) / 1024;
|
||||
ac_zero_cross_dimmer.dimm_timeClockCycles = tmax(ac_zero_cross_dimmer.dimm_timeClockCycles, 16000);
|
||||
// because in LOOP calculate the timelag to fire PWM correctly with zero-cross
|
||||
uint32_t timelag_ClockCycles = (current_cycle - ac_zero_cross_dimmer.currentCycleCount)%ac_zero_cross_dimmer.tobe_cycle_timeClockCycles;
|
||||
timelag_ClockCycles = ((ac_zero_cross_dimmer.dimm_timeClockCycles + ac_zero_cross_dimmer.tobe_cycle_timeClockCycles) - timelag_ClockCycles)%ac_zero_cross_dimmer.tobe_cycle_timeClockCycles;
|
||||
delayMicroseconds(clockCyclesToMicroseconds(timelag_ClockCycles));
|
||||
|
||||
#ifdef ESP8266
|
||||
pinMode(Pin(GPIO_PWM1, i), OUTPUT);
|
||||
// short fire to ensure not to hit next sinus curve. 0.78% of duty cycle (10ms) ~4µs
|
||||
uint32_t high = ac_zero_cross_dimmer.current_cycle_ClockCycles / 256;
|
||||
uint32_t low = ac_zero_cross_dimmer.current_cycle_ClockCycles - high;
|
||||
// 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), high, low, 0, -1, 0, true);
|
||||
#else // ESP32
|
||||
analogWrite(Pin(GPIO_PWM1, i), 5);
|
||||
#endif // ESP8266 - ESP32
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("CNT: [%d] dimm_time_CCs %d, current_cycle_CC: %d, timelag %lu, lastcc %lu, currentSteps %d, curr %d"), i, ac_zero_cross_dimmer.dimm_timeClockCycles,ac_zero_cross_dimmer.current_cycle_ClockCycles , timelag_ClockCycles, ac_zero_cross_dimmer.currentCycleCount, ac_zero_cross_dimmer.currentSteps, Light.fade_cur_10[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Commands
|
||||
\*********************************************************************************************/
|
||||
|
@ -305,6 +344,11 @@ bool Xsns01(uint8_t function)
|
|||
case FUNC_JSON_APPEND:
|
||||
CounterShow(1);
|
||||
break;
|
||||
#ifdef USE_AC_ZERO_CROSS_DIMMER
|
||||
case FUNC_LOOP:
|
||||
SyncACDimmer();
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_SENSOR:
|
||||
CounterShow(0);
|
||||
|
|
Loading…
Reference in New Issue