Sub micro second pulses
I had a need for sub micro second square wave pulses, so I wrote this. It looks fine on a scope. Comments are appreciated.
I had a need for sub micro second square wave pulses, so I wrote this. It looks fine on a scope. Comments are appreciated.
Code:
// Routine to delay for specified number of nano seconds
// NOTE: minimum pulse width is ~700 nsec, accuracy is ~ -0/+40 ns
// NOTE: you can't trust this code:
// compiler or library changes will change timing overhead
// CPU speed will effect timing
// Jon Zeeff V1.1
// Public Domain
// Written for teensy 3.1
#define LED_PIN 13
void setup() {
delay(1000);
pinMode(LED_PIN, OUTPUT);
Serial.println("hello");
}
void loop() {
//Setup_Nano_Delay(4000000000);
Setup_Nano_Delay(700);
Serial.println("start");
delay(10); // allow start message to go out
noInterrupts();
digitalWriteFast(LED_PIN, 1);
Nano_Delay();
digitalWriteFast(LED_PIN, 0);
interrupts();
Serial.println("stop\n");
delay(2000);
}
// delay for a given number of nano seconds
// less sensitive to interrupts and DMA
// max delay is 4 seconds
constexpr double CLOCK_RATE = 96.00000E6; // MCU clock rate - measure it for best accuracy
constexpr unsigned NANO_OVERHEAD = 470; // overhead - adjust as needed
constexpr unsigned NANO_JITTER = 18; // adjusts for jitter prevention - leave at 18
// prepare before, so less delay later
static uint32_t nano_ticks;
void Setup_Nano_Delay(uint32_t nanos)
{
// set up cycle counter
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
// improve teensy 3.1 clock accuracy
OSC0_CR = 0x2;
// we can't do less than this
if (nanos < NANO_OVERHEAD)
nanos = NANO_OVERHEAD;
// how many cycles to wait
nano_ticks = ((nanos - NANO_OVERHEAD) / (1.0E9 / CLOCK_RATE)) + .5;
if (nano_ticks < NANO_JITTER)
nano_ticks = NANO_JITTER;
} // Setup_Nano_Delay()
// Do the delay specified above.
// You may want to disable interrupts before and after
FASTRUN void Nano_Delay(void)
{
uint32_t start_time = ARM_DWT_CYCCNT;
uint32_t loop_ticks = nano_ticks - NANO_JITTER;
// loop until time is almost up
while ((ARM_DWT_CYCCNT - start_time) < loop_ticks) {
// could do other things here
}
if (NANO_JITTER) { // compile time option
register unsigned r; // for debugging
// delay for the remainder using single instructions
switch (r = (nano_ticks - (ARM_DWT_CYCCNT - start_time))) {
case 18: __asm__ volatile("nop" "\n\t");
case 17: __asm__ volatile("nop" "\n\t");
case 16: __asm__ volatile("nop" "\n\t");
case 15: __asm__ volatile("nop" "\n\t");
case 14: __asm__ volatile("nop" "\n\t");
case 13: __asm__ volatile("nop" "\n\t");
case 12: __asm__ volatile("nop" "\n\t");
case 11: __asm__ volatile("nop" "\n\t");
case 10: __asm__ volatile("nop" "\n\t");
case 9: __asm__ volatile("nop" "\n\t");
case 8: __asm__ volatile("nop" "\n\t");
case 7: __asm__ volatile("nop" "\n\t");
case 6: __asm__ volatile("nop" "\n\t");
case 5: __asm__ volatile("nop" "\n\t");
case 4: __asm__ volatile("nop" "\n\t");
case 3: __asm__ volatile("nop" "\n\t");
case 2: __asm__ volatile("nop" "\n\t");
case 1: __asm__ volatile("nop" "\n\t");
default:
break;
} // switch()
} // if
} // Nano_Delay()
Last edited: