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()


Reply With Quote
