Electronic – AVR asm wait loop explain

assemblyavrdelayloop

Can someone please explain me this code (it is from wait loop calculator), I cannot clearly understand calculation.

; Delay 1 600 000 cycles
; 100ms at 16 MHz

ldi  r18, 9       ;1 clock cycle
ldi  r19, 30      ;1 clock cycle
ldi  r20, 229     ;1 clock cycle
L1: dec  r20      ;1 clock cycle
brne L1           ;2 clock cycle
dec  r19          ;1 clock cycle
brne L1           ;2 clock cycle
dec  r18          ;1 clock cycle
brne L1           ;2 clock cycle
nop               ;1 clock cycle

Best Answer

The code loads 9, 30, and 229 into registers r18, r19, and r20, respectively. Then it decrements these registers in a triple nested loop. The outermost loop runs 9 times. dec, ldi, and nop always take 1 cycle. brne takes 1 cycle plus one extra cycle when it branches. On the first iteration of the outer loop, the middle loop runs 30 times. On the first iteration of the middle loop, the inner loop runs 229 times. The dec instructions decrement the registers and then the brne instructions compare the result with zero - each loop will run until the associated register is zero, at which point execution will 'fall through' to the next instruction. If the register is zero on entering the loop, dec will cause it to wrap around to 255. So the first time a loop is run, it will run until the counter is zero. This results in 256 iterations when a loop is started with 0 in the corresponding register.

The ldi and nop instructions take 4 cycles in total. The inner loop requires 3 cycles for each iteration except the last one which requires 2, so the first time around this is 229*3-1 cycles and subsequent iterations are 256*3-1 cycles. The other loops follow the same sequence, adding 3 cycles for each iteration except the last. If you factor in all of the loops, you get:

3+229*3-1+3+(256*3-1+3)*29-1+3+((256*3-1+3)*256-1+3)*8-1+1 = 1600000

3 for the ldi instructions, 229*3-1 for the first inner loop, 3 for the first middle loop iteration, (256*3-1+3)*29-1 for the rest of the first middle loop, 3 for the first outer loop, ((256*3-1+3)*256-1+3)*8-1 for the rest of the outer loop, and 1 for the final nop.

That equation can be rewritten as:

6+229*3+770*(30-1)+197122*(9-1)+1

where the 229, 30, 9 and 1 correspond to the 3 constants and the number of trailing nop instructions. You can calculate the three loop count constants by working backwards from largest to smallest, then adding 0, 1, or 2 nop instructions to get the exact number of cycles.

For example, recomputing for a 50 ms delay (800000 cycles) would work as follows: 800000/197122 = 4, remainder 11512. 11512/770 = 14, remainder 732. 732/3 = 244, remainder 0. So you would use the constants 4+1=5, 14+1=15, 244-6/3=244-2=242 and add zero extra nop instructions. To check, compute

6+242*3+770*(15-1)+197122*(5-1)+0 = 800000

.