From d3ba34d3a1ce08b69fedea84d6a5fd8d1ea680e2 Mon Sep 17 00:00:00 2001
From: Cano <gitcow@cano.sk>
Date: Tue, 12 Nov 2013 17:32:57 -0500
Subject: delayMicroseconds(): added support for 1Mhz, 12Mhz and 24Mhz

1Mhz is a default clock speed on Atmega328, many users run it on the
internal 1Mhz clock to save battery power. Up until now
delayMicroseconds() function wasn't taking this frequencies into an
account.
---
 cores/arduino/wiring.c | 78 +++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 68 insertions(+), 10 deletions(-)

diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c
index 5cbe241..6efda6e 100644
--- a/cores/arduino/wiring.c
+++ b/cores/arduino/wiring.c
@@ -119,17 +119,41 @@ void delay(unsigned long ms)
 	}
 }
 
-/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
+/* Delay for the given number of microseconds.  Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */
 void delayMicroseconds(unsigned int us)
 {
+  // call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable)
 	// calling avrlib's delay_us() function with low values (e.g. 1 or
 	// 2 microseconds) gives delays longer than desired.
 	//delay_us(us);
-#if F_CPU >= 20000000L
+#if F_CPU >= 24000000L
+	// for the 24 MHz clock for the aventurous ones, trying to overclock
+
+	// for a one-microsecond delay, simply wait 6 cycles and return. The overhead
+	// of the function call yields a delay of exactly one microsecond.
+	__asm__ __volatile__ (
+		"nop" "\n\t"
+		"nop" "\n\t"
+		"nop" "\n\t"
+		"nop" "\n\t"
+		"nop" "\n\t"
+		"nop"); //just waiting 6 cycles
+	if (--us == 0)
+		return;
+
+	// the following loop takes a 1/6 of a microsecond (4 cycles)
+	// per iteration, so execute it six times for each microsecond of
+	// delay requested.
+	us *= 6; // x6 us
+
+	// account for the time taken in the preceeding commands.
+	us -= 2;
+
+#elif F_CPU >= 20000000L
 	// for the 20 MHz clock on rare Arduino boards
 
-	// for a one-microsecond delay, simply wait 2 cycle and return. The overhead
-	// of the function call yields a delay of exactly a one microsecond.
+	// for a one-microsecond delay, simply wait 2 cycles and return. The overhead
+	// of the function call yields a delay of exactly one microsecond.
 	__asm__ __volatile__ (
 		"nop" "\n\t"
 		"nop"); //just waiting 2 cycle
@@ -152,15 +176,31 @@ void delayMicroseconds(unsigned int us)
 	if (--us == 0)
 		return;
 
-	// the following loop takes a quarter of a microsecond (4 cycles)
+	// the following loop takes 1/4 of a microsecond (4 cycles)
 	// per iteration, so execute it four times for each microsecond of
 	// delay requested.
-	us <<= 2;
+	us <<= 2; // x4 us
 
 	// account for the time taken in the preceeding commands.
 	us -= 2;
-#else
-	// for the 8 MHz internal clock on the ATmega168
+
+#elif F_CPU >= 12000000L
+	// for the 12 MHz clock if somebody is working with USB
+
+	// for a one-microsecond delay, simply return.  the overhead
+	// of the function call yields a delay of approximately 1.5 us.
+	if (--us == 0)
+		return;
+
+	// the following loop takes 1/3 of a microsecond (4 cycles)
+	// per iteration, so execute it three times for each microsecond of
+	// delay requested.
+	us = (us << 1) + us; // x3 us
+
+	// account for the time taken in the preceeding commands.
+	us -= 2;
+#elif F_CPU >= 8000000L
+	// for the 8 MHz internal clock
 
 	// for a one- or two-microsecond delay, simply return.  the overhead of
 	// the function calls takes more than two microseconds.  can't just
@@ -170,14 +210,31 @@ void delayMicroseconds(unsigned int us)
 	if (--us == 0)
 		return;
 
-	// the following loop takes half of a microsecond (4 cycles)
+	// the following loop takes 1/2 of a microsecond (4 cycles)
 	// per iteration, so execute it twice for each microsecond of
 	// delay requested.
-	us <<= 1;
+	us <<= 1; //x2 us
     
 	// partially compensate for the time taken by the preceeding commands.
 	// we can't subtract any more than this or we'd overflow w/ small delays.
 	us--;
+
+#else
+	// for the 1 MHz internal clock (default settings for common Atmega microcontrollers)
+
+	// the overhead of the function calls takes about 16 microseconds.
+	if (us <= 16) //4 cycles spent here
+		return;
+	if (us <= 22) { //4 cycles spent here
+    return;
+	}
+	
+	// compensate for the time taken by the preceeding and next commands.
+	us -= 22;
+
+	// the following loop takes 4 microseconds (4 cycles)
+	// per iteration, so execute it us/4 times
+	us >>= 2; // us div 4
 #endif
 
 	// busy wait
@@ -185,6 +242,7 @@ void delayMicroseconds(unsigned int us)
 		"1: sbiw %0,1" "\n\t" // 2 cycles
 		"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
 	);
+	// return = 4 cycles
 }
 
 void init()
-- 
cgit v1.2.3-18-g5258