I've created a simple assembler subroutine (asmFunction) that is supposed to toggle the output of PORTD every 10 ms.
Here is the assembler source code :
#define __SFR_OFFSET 0
#include <avr/io.h>
.section .text ; Defines a code section
;initialize
initialize:
ldi r24,0xFF ; set 11111111 value to the r24 register
out DDRD,r24 ; put r24 register value into DDRD register
ldi r24,0x00 ; set the r24 register to 00000000 value
out PORTD,r24 ; put the r24 register value to PORTD
ret ; return from a branch
;wait 100uS
subdelay:
ldi r23,99 ; set register r23 to 99
loop:
dec r23 ; 1 cycle, decrement r23
cpi r23,0 ; 1 cycle, compare r23 and 0
;nop to get exactly 16 clock cycles per loop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
brne loop ; 2 cycles, if r23 not eqal to 0, continue the loop
;wait a bit more (11 cycles to get exactly 100uS of delay
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
ret ; return from branch
;delay x/10 ms (R22)
delay:
ldi r23,100 ; set delay to 100x100uS
loop1:
dec r23 ; decrement r23
cpi r23,0 ; compare r23 to 0
call subdelay; call subdelay routine
brne loop1 ; if r23 is not equal to 0, continue the loop
ret ; otherwise return from the delay branch
.global asmFunction ; makes asm function visible in other source files
asmFunction: ; Start of asmfunc_calledfrom_c subroutine
call initialize ; call initialize branch
while: ; main loop
;turn output high
ldi r24,0xFF
out PORTD,r24
;delay 10mS
call delay
;turn output low
ldi r24,0x00
out PORTD,r24
;delay 10 ms
call delay
rjmp while ; jump to while (for loop to continue existing)
main.c :
#include "avr/io.h"
void asmFunction();
int main()
{
asmFunction();
return 0;
}
And here is disassembled hex file :
Atmega328p_test.elf: file format elf32-avr
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 00000000 00800100 000000f4 00000168 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .text 000000f4 00000000 00000000 00000074 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .comment 00000011 00000000 00000000 00000168 2**0
CONTENTS, READONLY
3 .note.gnu.avr.deviceinfo 00000040 00000000 00000000 0000017c 2**2
CONTENTS, READONLY
Disassembly of section .text:
00000000 <__vectors>:
0: 0c 94 34 00 jmp 0x68 ; 0x68 <__ctors_end>
4: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
8: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
10: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
14: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
18: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
1c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
20: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
24: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
28: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
2c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
30: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
34: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
38: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
3c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
40: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
44: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
48: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
4c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
50: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
54: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
58: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
5c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
60: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
64: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
00000068 <__ctors_end>:
68: 11 24 eor r1, r1
6a: 1f be out 0x3f, r1 ; 63
6c: cf ef ldi r28, 0xFF ; 255
6e: d8 e0 ldi r29, 0x08 ; 8
70: de bf out 0x3e, r29 ; 62
72: cd bf out 0x3d, r28 ; 61
74: 0e 94 73 00 call 0xe6 ; 0xe6 <main>
78: 0c 94 78 00 jmp 0xf0 ; 0xf0 <_exit>
0000007c <__bad_interrupt>:
7c: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>
00000080 <initialize>:
80: 8f ef ldi r24, 0xFF ; 255
82: 8a b9 out 0x0a, r24 ; 10
84: 80 e0 ldi r24, 0x00 ; 0
86: 8b b9 out 0x0b, r24 ; 11
88: 08 95 ret
0000008a <subdelay>:
8a: 73 e6 ldi r23, 0x63 ; 99
0000008c <loop>:
8c: 7a 95 dec r23
8e: 70 30 cpi r23, 0x00 ; 0
...
a8: 89 f7 brne .-30 ; 0x8c <loop>
...
be: 00 00 nop
c0: 08 95 ret
000000c2 <delay>:
c2: 74 e6 ldi r23, 0x64 ; 100
000000c4 <loop1>:
c4: 7a 95 dec r23
c6: 70 30 cpi r23, 0x00 ; 0
c8: 0e 94 45 00 call 0x8a ; 0x8a <subdelay>
cc: d9 f7 brne .-10 ; 0xc4 <loop1>
ce: 08 95 ret
000000d0 <asmFunction>:
d0: 0e 94 40 00 call 0x80 ; 0x80 <initialize>
000000d4 <while>:
d4: 8f ef ldi r24, 0xFF ; 255
d6: 8b b9 out 0x0b, r24 ; 11
d8: 0e 94 61 00 call 0xc2 ; 0xc2 <delay>
dc: 80 e0 ldi r24, 0x00 ; 0
de: 8b b9 out 0x0b, r24 ; 11
e0: 0e 94 61 00 call 0xc2 ; 0xc2 <delay>
e4: f7 cf rjmp .-18 ; 0xd4 <while>
000000e6 <main>:
e6: 0e 94 68 00 call 0xd0 ; 0xd0 <asmFunction>
ea: 80 e0 ldi r24, 0x00 ; 0
ec: 90 e0 ldi r25, 0x00 ; 0
ee: 08 95 ret
000000f0 <_exit>:
f0: f8 94 cli
000000f2 <__stop_program>:
f2: ff cf rjmp .-2 ; 0xf2 <__stop_program>
The problem is that when I'm running this code on my atmega328p microcontroler, it produces the signal with the period of 200 uS.
It seems that the subdelay
subroutine executes normally and produces 100uS of delay but for some reason loop1
inside delay
subroutine does not work which cause the subdelay
subroutine to be executed only ones.
The question is : what am I doing wrong?
You use r23 inside both delay and subdelay. You need to save it’s value before calling subdelay and restore it afterwards, either with a push and a pop, or storing it in a specific memory location.