Inaccuracy of delayMicroseconds()


i have timing-critical application, , i'm trying use delaymicroseconds control pulse width. works wonderfully @ higher values, @ ~10 it's off number of clock cycles.

code: [select]

#define strobe_port porte
const int strobepin = 4;
unsigned int strobetime = 10;

void setup()
{
pinmode(2, output);
digitalwrite(2, low);
}

void loop()
{
if ( correctserialinput )
{
powerpulse();
}
}

void powerpulse()
{
 if ( strobetime <= 10000 )
 {
 cli();
 sbi(strobe_port, strobepin);
 delaymicroseconds(strobetime);
 cbi(strobe_port, strobepin);
 sei();
 }
}

pulse width: 9.675us

the critical code between sbi() , cbi(), controls width of pulse. thought i'd take @ assembly code:

code: [select]

 sbi(strobe_port, strobepin);
 36:      74 9a             sbi      0x0e, 4      ; 14
 delaymicroseconds(strobetime);
 38:      c9 01             movw      r24, r18
 3a:      0e 94 00 00       call      0      ; 0x0 <_z10powerpulsev>
                 3a: r_avr_call      delaymicroseconds
 cbi(strobe_port, strobepin);
 3e:      74 98             cbi      0x0e, 4      ; 14


there's movw , call: 1 + 5 = 6. now, taking @ function-

delaymicroseconds:
code: [select]

#if f_cpu >= 16000000l
     // 16 mhz clock on arduino boards

     // one-microsecond delay, return.  the overhead
     // of function call yields delay of approximately 1 1/8 us.
     if (--us == 0)
  0:      01 97             sbiw      r24, 0x01      ; 1
  2:      01 f0             breq      .+0            ; 0x4 <delaymicroseconds+0x4>
                 2: r_avr_7_pcrel      .text.delaymicroseconds+0x12
           return;

     // following loop takes quarter of microsecond (4 cycles)
     // per iteration, execute 4 times each microsecond of
     // delay requested.
     us <<= 2;
  4:      88 0f             add      r24, r24
  6:      99 1f             adc      r25, r25
  8:      88 0f             add      r24, r24
  a:      99 1f             adc      r25, r25

     // account time taken in preceeding commands.
     us -= 2;
  c:      02 97             sbiw      r24, 0x02      ; 2
     // can't subtract more or we'd overflow w/ small delays.
     us--;
#endif

     // busy wait
     __asm__ __volatile__ (
  e:      01 97             sbiw      r24, 0x01      ; 1
 10:      01 f4             brne      .+0            ; 0x12 <delaymicroseconds+0x12>
                 10: r_avr_7_pcrel      .text.delaymicroseconds+0xe
 12:      08 95             ret


instruction - cycles
sbiw - 2
breq - 1 (condition false)
add - 1
adc - 1
add - 1
adc - 1
sbiw - 2
(the us--; different #ifdef branch , isn't compiled)

once in loop starts subtracting variable, changed since passed:
r25/r24 = 10
sbiw 1 -> 9
us <<= 2 -> 36
sbiw 2 -> 34


for = 34 = 2, sbiw takes 2 clock cycles, brne takes 2 (condition true).

33*4 = 132

in last loop, reaches 0, brne takes 1 cycle, plus return: 2+1+5 = 8.

summing cycles in delaymicroseconds: 9 + 132 + 8 = 149.
add 6 before: 155 clock cycles.

155/16 = 9.6875us approximately i'm seeing.

adding of clock cycles involved function, get:

5 + 9 + 4( 4(us-1) - 2 - 1 ) + 3 + 5

simplifying yields: 16us - 6. error of 6 clock cycles or 0.375us. @ 10us, -3.75% error high application, , quite possibly others.

a simple solution follows:
replace "us -= 2;" "us -= 1;". reduce error -2 clock cycles, remedied adding 2 nop's.

it might wise indicate 6 cycle error in reference. there still overhead in setting function, , can vary. reducing error 0 means setup overhead cause unavoidable positive error. if user knows error, easy compensate figuring out setup overhead, , adding nop's bring 6 cycles.

quote
a difference of 5 cycles. gives?


call/return overhead?

just guess.


Arduino Forum > Forum 2005-2010 (read only) > Software > Syntax & Programs > Inaccuracy of delayMicroseconds()


arduino

Comments

Popular posts from this blog

CAN'T INSTALL MAMBELFISH 1.5 FROM DIRECTORY - Joomla! Forum - community, help and support

error: expected initializer before 'void'

CPU load monitoring using GPIO and leds - Raspberry Pi Forums