Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: Bug in delayMicroseconds: 25% too short for const delay < 64us

  1. #1

    Bug in delayMicroseconds: 25% too short for const delay < 64us

    Function delayMicroseconds(delay) for AVR Teensies has a significant bug that causes delays to execute in only 75% of the requested time, when both of the following are true:

    -- The requested delay is known to be a constant at compile time, AND
    -- The requested delay is < 64usec

    The bug is in:

    C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy\cor e_pins.h,

    Code:
    if (__builtin_constant_p(usec)) {
    [...]
      if (tmp > 0) {
        if (tmp < 256) {
          uint8_t tmp2 = tmp;
          asm volatile(
            "L_%=_loop:"               // 1 to load
              "subi %0, 1"  "\n\t"     // 2
               // "nop\n\t"            // Uncomment to fix the problem. 
               "brne L_%=_loop" "\n\t" // 2 (1 on last)
               : "=d" (tmp2)
               : "0" (tmp2)
          );
        } else { [loop with correct timing] }
      } else { another different loop with correct timing }
    The problem is revealed by the comment for subi, which indicates 2 cycles, when the Atmel doc says only 1 cycle. If you add the nop I show, then the timing works properly.

    For testing, I used:

    Code:
    const int ledPin = 6;
    [...]
    const long delayus = 50;
    
    //----------------
    void loop() {
    //----------------
      while (true) {
        digitalWriteFast(ledPin, HIGH);   // set the LED on
        delayMicroseconds(delayus);                 
        digitalWriteFast(ledPin, LOW);    // set the LED off
        delayMicroseconds(delayus);                 
      }  
    }
    I observe the results on a digital scope, and it shows the period is only 75.4usec, when it should be 100usec (plus while loop overhead). Adding the NOP as described above fixes the problem. Doing either of the following also fixed the problem:
    -- requesting a delay >= 64 ((so that (tmp < 256) is false)
    -- deleting the "const" before "long delayus = 50"

    Further details: I used Arduino 1.8.4 and Teensyduino 1.38, both downloaded two days ago.

    As a side note, there may be libraries which use delayMicroseconds for bit-banging and so on, and may have adjusted to the incorrect timing provided by this function.

    -- Graham

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    15,709
    I've put this on my list of bugs to fix. It's probably too late to get into 1.39, but it's on the list for 1.40.

  3. #3
    Quote Originally Posted by PaulStoffregen View Post
    I've put this on my list of bugs to fix. It's probably too late to get into 1.39, but it's on the list for 1.40.
    Thanks Paul

  4. #4

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •