@@ -128,21 +128,20 @@ static IRAM_ATTR void forceTimerInterrupt() {
128128constexpr 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
141141static PWMState pwmState;
142142static uint32_t _pwmFreq = 1000 ;
143143static uint32_t _pwmPeriod = microsecondsToClockCycles(1000000UL ) / _pwmFreq;
144144
145-
146145// If there are no more scheduled activities, shut down Timer 1.
147146// Otherwise, do nothing.
148147static 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)
159158static 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