From bbec45d3df8bb593a2466ded232f5691e470a04f Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 3 Dec 2005 17:03:26 +0000 Subject: [PATCH] Improved accuracy of delayMicroseconds(). --- readme.txt | 1 + targets/arduino/wiring.c | 37 ++++++++++++++++++++++++++++++++++--- targets/arduino/wiring.h | 4 ++-- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/readme.txt b/readme.txt index aa5232545..8ed76c2b1 100644 --- a/readme.txt +++ b/readme.txt @@ -25,6 +25,7 @@ order to read the same physical pin. Now flushing the serial port before uploading (should fix some errors). Added a printNewline() function. Updated icon of the Windows executable. +Improved accuracy of the delayMicroseconds() function. 0002 - 2005.10.05 New build process no longer uses makefiles; now controlled by preferences.txt. diff --git a/targets/arduino/wiring.c b/targets/arduino/wiring.c index 8c657f456..4f2356342 100755 --- a/targets/arduino/wiring.c +++ b/targets/arduino/wiring.c @@ -19,7 +19,7 @@ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - $Id: wiring.c,v 1.7 2005/05/28 21:04:15 mellis Exp $ + $Id$ */ #include @@ -292,9 +292,40 @@ void delay(unsigned long ms) timerPause(ms); } -void delayMicroseconds(unsigned long us) +/* Delay for the given number of microseconds. Assumes a 16 MHz clock. + * Disables interrupts, which will disrupt the millis() function if used + * too frequently. */ +void delayMicroseconds(unsigned int us) { - delay_us(us); + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); + + // for a one-microsecond delay, simply return. the overhead + // of the function call yields a delay of approximately 1 1/8 us. + if (--us == 0) + return; + + // the following loop takes a quarter of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; + + // account for the time taken in the preceeding commands. + us -= 2; + + // disable interrupts, otherwise the timer 0 overflow interrupt that + // tracks milliseconds will make us delay longer than we want. + cli(); + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); + + // reenable interrupts. + sei(); } int main(void) diff --git a/targets/arduino/wiring.h b/targets/arduino/wiring.h index 1b57ffe3c..87ccdd2ce 100755 --- a/targets/arduino/wiring.h +++ b/targets/arduino/wiring.h @@ -19,7 +19,7 @@ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - $Id: wiring.h,v 1.4 2005/05/24 17:47:41 mellis Exp $ + $Id$ */ #ifndef Wiring_h @@ -57,7 +57,7 @@ typedef uint8_t byte; void delay(unsigned long); void delay_ms(unsigned short ms); -void delayMicroseconds(unsigned long us); +void delayMicroseconds(unsigned int us); void pinMode(int, int); void digitalWrite(int, int); int digitalRead(int);