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.
pulse width: 9.675us
the critical code between sbi() , cbi(), controls width of pulse. thought i'd take @ assembly code:
there's movw , call: 1 + 5 = 6. now, taking @ function-
delaymicroseconds:
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.
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
Post a Comment