0
Offline
Sr. Member
Karma: 0
Posts: 267
dinosaur cork
|
 |
« on: October 09, 2007, 07:28:01 pm » |
delayMicroseconds(0) appears to malfunction and return (delay really) a much larger value, instead of returning asap.
I discovered this experimenting with a sound synthesis program with a variable for the delayMicroseconds param.
Maybe this should be in the docs?
I'm pretty sure we don't want to fuss with the function or put a conditional statement in it, and change all the timing.
You can hear this if you set up a speaker or headphone connected to ground on one side and two 5k resistors on the other wire, the other ends of the resistors go to pins 3 & 4 .
void loop() // delayMicroseconds bug? {
for (int x = 1; x < 20; x++){ pinMode(3, OUTPUT); pinMode(4, OUTPUT); digitalWrite(3, HIGH); delayMicroseconds(1); // change this to 0 and listen digitalWrite(4, HIGH); delayMicroseconds(1000); digitalWrite(3, LOW); delayMicroseconds(1); // change this to 0 and listen digitalWrite(4, LOW); delayMicroseconds(1000); pinMode(4, INPUT); pinMode(3, INPUT); } delay(100); }
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Sr. Member
Karma: 0
Posts: 267
dinosaur cork
|
 |
« Reply #1 on: October 12, 2007, 12:00:13 am » |
OK hooking up a speaker is way too much work.
Here's the code
/* Test delayMicroseconds() with param of zero */
int tdelay; unsigned long i, hz; unsigned long time, timeForOnes, timeForZeros; int outPin = 11;
void setup(){ pinMode(outPin, OUTPUT); Serial.begin(9600); Serial.println("start"); }
void loop() { time = millis(); // get start time of loop for (i = 0; i < 4000; i++){ // time 100,000 cycles through the loop delayMicroseconds(1); } timeForOnes = millis() - time; // compute time through inner loop in milliseconds time = millis(); // get start time of loop for (i = 0; i < 4000; i++){ // time 100,000 cycles through the loop delayMicroseconds(0); } timeForZeros = millis() - time; // compute time through inner loop in milliseconds Serial.print("ones = "); Serial.print(timeForOnes, DEC); Serial.print(" zeros = "); Serial.println(timeForZeros, DEC); }
Here's the result:
ones = 11 zeros = 4118
ones = 11 zeros = 4120
ones = 13 zeros = 4119
DelayMicroseconds(0) appears to take about 1026 us.
|
|
|
|
|
Logged
|
|
|
|
|
berlin
Offline
Sr. Member
Karma: 0
Posts: 293
|
 |
« Reply #2 on: October 12, 2007, 04:12:06 pm » |
not sure if it matters, but are you running this on an atmega8 or 168 ? your test output might be wrong though. this is the function definition of delayMicroseconds takne from libs/targets/arduino/wiring.c: /* 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) { uint8_t oldSREG;
// 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. oldSREG = SREG; cli();
// busy wait __asm__ __volatile__ ( "1: sbiw %0,1" "\n\t" // 2 cycles "brne 1b" : "=w" (us) : "0" (us) // 2 cycles );
// reenable interrupts. SREG = oldSREG; }
i did not get into it too deep. but the lines if (--us == 0) return; (BTW: what are the two minus doing there?) look as if they'd serve a close to zero delay. on the other hand, your real short delays (1µs) might disable interrupts to often which affects the millis() function. see the note at the beginning. still it would be cool to get a real answer to your question.
|
|
|
|
|
Logged
|
|
|
|
|
Forum Administrator
Cambridge, MA
Offline
Faraday Member
Karma: 8
Posts: 3532
|
 |
« Reply #3 on: October 12, 2007, 04:16:36 pm » |
delayMicroseconds(0) does in fact, wrap around and give you a long delay, and, yes, we might want to mention that in the docs. Feel free to include it, Paul.
|
|
|
|
|
Logged
|
|
|
|
|
berlin
Offline
Sr. Member
Karma: 0
Posts: 293
|
 |
« Reply #4 on: October 12, 2007, 04:23:06 pm » |
hi mellis, why is that? i'd really like to see where this is happening. could you briefly explain the function to help me get it?
|
|
|
|
|
Logged
|
|
|
|
|
Forum Administrator
Cambridge, MA
Offline
Faraday Member
Karma: 8
Posts: 3532
|
 |
« Reply #5 on: October 12, 2007, 04:28:15 pm » |
Sure. if (--us == 0) return; Is kind of tricky. --us decrements us by 1, then returns the new value. So this will only return if us was 1. If us was 0, it will wrap around to a large positive number (since it's unsigned), meaning that it will take a long time for it to get back to 0.
|
|
|
|
|
Logged
|
|
|
|
|
berlin
Offline
Sr. Member
Karma: 0
Posts: 293
|
 |
« Reply #6 on: October 12, 2007, 04:30:28 pm » |
yeah  thank you.
|
|
|
|
|
Logged
|
|
|
|
|
USA
Offline
Sr. Member
Karma: 0
Posts: 452
Freeduino rocks
|
 |
« Reply #7 on: October 12, 2007, 08:24:22 pm » |
Apparently --us has the same result as us--, but when it is used in a comparison, the -- before us means that C will decrement the value FIRST, before the comparison, while -- after us means that C will decrement the value AFTER the comparison. If you use it us--; or --us; alone, both give the same result. You may say why the creators of C placed such ambiguous operations in the language. Well, once you learn it deeply, it is a language that allows you to write a very compact and intelligently optimized code. 20 years ago, there used to be C programming contests, where you could do very very complex things in just one line of code. Of course the resulting code was write only, and not meant to be read by mere mortals. I consider wiring implementation of delayMicroseconds() a bug... the programmer should have used if (us-- <= 1) return;
Probably he/she assumed that nobody wants to invoke a delay routine to wait 0 units of time... but it was a wrong assumption after all.
|
|
|
|
« Last Edit: October 12, 2007, 08:26:00 pm by nkcelectronics »
|
Logged
|
|
|
|
|
0
Offline
Sr. Member
Karma: 0
Posts: 267
dinosaur cork
|
 |
« Reply #8 on: October 12, 2007, 09:02:31 pm » |
So why don't we fix this ___ instead of documenting it?
As I see it, it would require only one more comparison, which would execute only in the case of 0. And the code should function the same way it does now.
Am I missing something?
PB
|
|
|
|
« Last Edit: October 12, 2007, 09:03:36 pm by paulb »
|
Logged
|
|
|
|
|
Forum Administrator
Cambridge, MA
Offline
Faraday Member
Karma: 8
Posts: 3532
|
 |
« Reply #9 on: October 13, 2007, 12:40:17 am » |
It should probably be fixed, but I was reluctant to change the function (and possibly its timing) and introduce slight incompatibilities for timing sensitive code. jims has done some nice work on redoing the whole timing system to make it much more precise and flexible; I'm hoping to incorporate his work soon. It seemed better to wait until then to change things.
|
|
|
|
|
Logged
|
|
|
|
|
USA
Offline
Sr. Member
Karma: 0
Posts: 452
Freeduino rocks
|
 |
« Reply #10 on: October 26, 2007, 12:17:20 pm » |
So why don't we fix this ___ instead of documenting it?
As I see it, it would require only one more comparison, which would execute only in the case of 0. And the code should function the same way it does now.
Am I missing something?
PB Using the code I posted before you don't need one extra comparison.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Jr. Member
Karma: 0
Posts: 79
Combat, please!
|
 |
« Reply #11 on: November 14, 2007, 12:48:18 pm » |
Postdecrement (value--) returns the value of the variable before the operation, and thus requires a temporary value to be created to hold that different value. think of the operation as a function: int postdec(int& val) { int temp = val; val = val -1; return temp; }
Predecrement doesn't require the use of a compiler generated temporary and is therefore quicker, less resource hungry. int predecrement(int& val) { val = val - 1; return val; }
If there was no overhead to calling a function then delay(0) might make some sense. As it is, the function would have to execute in negative time in order to return at precisely the same moment it was called  I think the designers got it right. Delay(0) is pointless, and coding for it would only waste space. Just my £0.01. Charlie.
|
|
|
|
|
Logged
|
|
|
|
|
berlin
Offline
Sr. Member
Karma: 0
Posts: 293
|
 |
« Reply #12 on: November 14, 2007, 01:05:59 pm » |
i guess hard-coding a zero doesn't make sense here. still there's a big chance to invoke delayMicroseconds(0) if the parameter is dynamic, like "howManyButtonsPressed" to make it simple.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Jr. Member
Karma: 0
Posts: 79
Combat, please!
|
 |
« Reply #13 on: November 15, 2007, 08:12:59 am » |
Then that's where the check needs to be - not in the library! 
|
|
|
|
|
Logged
|
|
|
|
|
berlin
Offline
Sr. Member
Karma: 0
Posts: 293
|
 |
« Reply #14 on: November 15, 2007, 10:57:39 am » |
i agree, now that someone found out we should keep this in mind, i just meant to underline that. peace,kuk
|
|
|
|
|
Logged
|
|
|
|
|
|