Path: Home => AVR overview => Time loops => using an 8 bit register    (Diese Seite in Deutsch: )  Timing loop with an 8 bit register in AVR assembler

Here the most simple time delay loop in one 8 bit register. Even though this only provides very short delays, it is useful to understand it because it provides the basic knowledge to step to other, more useful but also more complicated solutions. Calculating times, executed instructions etc. have to be learned here.

Coding an 8 bit loop in assembler

In assembler, such an 8 bit delay loop looks like that:

.equ c1 = 200 ; Define number of loop executions as a constant
ldi R16,c1 ; Instruction: load a register with this constant
Loop: ; Loop starts
dec R16 ; Instruction: Decrease register value by one, if zero set Z flag in SREG
brne Loop ; Instruction: if not zero jump to label Loop:, otherwise continue, uses Z in SREG
Practically the constant c1 determines the number of loop executions. As an 8 bit register can only hold 256 different numbers, the resolution is rather limited.

Controller clocks

The time that the controller needs to go through this delay loop is depending from two basic things:
• the number of clock cycles that each executed instruction requires (obviously more than the three that the loop consists of, because of the repetitions),
• the time that each clock cycle requires.
The number of clock cycles that are needed for each instruction are listed in the data books of the AVRs, close to the book's end in a chapter called "Instruction Set Summary", in the column ""#Clocks". According to this our delay loop instructions need the following number of clock cycles:

.equ c1 = 200 ; No instruction, no clock cycles, solely for the assembler
ldi R16,c1 ; 1 clock cycle
Loop: ; Loop start
dec R16 ; 1 clock cycle
brne Loop ; 2 clock cycles when zero flag is clear, 1 clock cycle when zero flag is set
The number of clock cycles therefore is:
2. Loop: 1 + 2 = 3 cycles when jumping back, plus
3. Loop end: 1 + 1 = 2 cycles when not jumping back at the last loop execution.
The number of clock cycles for the loop therefore is
ncycles = 1 + 3 * (c1 - 1) + 2

When multiplying the bracket by 3 the following results:
ncycles = 1 + 3 * c1 - 3 + 2

or even simpler:
ncycles = 3 * c1

For our above formulation with c1 = 200 the number of clock cycles is 3 * 200 = 600.

A special situation occurs, if we set c1 to 0: when the DEC instruction is first executed, the register "underflows" and reaches 255. As this does not set the Z flag in the status register SREG, the loop further executes normal. In that case the loop executes 256 times until the decreased register reaches zero again. So the maximum delay with an 8 bit register is 256 * 3 = 768 clock cycles.

Clock frequency of the AVR

The duration for each clock cycle is 1 divided by the clock frequency of the AVR. At 1 MHz that is 1 / 1,000,000 = 0.000,001 seconds or 1 µs.

It isn't that simple to find out at which clock frequency the AVR works as there are many opportunities to manipulate that:
1. As shipped: with the internal RC oscillator:
• without the CLKDIV8 fuse set: 8 MHz (ATtiny13: 9.6 MHz),
• default: with the CLKDIV8 fuse set: internal RC oscillator divided by 8,
• the frequency of the internal RC oscillator can be modified in certain limits by writing values to the OSCCAL port by overwriting the default content in this port,
2. Modified clock sources, selected by fuse settings:
• another internal RC oscillator (e.g. 128 kHz in an ATtiny13), or
• an external clock (RC oscillator, a crystal oscillator) supplied to the CLOCK1/XTAL1 input pin, or
• an external crystal or resonator on XTAL1 and XTAL2, oscillated with an internal inverter stage.
3. The external or internal oscillator signal can be divided by
• 8 by setting the CLKDIV8 fuse, or
• by 1, 2, 4, 8, 16, 32, 64 or 128 by writing to the CLKPR port, either on startup only or on the fly at any time by the software.
If unmodified you'll find the default clock in the data book in the chapter "System Clock and Clock Options" resp. in the sub-chapter "Default Clock Source".

Time delay

With the number of clock cycles ncycles and the the clock frequency the time delay by the 8 bit loop is
tdelay[seconds] = ncycles / fclock[Hz]

So, with an ATtiny13 and its default settings (fclock = 1.2 MHz) the range of time delays is between 3*1/1,200,000 (= 2.5µs) and 3*256/1,200,000 (= 640µs). If you have set CLKPR to a divide by a higher rate (e.g. 128 instead of the default 8) the delays are by a factor of 128 / 8 = 16-fold longer, roughly 10ms max.

Extending delay

With the following formulation some further delay can be reached:

.equ c1 = 200 ; 0 cycles, solely executed by the assembler
ldi R16,c1 ; 1 cycle
Loop: ; Loop start
nop ; do nothing, 1 cycle
nop ; do nothing, 1 cycle
nop ; do nothing, 1 cycle
nop ; do nothing, 1 cycle
nop ; do nothing, 1 cycle
dec R16 ; 1 cycle
brne Loop ; 2 cycles if not zero, 1 cycle when zero
Now each loop cycle (except for the last one) needs eight clock cycles and the formula changes to
ncycles = 1 + 8 * (c1 - 1) + 7 = 8 * c1

This prolongs the delay by a factor of 8 / 3 = 2.667. But still not enough delay for blinking, but enough for a tone generation program.

The tone generator program With our c1 of 200, we can produce a tone of 586 Hz in an attached speaker. To avoid too high DC currents, we use an electrolytical capacitor in between. If you assemble the following source code and burn its hex into an ATtiny13's flash memory, you'll get that tone.

.nolist ; Switch listing off
.include "tn13def.inc" ; assembles for an ATtiny13
.list
.equ c1 = 0 ; Defines the tone height (factually is 256!)
sbi DDRB,0 ; Port bit as output
Loop:
sbi PORTB,0 ; Port bit output to high
Loop1:
nop
nop
nop
nop
nop
dec R16
brne Loop1
cbi PORTB,0 ; Portbit to low
ldi R16,c1
Loop2:
nop
nop
nop
nop
nop
dec R16
brne Loop2
rjmp Loop That is the program in the simulator avr_sim. It produces a nice rectangle with 50% pulse width and a frequency of 292.54 Hz. As we delay by 256 loop cycles, this is the lowest we can get.

For those who need to generate other frequencies, here is the formula. The number of cycles here is the sum from
1. two cycles for the SBI,
2. the first loop with 8 * c1 cycles,
3. two cycles for the CBI,
4. the second loop with 8 * c1 cycles,
5. two cycles for the RJMP.
And
ncycles = 2 + 8 * c1 + 2 + 8 * c1 + 2 = 16 * c1 + 6 = 4,102

The time delay of the whole loop is
tloop = 4,102 / 1,200,000 = 3.4183 ms

And for the frequency,
ftone = 1,000 / 3.4183 = 292.54 Hz

Exactly as simulated.

If you need c1 for a certain frequency the formula is:
tloop [seconds] = 1 / ftone[Hz]
tloop[seconds] = ncycles / fclock[Hz]
ncycles = tloop[seconds] * fclock[Hz]
ncycles = 16 * c1 + 6
c1 = (ncycles - 6) / 16
c1 = (tloop[seconds] * fclock[Hz] - 6) / 16
c1 = (1 / ftone[Hz] * fclock[Hz] - 6) / 16
c1 = (fclock / ftone - 6) / 16

So, if you need 440 Hz (chamber tone A), you'll have to set c1 to 170. If you need 2 kHz, set it to 37 (produces exactly 2006.7 Hz).

If you need higher frequency of more accuracy, either
• remove the NOPs from the loop,
• clear the CLKDIV8 fuse, and/or
• write a smaller clock divider value to CLKPR, and/or
• use a higher clock frequency.

If you need lower frequencies than 294 Hz: either
• increase the number of NOPs inserted, and/or
• increase the clock divider rate in CLKPR, and/or
• use a lower frequency RC oscillator internally, and/or
• supply a lower external clock.
You see: lots of options to tailor those to your needs.

Remember: this is exact as long as the controller does nothing else than counting loops (and as exact its clock frequency is). But: it is by far more exact if programmed in assembler (because the controller does nothing else and is fully under your complete control) than in any other language or control structure.

To the top of that page