Sign in Join
Wiki copytemporary

AVR Embedded Tutorial - Delays: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: AVR Embedded Tutorial - Delays

OldNewLine
1+## Delays for ATmega328 / Arduino
2+
3+... and of course other AVR controllers.
4+
5+Accurate timing on the AVR controllers is actually very simple - if you do it in assembler. Simple loops in Pascal, on the other hand, cannot be precisely timed, because you never know how the compiler will build the loop next time.
6+
7+For example, with compiler option -o1, a for loop with a 16bit counter variable is created, the same loop with -o2 and -o3 with 8 bit. This makes the loop almost twice as fast.
8+
9+## Short delays in the microsecond range
10+
11+``` pascal
12+ {$ goto on} // must be specified
13+
14+ procedure delay_short();
15+ label
16+ loop;
17+ begin
18+ asm
19+ ldi r16, 60
20+ loop:
21+ nop
22+ dec r16
23+ brne loop
24+ end ['r16'];
25+ end;
26+```
27+
28+You have to try out the size of the counter variable. The loop lasts 4 clock cycles, so at 8MHz 2 loops would be one microsecond. In addition, there is a jump into the routine and the compiler tinkers with some stack pointer and register backup.
29+
30+## Longer delays in the millisecond range
31+
32+``` pascal
33+ {$ goto on} // must be specified
34+
35+ // pause msec, 1 to 255 msec
36+
37+ procedure delay_ms(time: uint8);
38+ const
39+ fmul = 1 * fcpu div 1000000;
40+ label
41+ loop1, loop2, loop3;
42+ begin
43+ asm
44+ ldd r20, time
45+ loop1:
46+ ldi r21, fmul
47+ loop2: // 1000 * fmul = 1000 * 1 * 8 = 8000 cycles / 8MHz
48+ idi r22, 250
49+ loop3: // 4 * 250 = 1000 cycles
50+ nop
51+ dec r22
52+ brne loop3
53+ dec r21
54+ brne loop2
55+ dec r20
56+ brne loop1
57+ end ['r20', 'r21', 'r22'];
58+ end;
59+```
60+
61+With this loop you get pretty accurate timing in the range 1 to 255msec. The loop may be interrupted by interrupts and then, of course, it will take longer.
62+
63+The inner loop lasts 4 clock cycles per run, ergo 1000 cycles. The middle loop makes it 1msec depending on the clock frequency (1 pass at 1Mhz, 8 passes at 8MHz, 16 passes at 16MHz). The outer loop then corresponds to the number of milliseconds.
64+
65+**Caution!** fmul, fcpu must be constants. Then the compiler calculates the value when compiling and uses it permanently. The compiler would insert an integer division as variables and you don't really want that - in addition, the assignment ldi to a variable goes wrong.
66+
67+## Even longer delays
68+
69+... in seconds? Really, it doesn't have to be that way. Already 50msec can be taken at startup when the controller still has to wait for the peripherals. But long delays in the program flow are bad style and there are always better options.
70+
71+## See also
72+
73+- [[AVR Embedded Tutorial|AVR Embedded Tutorials]] - Overview page
74+
75+---
76+*From the Free Pascal wiki, page "AVR Embedded Tutorial - Delays", as it stood on 2021-12-05 after a change by Ccrause, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
77+Category: AVR
78+Category: Arduino
79+Category: Embedded
80+Category: Tutorials

Back to history