kopia lustrzana https://github.com/Aircoookie/WLED
Improve PWM on ESP8266
- Better phase updates without dropping samples - Make second pin duty cycle always after first, even invertedpull/4165/head
rodzic
3c7f83407b
commit
59deebc961
|
@ -242,7 +242,7 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCc
|
||||||
wave.mode = WaveformMode::UPDATEEXPIRY;
|
wave.mode = WaveformMode::UPDATEEXPIRY;
|
||||||
std::atomic_thread_fence(std::memory_order_release);
|
std::atomic_thread_fence(std::memory_order_release);
|
||||||
waveform.toSetBits = 1UL << pin;
|
waveform.toSetBits = 1UL << pin;
|
||||||
} else if (alignPhase) {
|
} else if (alignPhase >= 0) {
|
||||||
// @willmmiles new feature
|
// @willmmiles new feature
|
||||||
wave.mode = WaveformMode::UPDATEPHASE; // recalculate start
|
wave.mode = WaveformMode::UPDATEPHASE; // recalculate start
|
||||||
std::atomic_thread_fence(std::memory_order_release);
|
std::atomic_thread_fence(std::memory_order_release);
|
||||||
|
@ -303,7 +303,7 @@ static inline IRAM_ATTR int32_t scaleCcys(const int32_t ccys, const bool isCPU2X
|
||||||
|
|
||||||
static IRAM_ATTR void timer1Interrupt() {
|
static IRAM_ATTR void timer1Interrupt() {
|
||||||
const uint32_t isrStartCcy = ESP.getCycleCount();
|
const uint32_t isrStartCcy = ESP.getCycleCount();
|
||||||
int32_t clockDrift = isrStartCcy - waveform.nextEventCcy;
|
//int32_t clockDrift = isrStartCcy - waveform.nextEventCcy;
|
||||||
|
|
||||||
// ----- @willmmiles begin patch -----
|
// ----- @willmmiles begin patch -----
|
||||||
nmiCrashWorkaround();
|
nmiCrashWorkaround();
|
||||||
|
@ -341,12 +341,16 @@ static IRAM_ATTR void timer1Interrupt() {
|
||||||
break;
|
break;
|
||||||
// @willmmiles new feature
|
// @willmmiles new feature
|
||||||
case WaveformMode::UPDATEPHASE:
|
case WaveformMode::UPDATEPHASE:
|
||||||
// in WaveformMode::UPDATEPHASE, we recalculate the targets without adjusting the state
|
// in WaveformMode::UPDATEPHASE, we recalculate the targets
|
||||||
if (waveform.alignPhase >= 0 && waveform.enabled & (1UL << waveform.alignPhase)) {
|
if (waveform.alignPhase >= 0 && waveform.enabled & (1UL << waveform.alignPhase)) {
|
||||||
|
// Compute phase shift to realign with target
|
||||||
auto& align_wave = waveform.pins[waveform.alignPhase];
|
auto& align_wave = waveform.pins[waveform.alignPhase];
|
||||||
// Go back one cycle
|
int32_t shift = static_cast<int32_t>(align_wave.nextPeriodCcy + scaleCcys(waveform.phaseCcy, isCPU2X) - wave.nextPeriodCcy);
|
||||||
wave.nextPeriodCcy = align_wave.nextPeriodCcy - scaleCcys(align_wave.periodCcys, isCPU2X) + scaleCcys(waveform.phaseCcy, isCPU2X);
|
const int32_t periodCcys = scaleCcys(wave.periodCcys, isCPU2X);
|
||||||
wave.endDutyCcy = wave.nextPeriodCcy + scaleCcys(wave.dutyCcys, isCPU2X);
|
if (shift > periodCcys/2) shift -= periodCcys;
|
||||||
|
else if (shift <= -periodCcys/2) shift += periodCcys;
|
||||||
|
wave.nextPeriodCcy += shift;
|
||||||
|
wave.endDutyCcy += shift;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -462,7 +466,7 @@ static IRAM_ATTR void timer1Interrupt() {
|
||||||
}
|
}
|
||||||
now = ESP.getCycleCount();
|
now = ESP.getCycleCount();
|
||||||
}
|
}
|
||||||
clockDrift = 0;
|
//clockDrift = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t callbackCcys = 0;
|
int32_t callbackCcys = 0;
|
||||||
|
|
|
@ -565,7 +565,7 @@ void BusPwm::show() {
|
||||||
const unsigned analogPeriod = F_CPU / _frequency;
|
const unsigned analogPeriod = F_CPU / _frequency;
|
||||||
const unsigned maxBri = analogPeriod; // compute to clock cycle accuracy
|
const unsigned maxBri = analogPeriod; // compute to clock cycle accuracy
|
||||||
constexpr bool dithering = false;
|
constexpr bool dithering = false;
|
||||||
constexpr unsigned bitShift = 7; // 2^7 clocks for dead time
|
constexpr unsigned bitShift = 8; // 256 clocks for dead time, ~3us at 80MHz
|
||||||
#else
|
#else
|
||||||
// if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor)
|
// if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor)
|
||||||
// https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1)
|
// https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1)
|
||||||
|
@ -609,8 +609,10 @@ void BusPwm::show() {
|
||||||
duty -= deadTime << 1; // shorten duty of larger signal except if full on
|
duty -= deadTime << 1; // shorten duty of larger signal except if full on
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_reversed) duty = maxBri - duty;
|
if (_reversed) {
|
||||||
|
if (i) hPoint += duty; // align start at time zero
|
||||||
|
duty = maxBri - duty;
|
||||||
|
}
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
//stopWaveform(_pins[i]); // can cause the waveform to miss a cycle. instead we risk crossovers.
|
//stopWaveform(_pins[i]); // can cause the waveform to miss a cycle. instead we risk crossovers.
|
||||||
startWaveformClockCycles(_pins[i], duty, analogPeriod - duty, 0, i ? _pins[0] : -1, hPoint, false);
|
startWaveformClockCycles(_pins[i], duty, analogPeriod - duty, 0, i ? _pins[0] : -1, hPoint, false);
|
||||||
|
@ -625,7 +627,8 @@ void BusPwm::show() {
|
||||||
ledc_update_duty((ledc_mode_t)gr, (ledc_channel_t)ch);
|
ledc_update_duty((ledc_mode_t)gr, (ledc_channel_t)ch);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
hPoint += duty + (_reversed ? -1 : 1) * deadTime; // offset to cascade the signals
|
if (!_reversed) hPoint += duty;
|
||||||
|
hPoint += deadTime; // offset to cascade the signals
|
||||||
if (hPoint >= maxBri) hPoint -= maxBri; // offset is out of bounds, reset
|
if (hPoint >= maxBri) hPoint -= maxBri; // offset is out of bounds, reset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue