55
55
#include <Arduino.h>
56
56
#include "core_esp8266_waveform.h"
57
57
58
+ // Need speed, not size, here
59
+ #pragma GCC optimize ("O3")
60
+
58
61
// Map the IRQ stuff to standard terminology
59
62
#define cli () ets_intr_lock()
60
63
#define sei () ets_intr_unlock()
63
66
#define MAXIRQUS (10000)
64
67
65
68
// If the cycles from now to an event are below this value, perform it anyway since IRQs take longer than this
66
- #define CYCLES_FLUFF (200 )
69
+ #define CYCLES_FLUFF (100 )
67
70
68
71
// Macro to get count of predefined array elements
69
72
#define countof (a ) ((size_t)(sizeof(a)/sizeof(a[0])))
77
80
78
81
// Waveform generator can create tones, PWM, and servos
79
82
typedef struct {
80
- uint32_t nextEventCycles ;
83
+ uint32_t nextServiceCycle ;
81
84
uint32_t timeHighCycles ;
82
85
uint32_t timeLowCycles ;
83
86
uint32_t timeLeftCycles ;
84
87
// To ensure stable change, only copy these over on low->high transition
85
- unsigned gpioPin : 4 ; // Check gpioPin16 first
86
- unsigned nextTimeHighCycles : 28 ;
87
- unsigned gpioPin16 : 1 ; // Special case for weird IO16
88
+ uint16_t gpioMask ;
89
+ uint16_t gpio16Mask ;
90
+ // unsigned gpioPin : 4 ; // Check gpioPin16 first
88
91
unsigned state : 1 ;
92
+ unsigned nextTimeHighCycles : 31 ;
93
+ // unsigned gpioPin16 : 1; // Special case for weird IO16
89
94
unsigned enabled : 1 ;
90
- unsigned nextTimeLowCycles : 28 ;
95
+ unsigned nextTimeLowCycles : 31 ;
91
96
} Waveform ;
92
97
93
98
// These can be accessed in interrupts, so ensure to bracket access with SEI/CLI
94
99
static Waveform waveform [] = {
95
- {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // GPIO0
96
- {0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 }, // GPIO1
97
- {0 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 0 , 0 },
98
- {0 , 0 , 0 , 0 , 3 , 0 , 0 , 0 , 0 , 0 },
99
- {0 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , 0 , 0 },
100
- {0 , 0 , 0 , 0 , 5 , 0 , 0 , 0 , 0 , 0 },
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 },
101
106
// GPIOS 6-11 not allowed, used for flash
102
- {0 , 0 , 0 , 0 , 12 , 0 , 0 , 0 , 0 , 0 },
103
- {0 , 0 , 0 , 0 , 13 , 0 , 0 , 0 , 0 , 0 },
104
- {0 , 0 , 0 , 0 , 14 , 0 , 0 , 0 , 0 , 0 },
105
- {0 , 0 , 0 , 0 , 15 , 0 , 0 , 0 , 0 , 0 },
106
- {0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 }
107
- }; // GPIO16
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
112
+ };
108
113
109
114
110
115
// Maximum umber of moves per stepper queue
@@ -164,8 +169,20 @@ static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b) {
164
169
return b ;
165
170
}
166
171
172
+ static inline ICACHE_RAM_ATTR uint32_t min_s32 (int32_t a , int32_t b ) {
173
+ if (a < b ) {
174
+ return a ;
175
+ }
176
+ return b ;
177
+ }
178
+
167
179
static inline ICACHE_RAM_ATTR void ReloadTimer (uint32_t a ) {
168
- timer1_write (a );
180
+ // Below a threshold you actually miss the edge IRQ, so ensure enough time
181
+ if (a > 32 ) {
182
+ timer1_write (a );
183
+ } else {
184
+ timer1_write (32 );
185
+ }
169
186
}
170
187
171
188
static inline ICACHE_RAM_ATTR uint32_t GetCycleCount () {
@@ -220,7 +237,7 @@ static inline ICACHE_RAM_ATTR void PopStepper(int i) {
220
237
}
221
238
222
239
// Called by the user to detach a stepper and free memory
223
- int removeStepper (int pin ) {
240
+ int removeStepper (uint8_t pin ) {
224
241
sei ();
225
242
for (int i = 0 ; i < stepQCnt ; i ++ ) {
226
243
if (stepQ [i ].gpioPin == pin ) {
@@ -231,6 +248,7 @@ int removeStepper(int pin) {
231
248
return true;
232
249
}
233
250
}
251
+ cli ();
234
252
return false;
235
253
}
236
254
@@ -295,7 +313,11 @@ static int PushStepper(int gpioPin, const Motion *nextMove) {
295
313
}
296
314
297
315
// Called by user to add a PWL move to the queue, returns false if there is no space left
298
- int pushStepperMove (int pin , int dir , int sync , uint16_t pulses , float j , float a0 , float v0 ) {
316
+ 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
319
+ return false;
320
+ }
299
321
Motion m ;
300
322
m .pulses = pulses ;
301
323
m .j_2 = j / 2.0 ;
@@ -307,7 +329,7 @@ int pushStepperMove(int pin, int dir, int sync, uint16_t pulses, float j, float
307
329
}
308
330
309
331
// Assign a pin to stepper DIR
310
- int setStepperDirPin (int pin ) {
332
+ int setStepperDirPin (uint8_t pin ) {
311
333
if (pin > 16 ) {
312
334
return false;
313
335
}
@@ -321,7 +343,7 @@ int setStepperDirPin(int pin) {
321
343
int startWaveform (uint8_t pin , uint32_t timeHighUS , uint32_t timeLowUS , uint32_t runTimeUS ) {
322
344
Waveform * wave = NULL ;
323
345
for (size_t i = 0 ; i < countof (waveform ); i ++ ) {
324
- if (((pin == 16 ) && waveform [i ].gpioPin16 ) || ((pin != 16 ) && (waveform [i ].gpioPin == pin ))) {
346
+ if (((pin == 16 ) && waveform [i ].gpio16Mask == 1 ) || ((pin != 16 ) && (waveform [i ].gpioMask == 1 << pin ))) {
325
347
wave = (Waveform * ) & (waveform [i ]);
326
348
break ;
327
349
}
@@ -334,16 +356,16 @@ int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t
334
356
wave -> nextTimeLowCycles = MicrosecondsToCycles (timeLowUS );
335
357
wave -> timeLeftCycles = MicrosecondsToCycles (runTimeUS );
336
358
if (!wave -> enabled ) {
337
- wave -> state = 1 ;
338
- digitalWrite ( pin , 1 );
339
- wave -> timeHighCycles = MicrosecondsToCycles (timeHighUS );
340
- wave -> timeLowCycles = MicrosecondsToCycles (timeLowUS );
341
- wave -> nextEventCycles = wave -> timeHighCycles ;
359
+ wave -> state = 0 ;
360
+ // 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
+ wave -> nextServiceCycle = GetCycleCount () + MicrosecondsToCycles ( 1 ) ;
342
364
wave -> enabled = 1 ;
343
365
if (!timerRunning ) {
344
366
initTimer ();
345
367
}
346
- ReloadTimer (10 ); // Cause an interrupt post-haste
368
+ ReloadTimer (MicrosecondsToCycles ( 1 ) ); // Cause an interrupt post-haste
347
369
}
348
370
cli ();
349
371
return true;
@@ -352,7 +374,7 @@ int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t
352
374
// Stops a waveform on a pin
353
375
int stopWaveform (uint8_t pin ) {
354
376
for (size_t i = 0 ; i < countof (waveform ); i ++ ) {
355
- if (((pin == 16 ) && waveform [i ].gpioPin16 ) || ((pin != 16 ) && (waveform [i ].gpioPin == pin ))) {
377
+ if (((pin == 16 ) && waveform [i ].gpio16Mask ) || ((pin != 16 ) && (waveform [i ].gpioMask == 1 << pin ))) {
356
378
sei ();
357
379
waveform [i ].enabled = 0 ;
358
380
int cnt = stepQCnt ;
@@ -366,6 +388,7 @@ int stopWaveform(uint8_t pin) {
366
388
return true;
367
389
}
368
390
}
391
+ cli ();
369
392
return false;
370
393
}
371
394
@@ -463,95 +486,92 @@ static ICACHE_RAM_ATTR uint32_t ProcessSteppers(uint32_t deltaCycles) {
463
486
}
464
487
465
488
static ICACHE_RAM_ATTR void timer1Interrupt () {
489
+ uint32_t nextEventCycles ;
490
+ #if F_CPU == 160000000
491
+ uint8_t cnt = 20 ;
492
+ #else
493
+ uint8_t cnt = 10 ;
494
+ #endif
495
+
496
+ do {
497
+ nextEventCycles = MicrosecondsToCycles (MAXIRQUS );
498
+ for (size_t i = 0 ; i < countof (waveform ); i ++ ) {
499
+ Waveform * wave = & waveform [i ];
500
+ uint32_t now ;
501
+
502
+ // If it's not on, ignore!
503
+ if (!wave -> enabled ) {
504
+ continue ;
505
+ }
506
+
507
+ // Check for toggles
508
+ now = GetCycleCount ();
509
+ if (now >= wave -> nextServiceCycle ) {
510
+ wave -> state = !wave -> state ;
511
+ if (wave -> state ) {
512
+ SetGPIO (wave -> gpioMask );
513
+ if (wave -> gpio16Mask ) {
514
+ GP16O |= wave -> gpio16Mask ; // GPIO16 write slow as it's RMW
515
+ }
516
+ wave -> nextServiceCycle = now + wave -> timeHighCycles ;
517
+ wave -> timeHighCycles = wave -> nextTimeHighCycles ;
518
+ nextEventCycles = min_u32 (nextEventCycles , wave -> timeHighCycles );
519
+ } else {
520
+ ClearGPIO (wave -> gpioMask );
521
+ if (wave -> gpio16Mask ) {
522
+ GP16O &= ~wave -> gpio16Mask ;
523
+ }
524
+ wave -> nextServiceCycle = now + wave -> timeLowCycles ;
525
+ wave -> timeLowCycles = wave -> nextTimeLowCycles ;
526
+ nextEventCycles = min_u32 (nextEventCycles , wave -> timeLowCycles );
527
+ }
528
+ } else {
529
+ uint32_t deltaCycles = wave -> nextServiceCycle - now ;
530
+ nextEventCycles = min_u32 (nextEventCycles , deltaCycles );
531
+ }
532
+ }
533
+ } while (-- cnt && (nextEventCycles < MicrosecondsToCycles (4 )));
534
+
466
535
uint32_t curCycleCount = GetCycleCount ();
467
536
uint32_t deltaCycles = curCycleCount - lastCycleCount ;
468
537
lastCycleCount = curCycleCount ;
469
538
539
+ // Check for timed-out waveforms out of the high-frequency toggle loop
470
540
for (size_t i = 0 ; i < countof (waveform ); i ++ ) {
471
541
Waveform * wave = & waveform [i ];
472
-
473
- // If it's not on, ignore!
474
- if (!wave -> enabled ) {
475
- continue ;
476
- }
477
-
478
- // Check for timed-out waveforms
479
542
if (wave -> timeLeftCycles ) {
480
- uint32_t newTimeLeftCycles = wave -> timeLeftCycles - deltaCycles ;
481
543
// Check for unsigned underflow with new > old
482
- if (( deltaCycles >= wave -> timeLeftCycles ) || ( newTimeLeftCycles <= CYCLES_FLUFF ) ) {
544
+ if (deltaCycles >= wave -> timeLeftCycles ) {
483
545
// Done, remove!
484
546
wave -> enabled = false;
485
- if (wave -> gpioPin16 ) {
486
- GP16O &= ~1 ;
487
- } else {
488
- ClearGPIO (1 << wave -> gpioPin );
489
- }
547
+ ClearGPIO (wave -> gpioMask );
548
+ GP16O &= ~wave -> gpio16Mask ;
490
549
} else {
550
+ uint32_t newTimeLeftCycles = wave -> timeLeftCycles - deltaCycles ;
491
551
wave -> timeLeftCycles = newTimeLeftCycles ;
492
552
}
493
553
}
494
-
495
- // Check for toggles
496
- uint32_t newNextEventCycles = wave -> nextEventCycles - deltaCycles ;
497
- if ((deltaCycles >= wave -> nextEventCycles ) || (newNextEventCycles <= CYCLES_FLUFF )) {
498
- wave -> state = !wave -> state ;
499
- if (wave -> state ) {
500
- if (wave -> gpioPin16 ) {
501
- GP16O |= 1 ;
502
- } else {
503
- SetGPIO (1 << wave -> gpioPin );
504
- }
505
- wave -> nextEventCycles = wave -> timeHighCycles ;
506
- wave -> timeHighCycles = wave -> nextTimeHighCycles ;
507
- } else {
508
- if (wave -> gpioPin16 ) {
509
- GP16O &= ~1 ;
510
- } else {
511
- ClearGPIO (1 << wave -> gpioPin );
512
- }
513
- wave -> nextEventCycles = wave -> timeLowCycles ;
514
- wave -> timeLowCycles = wave -> nextTimeLowCycles ;
515
- }
516
- } else {
517
- wave -> nextEventCycles = newNextEventCycles ;
518
- }
519
- }
520
-
521
- uint32_t nextEventCycles = MicrosecondsToCycles (MAXIRQUS );
522
- for (size_t i = 0 ; i < countof (waveform ); i ++ ) {
523
- if (waveform [i ].enabled ) {
524
- nextEventCycles = min_u32 (nextEventCycles , waveform [i ].nextEventCycles );
525
- }
526
554
}
527
555
528
556
if (stepQCnt ) {
529
557
nextEventCycles = min_u32 (nextEventCycles , ProcessSteppers (deltaCycles ));
530
558
}
531
559
532
- // Adjust back by the time we spent in here
533
- deltaCycles = GetCycleCount () - lastCycleCount ;
534
- // Add in IRQ delay, from measurements on idle system
535
560
#if F_CPU == 160000000
536
- deltaCycles += MicrosecondsToCycles (1 ) + (MicrosecondsToCycles (1 ) >> 1 );
537
- #else
538
- deltaCycles += MicrosecondsToCycles (3 );
539
- #endif
540
- if (nextEventCycles > deltaCycles ) {
541
- nextEventCycles -= deltaCycles ;
561
+ if (nextEventCycles <= 5 * MicrosecondsToCycles (1 )) {
562
+ nextEventCycles = MicrosecondsToCycles (1 ) / 2 ;
542
563
} else {
543
- nextEventCycles = CYCLES_FLUFF ;
564
+ nextEventCycles -= 5 * MicrosecondsToCycles ( 1 ) ;
544
565
}
545
-
546
- // Keep next call within sane min/max time
547
- if (nextEventCycles < CYCLES_FLUFF ) {
548
- nextEventCycles = CYCLES_FLUFF ;
549
- } else if (nextEventCycles > MicrosecondsToCycles (MAXIRQUS )) {
550
- nextEventCycles = MicrosecondsToCycles (MAXIRQUS );
551
- }
552
- #if F_CPU == 160000000
553
566
nextEventCycles = nextEventCycles >> 1 ;
567
+ #else
568
+ if (nextEventCycles <= 6 * MicrosecondsToCycles (1 )) {
569
+ nextEventCycles = MicrosecondsToCycles (1 ) / 2 ;
570
+ } else {
571
+ nextEventCycles -= 6 * MicrosecondsToCycles (1 );
572
+ }
554
573
#endif
574
+
555
575
ReloadTimer (nextEventCycles );
556
576
}
557
577
0 commit comments