@@ -128,21 +128,20 @@ static IRAM_ATTR void forceTimerInterrupt() {
128
128
constexpr int maxPWMs = 8 ;
129
129
130
130
// PWM machine state
131
- typedef struct PWMState {
131
+ struct PWMState {
132
132
uint32_t mask; // Bitmask of active pins
133
133
uint32_t cnt; // How many entries
134
134
uint32_t idx; // Where the state machine is along the list
135
135
uint8_t pin[maxPWMs + 1 ];
136
136
uint32_t delta[maxPWMs + 1 ];
137
137
uint32_t nextServiceCycle; // Clock cycle for next step
138
138
struct PWMState *pwmUpdate; // Set by main code, cleared by ISR
139
- } PWMState ;
139
+ };
140
140
141
141
static PWMState pwmState;
142
142
static uint32_t _pwmFreq = 1000 ;
143
143
static uint32_t _pwmPeriod = microsecondsToClockCycles(1000000UL ) / _pwmFreq;
144
144
145
-
146
145
// If there are no more scheduled activities, shut down Timer 1.
147
146
// Otherwise, do nothing.
148
147
static IRAM_ATTR void disableIdleTimer () {
@@ -158,6 +157,7 @@ static IRAM_ATTR void disableIdleTimer() {
158
157
// Wait for mailbox to be emptied (either busy or delay() as needed)
159
158
static IRAM_ATTR void _notifyPWM (PWMState *p, bool idle) {
160
159
p->pwmUpdate = nullptr ;
160
+ MEMBARRIER ();
161
161
pwmState.pwmUpdate = p;
162
162
MEMBARRIER ();
163
163
forceTimerInterrupt ();
@@ -242,8 +242,7 @@ IRAM_ATTR bool _stopPWM_weak(uint8_t pin) {
242
242
return false ; // Pin not actually active
243
243
}
244
244
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
247
246
248
247
// In _stopPWM we just clear the mask but keep everything else
249
248
// untouched to save IRAM. The main startPWM will handle cleanup.
@@ -264,7 +263,7 @@ IRAM_ATTR bool _stopPWM(uint8_t pin) {
264
263
return _stopPWM_bound (pin);
265
264
}
266
265
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) {
268
267
// Stash the val and range so we can re-evaluate the fraction
269
268
// should the user change PWM frequency. This allows us to
270
269
// 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
278
277
// Clip to sane values in the case we go from OK to not-OK when adjusting frequencies
279
278
if (cc == 0 ) {
280
279
cc = 1 ;
281
- } else if (cc >= _pwmPeriod) {
280
+ }
281
+ else if (cc >= _pwmPeriod) {
282
282
cc = _pwmPeriod - 1 ;
283
283
}
284
284
285
285
if (p.cnt == 0 ) {
286
286
// Starting up from scratch, special case 1st element and PWM period
287
287
p.pin [0 ] = pin;
288
288
p.delta [0 ] = cc;
289
- // Final pin is never used: p.pin[1] = 0xff;
289
+ // Final pin is never used: p.pin[1] = 0xff;
290
290
p.delta [1 ] = _pwmPeriod - cc;
291
- } else {
291
+ }
292
+ else {
292
293
uint32_t ttl = 0 ;
293
294
uint32_t i;
294
295
// Skip along until we're at the spot to insert
@@ -532,39 +533,39 @@ static IRAM_ATTR void timer1Interrupt() {
532
533
533
534
// PWM state machine implementation
534
535
if (pwmState.cnt ) {
535
- int32_t cyclesToGo ;
536
+ int32_t pwmCyclesToGo ;
536
537
do {
537
- cyclesToGo = pwmState.nextServiceCycle - GetCycleCountIRQ ();
538
- if (cyclesToGo < 0 ) {
538
+ pwmCyclesToGo = pwmState.nextServiceCycle - GetCycleCountIRQ ();
539
+ if (pwmCyclesToGo <= 0 ) {
539
540
if (pwmState.idx == pwmState.cnt ) { // Start of pulses, possibly copy new
540
541
if (pwmState.pwmUpdate ) {
541
542
// Do the memory copy from temp to global and clear mailbox
542
- pwmState = *(PWMState*) pwmState.pwmUpdate ;
543
+ pwmState = *pwmState.pwmUpdate ;
543
544
}
544
545
GPOS = pwmState.mask ; // Set all active pins high
545
546
if (pwmState.mask & (1 <<16 )) {
546
547
GP16O = 1 ;
547
548
}
548
549
pwmState.idx = 0 ;
549
- } else {
550
+ }
551
+ else {
550
552
do {
551
553
// 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 ;
557
557
}
558
558
pwmState.idx ++;
559
559
// Any other pins at this same PWM value will have delta==0, drop them too.
560
560
} while (pwmState.delta [pwmState.idx ] == 0 );
561
561
}
562
562
// 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 ;
565
565
}
566
566
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 );
568
569
}
569
570
570
571
for (auto i = wvfState.startPin ; i <= wvfState.endPin ; i++) {
0 commit comments