After some frustration with timing jitter from a short loop like that in delayMicroseconds, I put a set of hundred-nanosecond delay macros together today for bit-banging a second SPI port on my Teensy 3.2 and thought I'd share. Dedicated to the public domain.
The sketch below is what I used to empirically determine the combinations of NOP3, NOP4, and NOP6 to use for each macro in each case. I tried to get them all to conform as closely as possible to a 100-500 ns negative pulse width, from a high setting to a low setting and then back high again, erring on the side of a pulse too long rather than too short. I kept my eye on the positive pulse width, too, though that was intermittently longer (perhaps up to 20%) due to the beginning of the sketch loop.
You can stack these up to get longer delays, although I wouldn't be surprised if there was some non-linearity involved. And if your desired delays get long enough, you're just getting into the territory of delayMicroseconds.
Of course, the delay of digitalWriteFast is inherently included in the delay of each macro. That's probably what you'd want this delay to be used with anyhow.
I'm sure all the macro expansion bloats the compiled code somewhat, especially with longer delays, but I doubt if it adds up to much. Even with an F_CPU of 96MHz and a PAUSE of P5, I'm only seeing this sketch occupy 5% of program storage space.
The sketch below is what I used to empirically determine the combinations of NOP3, NOP4, and NOP6 to use for each macro in each case. I tried to get them all to conform as closely as possible to a 100-500 ns negative pulse width, from a high setting to a low setting and then back high again, erring on the side of a pulse too long rather than too short. I kept my eye on the positive pulse width, too, though that was intermittently longer (perhaps up to 20%) due to the beginning of the sketch loop.
You can stack these up to get longer delays, although I wouldn't be surprised if there was some non-linearity involved. And if your desired delays get long enough, you're just getting into the territory of delayMicroseconds.
Of course, the delay of digitalWriteFast is inherently included in the delay of each macro. That's probably what you'd want this delay to be used with anyhow.
I'm sure all the macro expansion bloats the compiled code somewhat, especially with longer delays, but I doubt if it adds up to much. Even with an F_CPU of 96MHz and a PAUSE of P5, I'm only seeing this sketch occupy 5% of program storage space.
Code:
// Empirically determined by Ed Suominen with an oscilloscope and a good deal of
// pressing Ctrl+U in the Arduino window. No guarantees expressed or implied. Dedicated
// to the public domain.
#define pinNum 13
void setup() {
pinMode(pinNum, OUTPUT);
}
#define NOP3 "nop\n\t""nop\n\t""nop\n\t"
#define NOP4 "nop\n\t""nop\n\t""nop\n\t""nop\n\t"
#define NOP6 "nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"
// P1-5 are 100-500 ns pauses, tested with an oscilloscope (2 second
// display persistence) and a Teensy 3.2 compiling with
// Teensyduino/Arduino 1.8.1, "faster" setting
#if F_CPU == 96000000
#define P1 __asm__(NOP4 NOP4)
#define P2 __asm__(NOP6 NOP6 NOP6)
#define P3 __asm__(NOP6 NOP6 NOP6 NOP6 NOP3)
#define P4 __asm__(NOP6 NOP6 NOP6 NOP6 NOP6 NOP4 NOP4)
#define P5 __asm__(NOP6 NOP6 NOP6 NOP6 NOP6 NOP6 NOP6 NOP4 NOP3)
#elif F_CPU == 72000000
#define P1 __asm__(NOP6)
#define P2 __asm__(NOP6 NOP6)
#define P3 __asm__(NOP6 NOP6 NOP6 NOP3)
#define P4 __asm__(NOP6 NOP6 NOP6 NOP6 NOP4)
#define P5 __asm__(NOP6 NOP6 NOP6 NOP6 NOP4 NOP4 NOP3)
#elif F_CPU == 48000000
#define P1 __asm__(NOP4)
#define P2 __asm__(NOP6 NOP3)
#define P3 __asm__(NOP6 NOP4 NOP3)
#define P4 __asm__(NOP6 NOP6 NOP6)
#define P5 __asm__(NOP6 NOP6 NOP4 NOP4 NOP3)
#endif
#define PAUSE P5
void loop() {
noInterrupts();
digitalWriteFast(pinNum, HIGH); // 1
PAUSE;
digitalWriteFast(pinNum, LOW);
PAUSE;
digitalWriteFast(pinNum, HIGH); // 2
PAUSE;
digitalWriteFast(pinNum, LOW);
PAUSE;
digitalWriteFast(pinNum, HIGH); // 3
PAUSE;
digitalWriteFast(pinNum, LOW);
PAUSE;
interrupts();
}
Last edited: