ldi r16, val
loop:
dec r16
brne loop
The biggest number we can put in val is 255.
Our clock frequency is 16MHz, so the period is T = 1/f = 62.5 x 10-9 seconds per cycle.
We can determine the length of time required for the loop as follows:
# of times # of clocks Total clocks
ldi r16, val 1 1 1
loop:
dec r16 val 1 val
brne loop val 2 2*val-1
The -1 on 2*val-1 is because the BRNE instruction only requires on clock cycle the last time it runs.
With val=255, this works out to 1+255+509 → 47.8 x 10-6 seconds.
This doesn't provide much of a delay… let's consider a nested loop:
# of times # of clocks Total clocks
ldi r17, val1 1 1 1
loop2:
ldi r16, val2 val1 1 val1
loop1:
dec r16 val2*val1 1 val1*val2
brne loop1 val2*val1 2 2*val1*val2
dec r17 val1 1 val1
brne loop2 val1 2 2*val1
To simplify things, we're ignoring assuming that the BRNE execution is 2 cycles all the time.
With val1=val2=255, this works out to 1+255+65025+130050+255+510 → 0.0123 seconds.
If you need a timing loop to provide a delay that is longer than 0.0123 seconds requires at least three nested loops.
Is a memory structure located in SRAM
Typically we make the starting address for the stack at the last available SRAM location (0x85F or RAMEND).
ATmon actually uses the last 32 memory locations for it's stack, so we will initialize our stack to RAMEND-0x20.
There is a special pointer to the stack (called SP)
The stack pointer points to the “top” of the stack.
The SP is 16 bits wide since it contains an address.
Hence, it consists of two registers (SPH and SPL).
We initialize it like this:
ldi r16, HIGH(RAMEND-0x20)
out SPH, r16
ldi r16, LOW(RAMEND-0x20)
out SPL, r16
The stack may be used as a temporary storage area for data.
The PUSH instruction puts data onto the stack.
Each
PUSH should have a corresponding
POP operation.
POP R0 does the following:
Recall that the stack is a Last In/First Out structure.
It can be used to save/restore the values in the registers before/after a call to a subroutine. E.g.,
push r0
push r1
push r2
...
push r31
; call some subroutine
pop r31
...
pop r2
pop r1
pop r0
.nolist
.include "m32def.inc"
.list
.cseg
.org 0
rjmp start
.org 0x2a
start:
ldi r16, HIGH(RAMEND-0x20) ; Initialize stack pointer
out SPH, r16
ldi r16, LOW(RAMEND-0x20)
out SPL, r16
ldi r20, 0x25 ; Initialize registers r20-r22
ldi r21, 0x50
ldi r22, 0x75
push r20 ; Save r20-r22 register values
push r21 ; by placing r20-r22 onto the stack
push r22
; blah blah blah
pop r22 ; Restore r20-r22 registers by
pop r21 ; by popping their values off the stack
pop r20
forever:
rjmp forever ; This loop is tight