delayMicroseconds() does not delay as it should

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi there,
i already struggle hours with this strange problem. Please see the comment in the code for the details. Note that these are actually 2 sourcecodes right after each other.

 


void setup(){
    DDRB |= (1 << PB1);
}
void loop(){

    unsigned long longy = millis(); //ERROR in Ecplise (ProMicro and Attiny85 - starts at about 37us) / ERROR in Arduino IDE (ProMicro - Attiny unknown)

    //unsigned long longy = 3000; // WORKS AS EXPECTED in Eclipse (ProMicro and Attiny85) / WORKS AS EXPECTED in Arduino IDE (ProMicro - Attiny unknown)

    PORTB |= (1 << PB1);
    delayMicroseconds(longy / 1000);
    PORTB &= ~(1 << PB1);

    delay(1000);
}

void setup(){
    DDRB |= (1 << PB1);
}

void loop(){
    unsigned int tempADC = (unsigned int) (millis() / 1000);

    PORTB |= (1 << PB1);

    delayMicroseconds(tempADC); // ERROR in Eclipse (delay starts from about 37us ProMicro and Attiny85) / WORKING in Arduino IDE (ProMicro - Attiny unknown)

    //delay(tempADC); // WORKING in Ecplise (ProMicro and Attiny85) / WORKING in Arduino IDE (ProMicro - Attiny unknown)

    PORTB &= ~(1 << PB1); delay(1000); 

}
Last Edited: Tue. Feb 20, 2018 - 01:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You say "does not delay as it should" - but what, exactly, does it do?

 

How are you observing it?

 

The documentation is here: https://www.arduino.cc/reference/en/language/functions/time/delaymicroseconds/

 

Did you see this note:

This function works very accurately in the range 3 microseconds and up.

We cannot assure that delayMicroseconds will perform precisely for smaller delay-times.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Tue. Feb 20, 2018 - 01:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The delay starts from 37us and goes up (as it shoult with = millis() /1000, but it should start from about 3us). But this is wrong. See where the comment say it works as it should. I observed it with a DSO.

Last Edited: Tue. Feb 20, 2018 - 01:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Tobey wrote:
The delay starts from 37us and goes up (as it shoult with = millis() /1000, but it should start from about 3us).
Between the pin toggles you have not only the time from the delay, but also the time that is needed to calculate the division.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good point. But thats only in the first example, not in the second.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tobey wrote:
But thats only in the first example, not in the second.
Have you checked the generated assembler code? It is very well possible that the compiler moved the initialization of the variable (and therefore the division) to the place where the variable is used the first time.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tobey wrote:
The delay starts from 37us and goes up (as it shoult with = millis() /1000, but it should start from about 3us). But this is wrong. See where the comment say it works as it should. I observed it with a DSO.
  Yeah, well,

We do not have your DSO, nor do we have any info on what values you put into your microDelay() nor any info on what delays you actually got.

 

Eric Steven Raymond has some good info on "how to ask questions the smart way":
http://www.catb.org/~esr/faqs/sm...

 

I find a USD 8 Logic analyser (search 8ch 24MHz on Ali / Ebay) very handy for looking at stuf like this. ( I use mine with Sigrok / Pulseview).

With such a logic analyser you can use a uC pin to output some squiggly waves between all the lines  and have a very fast and neat overview of timing.

#define TOGGLE (1<<3)

void toggle( uint8_t number) {
    for( ; number; --number) {
        PORTB |= TOGGLE;
        PORTB &= ~TOGGLE;
    }
}

void loop(){
    unsigned int tempADC;
    toggle( 2);
    tempADC = (unsigned int) (millis() / 1000);
    toggle( 3);
    PORTB |= (1 << PB1);
    toggle( 4);
    delayMicroseconds(tempADC); // ERROR in Eclipse, yeah eclipse is bad.
    toggle( 213);
    digitalWrite( Earth, OFF);  // Will take about a week.
    toggle ( 21);
    PORTB &= ~(1 << PB1); delay(1000);
    toggle( 42) // Answer to everything.
}

While typing the above saw that you have differences compared on how you compiled (eclipse versus arduino).

Make some LSS files and look at the assembly the compiler spits out.

 

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

Last Edited: Tue. Feb 20, 2018 - 03:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tobey wrote:

The delay starts from 37us and goes up (as it shoult with = millis() /1000, but it should start from about 3us). But this is wrong. See where the comment say it works as it should. I observed it with a DSO.

Paulvdh wrote:
We do not have your DSO, nor do we have any info on what values you put into your microDelay() nor any info on what delays you actually got.

Indeed.

 

Posting the DSO screenshot would have helped.

 

Instructions for posting images here: https://www.avrfreaks.net/comment...

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the first example, you use fixed timings, but in the second it looks like you want to vary the time using the ADC...

The ADC will take at least 100us to do a conversion, I would expect the Arduino ENV to be some what slower...

 

 

Jim

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just checked it, and its true. Oh my gosh didnt know that!

 

Now i understand!

But how can i prevent this moving of initiatzitions of variables? Thats pretty bad, since i put it there on purpose! Also the millis() is wrong then? Or if it would be micros()?

Last Edited: Tue. Feb 20, 2018 - 03:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
Posting the DSO screenshot would have helped.
No it would not. A DSO trace without the accompanying values put into the delay routine is useless.

ki0bk wrote:
The ADC will take at least 100us to do a conversion, I would expect the Arduino ENV to be some what slower...
>Hence my suggestion to use a LA and put some toggles() between each line of source code. Then you can easily time each line.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another Test:

void setup(){
  DDRB |= (1 << PB1);
}
void loop(){
	PORTB |=  (1 << PB1);
	unsigned int tempADC = millis();
	PORTB &=  ~(1 << PB1);


	tempADC = tempADC / 1000;


	PORTB |=  (1 << PB1);

	delayMicroseconds(tempADC); // ERROR in Eclipse (delay starts from about 37us ProMicro and Attiny85) / WORKING in Arduino IDE (ProMicro - Attiny unknown)
	PORTB &=  ~(1 << PB1);


	delay(1000);

}

That last falling edge is moving.

 

Not only the inti, but also the equation gets moved into the delayMicrosseconds() WTF.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Paulvdh wrote:
A DSO trace without the accompanying values put into the delay routine is useless.

Yes, you had already said that - the screenshot would have helped to back-up the information you had already mentioned.

 

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As I said in #11

A scope trace is useless if it is not combined with the actual values in your source code.

 

It seems you are bumping into the fact that everything takes time on a uC.

Using the toggle() I mentioned earlier you can use the 2nd channel of your scope to separate the lines of code from the single scope trace.

But I really recommend a cheap Logic Analyser.

 

And for timing into the us delays (or any acurate timing actually) ditch the delay routines and use a hardware timer.

There is no substitute for using the hardware timers.

They are designed for stuff like this.

Don't waste your time on those delay() routines. They are only meant to be used as a quick hack to blink a led or something when the actual delay is not important.

 

===================

Those simple delay routine's depend on the right #definion of "F_CPU". If that value is off in Eclipse, but not on "arduino" then all your delay functions will be off in eclipse.

 

 

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The tempADC variable is the number of seconds since the AVR has been turned on or reset.  I assume that you are using an Arduino, because of the millis() function.   To do precision learning experiments, I suggest doing a review of using in-line assembly for the Arduino's C++ AVRGCC compiler.   It has weird formatting, but it works and it is consistent.  Check the AVRGCC documentation, or Google for "AVRGCC in-line assembly".  The Adafruit library for the NeoPixel LED module has good examples of in-line assembler.

 

The AVR Mega328P ADC is relatively slow by modern standards.  It takes about 30 microseconds per a 10-bit conversion.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta wrote:
The AVR Mega328P ADC is relatively slow by modern standards. It takes about 30 microseconds per a 10-bit conversion.

30us would be overclocking the ADC, more like 104us given the 16MHz clock on an Arduino!

 

Jim

 

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For 10 bit the "best" rate is 66us (15.3ksps) in fact. (that's scaling the ADC to the optimal 200kHz