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

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 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:
  1. Loading: 1 cycle, executed only once, plus
  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:
  2. Modified clock sources, selected by fuse settings:
  3. The external or internal oscillator signal can be divided by
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

Speaker on port pin PB0 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
	ldi R16,c1 ; Load constant
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
Tone generation with an ATtiny13 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

If you need lower frequencies than 294 Hz: either 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

©2009-2019 by http://www.avr-asm-tutorial.net