Skip to content

Commit 36b2bd3

Browse files
committed
Don't force timer on PWM update as this is pulled by ISR, but only implemented
on next PWM period begin anyway.
1 parent 98537bd commit 36b2bd3

File tree

1 file changed

+23
-22
lines changed

1 file changed

+23
-22
lines changed

cores/esp8266/core_esp8266_waveform_pwm.cpp

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,20 @@ static IRAM_ATTR void forceTimerInterrupt() {
128128
constexpr int maxPWMs = 8;
129129

130130
// PWM machine state
131-
typedef struct PWMState {
131+
struct PWMState {
132132
uint32_t mask; // Bitmask of active pins
133133
uint32_t cnt; // How many entries
134134
uint32_t idx; // Where the state machine is along the list
135135
uint8_t pin[maxPWMs + 1];
136136
uint32_t delta[maxPWMs + 1];
137137
uint32_t nextServiceCycle; // Clock cycle for next step
138138
struct PWMState *pwmUpdate; // Set by main code, cleared by ISR
139-
} PWMState;
139+
};
140140

141141
static PWMState pwmState;
142142
static uint32_t _pwmFreq = 1000;
143143
static uint32_t _pwmPeriod = microsecondsToClockCycles(1000000UL) / _pwmFreq;
144144

145-
146145
// If there are no more scheduled activities, shut down Timer 1.
147146
// Otherwise, do nothing.
148147
static IRAM_ATTR void disableIdleTimer() {
@@ -158,6 +157,7 @@ static IRAM_ATTR void disableIdleTimer() {
158157
// Wait for mailbox to be emptied (either busy or delay() as needed)
159158
static IRAM_ATTR void _notifyPWM(PWMState *p, bool idle) {
160159
p->pwmUpdate = nullptr;
160+
MEMBARRIER();
161161
pwmState.pwmUpdate = p;
162162
MEMBARRIER();
163163
forceTimerInterrupt();
@@ -242,8 +242,7 @@ IRAM_ATTR bool _stopPWM_weak(uint8_t pin) {
242242
return false; // Pin not actually active
243243
}
244244

245-
PWMState p; // The working copy since we can't edit the one in use
246-
p = pwmState;
245+
PWMState p = pwmState; // The working copy since we can't edit the one in use
247246

248247
// In _stopPWM we just clear the mask but keep everything else
249248
// untouched to save IRAM. The main startPWM will handle cleanup.
@@ -264,7 +263,7 @@ IRAM_ATTR bool _stopPWM(uint8_t pin) {
264263
return _stopPWM_bound(pin);
265264
}
266265

267-
static void _addPWMtoList(PWMState &p, uint8_t pin, uint32_t val, uint32_t range) {
266+
static void _addPWMtoList(PWMState& p, uint8_t pin, uint32_t val, uint32_t range) {
268267
// Stash the val and range so we can re-evaluate the fraction
269268
// should the user change PWM frequency. This allows us to
270269
// give as great a precision as possible. We know by construction
@@ -278,17 +277,19 @@ static void _addPWMtoList(PWMState &p, uint8_t pin, uint32_t val, uint32_t range
278277
// Clip to sane values in the case we go from OK to not-OK when adjusting frequencies
279278
if (cc == 0) {
280279
cc = 1;
281-
} else if (cc >= _pwmPeriod) {
280+
}
281+
else if (cc >= _pwmPeriod) {
282282
cc = _pwmPeriod - 1;
283283
}
284284

285285
if (p.cnt == 0) {
286286
// Starting up from scratch, special case 1st element and PWM period
287287
p.pin[0] = pin;
288288
p.delta[0] = cc;
289-
// Final pin is never used: p.pin[1] = 0xff;
289+
// Final pin is never used: p.pin[1] = 0xff;
290290
p.delta[1] = _pwmPeriod - cc;
291-
} else {
291+
}
292+
else {
292293
uint32_t ttl = 0;
293294
uint32_t i;
294295
// Skip along until we're at the spot to insert
@@ -532,39 +533,39 @@ static IRAM_ATTR void timer1Interrupt() {
532533

533534
// PWM state machine implementation
534535
if (pwmState.cnt) {
535-
int32_t cyclesToGo;
536+
int32_t pwmCyclesToGo;
536537
do {
537-
cyclesToGo = pwmState.nextServiceCycle - GetCycleCountIRQ();
538-
if (cyclesToGo < 0) {
538+
pwmCyclesToGo = pwmState.nextServiceCycle - GetCycleCountIRQ();
539+
if (pwmCyclesToGo <= 0) {
539540
if (pwmState.idx == pwmState.cnt) { // Start of pulses, possibly copy new
540541
if (pwmState.pwmUpdate) {
541542
// Do the memory copy from temp to global and clear mailbox
542-
pwmState = *(PWMState*)pwmState.pwmUpdate;
543+
pwmState = *pwmState.pwmUpdate;
543544
}
544545
GPOS = pwmState.mask; // Set all active pins high
545546
if (pwmState.mask & (1<<16)) {
546547
GP16O = 1;
547548
}
548549
pwmState.idx = 0;
549-
} else {
550+
}
551+
else {
550552
do {
551553
// Drop the pin at this edge
552-
if (pwmState.mask & (1<<pwmState.pin[pwmState.idx])) {
553-
GPOC = 1<<pwmState.pin[pwmState.idx];
554-
if (pwmState.pin[pwmState.idx] == 16) {
555-
GP16O = 0;
556-
}
554+
GPOC = 1<<pwmState.pin[pwmState.idx];
555+
if (pwmState.pin[pwmState.idx] == 16) {
556+
GP16O = 0;
557557
}
558558
pwmState.idx++;
559559
// Any other pins at this same PWM value will have delta==0, drop them too.
560560
} while (pwmState.delta[pwmState.idx] == 0);
561561
}
562562
// Preserve duty cycle over PWM period by using now+xxx instead of += delta
563-
cyclesToGo = adjust(pwmState.delta[pwmState.idx]);
564-
pwmState.nextServiceCycle = GetCycleCountIRQ() + cyclesToGo;
563+
pwmCyclesToGo = adjust(pwmState.delta[pwmState.idx]);
564+
pwmState.nextServiceCycle = GetCycleCountIRQ() + pwmCyclesToGo;
565565
}
566566
nextEventCycle = earliest(nextEventCycle, pwmState.nextServiceCycle);
567-
} while (pwmState.cnt && (cyclesToGo < 100));
567+
// PWM can starve the generic waveform generator if pwmCyclesToGo remains below 100
568+
} while (pwmState.cnt && pwmCyclesToGo < 100);
568569
}
569570

570571
for (auto i = wvfState.startPin; i <= wvfState.endPin; i++) {

0 commit comments

Comments
 (0)