80
80
81
81
// Waveform generator can create tones, PWM, and servos
82
82
typedef struct {
83
- uint32_t nextServiceCycle ;
84
- uint32_t timeHighCycles ;
85
- uint32_t timeLowCycles ;
86
- uint32_t timeLeftCycles ;
87
- // To ensure stable change, only copy these over on low->high transition
88
- uint16_t gpioMask ;
89
- uint16_t gpio16Mask ;
90
- // unsigned gpioPin : 4; // Check gpioPin16 first
91
- unsigned state : 1 ;
92
- unsigned nextTimeHighCycles : 31 ;
93
- // unsigned gpioPin16 : 1; // Special case for weird IO16
94
- unsigned enabled : 1 ;
95
- unsigned nextTimeLowCycles : 31 ;
83
+ uint32_t nextServiceCycle ; // ESP cycle timer when a transition required
84
+ uint32_t timeLeftCycles ; // For time-limited waveform, how many ESP cycles left
85
+ uint16_t gpioMask ; // Mask instead of value to speed IRQ loop
86
+ uint16_t gpio16Mask ; // Mask instead of value to speed IRQ loop
87
+ unsigned state : 1 ; // Current state of this pin
88
+ unsigned nextTimeHighCycles : 31 ; // Copy over low->high to keep smooth waveform
89
+ unsigned enabled : 1 ; // Is this GPIO generating a waveform?
90
+ unsigned nextTimeLowCycles : 31 ; // Copy over high->low to keep smooth waveform
96
91
} Waveform ;
97
92
98
93
// These can be accessed in interrupts, so ensure to bracket access with SEI/CLI
99
94
static Waveform waveform [] = {
100
- {0 , 0 , 0 , 0 , 1 <<0 , 0 , 0 , 0 , 0 , 0 }, // GPIO0
101
- {0 , 0 , 0 , 0 , 1 <<1 , 0 , 0 , 0 , 0 , 0 }, // GPIO1
102
- {0 , 0 , 0 , 0 , 1 <<2 , 0 , 0 , 0 , 0 , 0 },
103
- {0 , 0 , 0 , 0 , 1 <<3 , 0 , 0 , 0 , 0 , 0 },
104
- {0 , 0 , 0 , 0 , 1 <<4 , 0 , 0 , 0 , 0 , 0 },
105
- {0 , 0 , 0 , 0 , 1 <<5 , 0 , 0 , 0 , 0 , 0 },
95
+ {0 , 0 , 1 <<0 , 0 , 0 , 0 , 0 , 0 }, // GPIO0
96
+ {0 , 0 , 1 <<1 , 0 , 0 , 0 , 0 , 0 }, // GPIO1
97
+ {0 , 0 , 1 <<2 , 0 , 0 , 0 , 0 , 0 },
98
+ {0 , 0 , 1 <<3 , 0 , 0 , 0 , 0 , 0 },
99
+ {0 , 0 , 1 <<4 , 0 , 0 , 0 , 0 , 0 },
100
+ {0 , 0 , 1 <<5 , 0 , 0 , 0 , 0 , 0 },
106
101
// GPIOS 6-11 not allowed, used for flash
107
- {0 , 0 , 0 , 0 , 1 <<12 , 0 , 0 , 0 , 0 , 0 },
108
- {0 , 0 , 0 , 0 , 1 <<13 , 0 , 0 , 0 , 0 , 0 },
109
- {0 , 0 , 0 , 0 , 1 <<14 , 0 , 0 , 0 , 0 , 0 },
110
- {0 , 0 , 0 , 0 , 1 <<15 , 0 , 0 , 0 , 0 , 0 },
111
- {0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 } // GPIO16
102
+ {0 , 0 , 1 <<12 , 0 , 0 , 0 , 0 , 0 },
103
+ {0 , 0 , 1 <<13 , 0 , 0 , 0 , 0 , 0 },
104
+ {0 , 0 , 1 <<14 , 0 , 0 , 0 , 0 , 0 },
105
+ {0 , 0 , 1 <<15 , 0 , 0 , 0 , 0 , 0 },
106
+ {0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 } // GPIO16
112
107
};
113
108
114
109
@@ -137,20 +132,20 @@ typedef struct {
137
132
uint32_t nextEventCycles ;
138
133
139
134
// Copied from head for fast access
140
- uint16_t pulses ;
141
- uint32_t cumCycles ;
142
- float j_2 ;
143
- float a0 ;
144
- float v0 ;
145
- unsigned sync : 1 ;
146
- unsigned dir : 1 ;
147
-
148
- unsigned gpioPin : 4 ;
149
- unsigned finished : 1 ;
150
-
151
- uint8_t readPtr ;
152
- uint8_t writePtr ;
153
- uint8_t validEntries ;
135
+ uint16_t pulses ; // Pulses remaining
136
+ uint32_t cumCycles ; // The "t" in our equations
137
+ float j_2 ; // j/2 (jerk divided by 2.0)
138
+ float a0 ; // Initial constant acceleration
139
+ float v0 ; // Initial constant velocity
140
+ unsigned sync : 1 ; // Wait for all steppers to finish before advancing
141
+ unsigned dir : 1 ; // CCW or CW
142
+
143
+ unsigned finished : 1 ; // Done with all moves, on next hit pop another motion
144
+ unsigned gpioPin : 5 ; // Allow all GPIOs, we're going to be slow no matter what
145
+
146
+ uint8_t readPtr ; // Read queue index
147
+ uint8_t writePtr ; // Push queue spot
148
+ uint8_t validEntries ; // How many entries present
154
149
} StepperQueue ;
155
150
156
151
static volatile StepperQueue * stepQ = NULL ;
@@ -254,9 +249,10 @@ int removeStepper(uint8_t pin) {
254
249
255
250
// Add a stepper move, return TRUE on success, FALSE on out of space
256
251
// Calling application needs to ensure IRQS are disabled for the call!
257
- static int PushStepper (int gpioPin , const Motion * nextMove ) {
252
+ static int PushStepper (uint8_t gpioPin , const Motion * nextMove ) {
258
253
StepperQueue * q = NULL ;
259
254
int i ;
255
+ // gpioPin already validated in calling function
260
256
sei ();
261
257
// Determine which queue it should be on, or maybe add one if needed
262
258
for (i = 0 ; i < stepQCnt ; i ++ ) {
@@ -314,10 +310,10 @@ static int PushStepper(int gpioPin, const Motion *nextMove) {
314
310
315
311
// Called by user to add a PWL move to the queue, returns false if there is no space left
316
312
int pushStepperMove (uint8_t pin , int dir , int sync , uint16_t pulses , float j , float a0 , float v0 ) {
317
- if (pin > 15 ) {
318
- // Only GPIO 0...15 allowed
313
+ if (pin > 16 ) {
319
314
return false;
320
315
}
316
+
321
317
Motion m ;
322
318
m .pulses = pulses ;
323
319
m .j_2 = j / 2.0 ;
@@ -351,31 +347,26 @@ int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t
351
347
if (!wave ) {
352
348
return false;
353
349
}
354
- sei ();
355
- wave -> nextTimeHighCycles = MicrosecondsToCycles (timeHighUS );
356
- wave -> nextTimeLowCycles = MicrosecondsToCycles (timeLowUS );
350
+ wave -> nextTimeHighCycles = MicrosecondsToCycles (timeHighUS ) - 70 ; // Take out some time for IRQ codepath
351
+ wave -> nextTimeLowCycles = MicrosecondsToCycles (timeLowUS ) - 70 ; // Take out some time for IRQ codepath
357
352
wave -> timeLeftCycles = MicrosecondsToCycles (runTimeUS );
358
353
if (!wave -> enabled ) {
359
354
wave -> state = 0 ;
360
355
// Actually set the pin high or low in the IRQ service to guarantee times
361
- wave -> timeHighCycles = MicrosecondsToCycles (timeHighUS ) - 30 ; // Sub off some of the codepath time
362
- wave -> timeLowCycles = MicrosecondsToCycles (timeLowUS ) - 30 ; // Sub off some of the codepath time
363
356
wave -> nextServiceCycle = GetCycleCount () + MicrosecondsToCycles (1 );
364
357
wave -> enabled = 1 ;
365
358
if (!timerRunning ) {
366
359
initTimer ();
367
360
}
368
361
ReloadTimer (MicrosecondsToCycles (1 )); // Cause an interrupt post-haste
369
362
}
370
- cli ();
371
363
return true;
372
364
}
373
365
374
366
// Stops a waveform on a pin
375
367
int stopWaveform (uint8_t pin ) {
376
368
for (size_t i = 0 ; i < countof (waveform ); i ++ ) {
377
369
if (((pin == 16 ) && waveform [i ].gpio16Mask ) || ((pin != 16 ) && (waveform [i ].gpioMask == 1 <<pin ))) {
378
- sei ();
379
370
waveform [i ].enabled = 0 ;
380
371
int cnt = stepQCnt ;
381
372
for (size_t i = 0 ; i < countof (waveform ); i ++ ) {
@@ -384,7 +375,6 @@ int stopWaveform(uint8_t pin) {
384
375
if (!cnt ) {
385
376
deinitTimer ();
386
377
}
387
- cli ();
388
378
return true;
389
379
}
390
380
}
@@ -397,8 +387,8 @@ int stopWaveform(uint8_t pin) {
397
387
// Send pulses for specific direction.
398
388
// Stepper direction pin needs to be set before calling (helps ensure setup time)
399
389
static ICACHE_RAM_ATTR void AdvanceSteppers (uint32_t deltaCycles , int dir ) {
400
- static uint16_t toClear = 0 ; // Store last call's pins to allow us to meet hold time by clearing on the processing of the other dir
401
- uint16_t pulseGPIO = 0 ;
390
+ static uint32_t toClear = 0 ; // Store last call's pins to allow us to meet hold time by clearing on the processing of the other dir
391
+ uint32_t pulseGPIO = 0 ;
402
392
for (size_t i = 0 ; i < stepQCnt ; i ++ ) {
403
393
StepperQueue * q = (StepperQueue * )& stepQ [i ];
404
394
if (q -> dir != dir || q -> finished ) {
@@ -443,8 +433,14 @@ static ICACHE_RAM_ATTR void AdvanceSteppers(uint32_t deltaCycles, int dir) {
443
433
q -> nextEventCycles = newNextEventCycles ;
444
434
}
445
435
}
446
- ClearGPIO (toClear );
447
- SetGPIO (pulseGPIO );
436
+ ClearGPIO (toClear & 0xffff );
437
+ if (toClear & 0x80000 ) {
438
+ GP16O &= ~1 ; // RMW is slow, only do if needed
439
+ }
440
+ SetGPIO (pulseGPIO & 0xffff );
441
+ if (pulseGPIO & 0x80000 ) {
442
+ GP16O |= 1 ; // RMW is slow, only do if needed
443
+ }
448
444
toClear = pulseGPIO ;
449
445
}
450
446
@@ -513,17 +509,15 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
513
509
if (wave -> gpio16Mask ) {
514
510
GP16O |= wave -> gpio16Mask ; // GPIO16 write slow as it's RMW
515
511
}
516
- wave -> nextServiceCycle = now + wave -> timeHighCycles ;
517
- wave -> timeHighCycles = wave -> nextTimeHighCycles ;
518
- nextEventCycles = min_u32 (nextEventCycles , wave -> timeHighCycles );
512
+ wave -> nextServiceCycle = now + wave -> nextTimeHighCycles ;
513
+ nextEventCycles = min_u32 (nextEventCycles , wave -> nextTimeHighCycles );
519
514
} else {
520
515
ClearGPIO (wave -> gpioMask );
521
516
if (wave -> gpio16Mask ) {
522
517
GP16O &= ~wave -> gpio16Mask ;
523
518
}
524
- wave -> nextServiceCycle = now + wave -> timeLowCycles ;
525
- wave -> timeLowCycles = wave -> nextTimeLowCycles ;
526
- nextEventCycles = min_u32 (nextEventCycles , wave -> timeLowCycles );
519
+ wave -> nextServiceCycle = now + wave -> nextTimeLowCycles ;
520
+ nextEventCycles = min_u32 (nextEventCycles , wave -> nextTimeLowCycles );
527
521
}
528
522
} else {
529
523
uint32_t deltaCycles = wave -> nextServiceCycle - now ;
0 commit comments