#include <stk200/delay.c>
instead of requiring us to type the entire path like this:
#include "C:/Atmel/WinAVR/avr/include/stk200/delay.c"
The following program has two source files: sampleC.c and configB.s. The program turns every other LED on and then toggles all of the state of the LEDs every 0.5 seconds.
This source file has two functions:
/* sampleC.c -- Sample program that causes every other LED to toggle on and * off every half second. * Configuration: PORTB must be connected to eight LEDs. * Dependencies: configB.s and stk200/delay.c * (You do not need to include standard libraries in this list.) * Author: t a y l o r@msoe.edu * Date: 5-4-2007 */ #include <avr/io.h> /* Contains I/O port declarations */ #include <inttypes.h> /* Contains C99 type declarations */ #include <avr/interrupt.h> /* Contains interrupt related functions */ #include <stk200/delay.c> /* Contains delay function */ /* Configures PORTB for I/O based on the mask * Parameters: * mask -- 8-bit mask with 1 indicating output and 0 indicating input * Assembly implementation in configB.s */ extern void configPortB(uint8_t mask); /* Selects one of two bit patterns * Parameters: * type -- selects the desired bit pattern * return: * 0b10101010 if type==1 * 0b01010101 if type!=1 * C implementation in this file. */ uint8_t getPattern(uint8_t type); /* Causes every other LED to toggle on and off every half second. * return: * never */ int main(void) { sei(); /* Sets global interrupt flag so ATmon works */ configPortB(0xff); /* Configure all pins on PORTB for output */ while(1) /* Loop forever */ { PORTB = getPattern(0); /* Turn every other light on */ delay_ms(500); /* Pass for 0.5 seconds */ PORTB = getPattern(1); /* Toggle all the lights on/off */ delay_ms(500); /* Pass for 0.5 seconds */ } return 0; /* We never get here */ } uint8_t getPattern(uint8_t type) { uint8_t pattern = 0b01010101; if(type==1) { pattern = 0b10101010; } return pattern; }
The assembly source file contains the confgPortB function.
#define _SFR_ASM_COMPAT 1
#define __SFR_OFFSET 0 /* Required for port labels to work as expected */
#include <avr/io.h> /* Contains I/O port declarations */
#define temp r16 /* Associate temp label with R16 */
.global configPortB ; Make configPortB function visible to other source files.
.section .text ; Start program section
; Configures PORTB for I/O based on the mask
; Parameters:
; mask -- 8-bit mask with 1 indicating output and 0 indicating input
; Implementation notes:
; The implementation is more complicated than it needs to be. We could
; just send R24 directly out to DDRB.
configPortB:
push temp ; Save temp register on stack
mov temp, r24 ; Copy parameter passed in to temp register
out DDRB, temp ; Configure PORTB
pop temp ; Restore temp register
ret
The results of compiling, assembling, and linking this project are stored in a default folder in the project directory. The listing file looks like this:
sampleC.elf: file format elf32-avr
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 000001a8 00000000 00000000 00000094 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 00800060 000001a8 0000023c 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00800060 000001a8 0000023c 2**0
ALLOC
3 .noinit 00000000 00800060 00800060 0000023c 2**0
CONTENTS
4 .eeprom 00000000 00810000 00810000 0000023c 2**0
CONTENTS
5 .stab 0000036c 00000000 00000000 0000023c 2**2
CONTENTS, READONLY, DEBUGGING
6 .stabstr 00000084 00000000 00000000 000005a8 2**0
CONTENTS, READONLY, DEBUGGING
7 .debug_aranges 00000014 00000000 00000000 0000062c 2**0
CONTENTS, READONLY, DEBUGGING
8 .debug_pubnames 00000044 00000000 00000000 00000640 2**0
CONTENTS, READONLY, DEBUGGING
9 .debug_info 000001c5 00000000 00000000 00000684 2**0
CONTENTS, READONLY, DEBUGGING
10 .debug_abbrev 00000096 00000000 00000000 00000849 2**0
CONTENTS, READONLY, DEBUGGING
11 .debug_line 00000112 00000000 00000000 000008df 2**0
CONTENTS, READONLY, DEBUGGING
Disassembly of section .text: 00000000 <__vectors>: 0: 0c 94 2a 00 jmp 0x54 <__ctors_end> 4: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 8: 0c 94 45 00 jmp 0x8a <__bad_interrupt> c: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 10: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 14: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 18: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 1c: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 20: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 24: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 28: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 2c: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 30: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 34: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 38: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 3c: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 40: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 44: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 48: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 4c: 0c 94 45 00 jmp 0x8a <__bad_interrupt> 50: 0c 94 45 00 jmp 0x8a <__bad_interrupt>
00000054 <__ctors_end>: 54: 11 24 eor r1, r1 56: 1f be out 0x3f, r1 ; 63 Ensure R1 = 0x00 58: cf e5 ldi r28, 0x5F ; 95 Initialize stack pointer 5a: d8 e0 ldi r29, 0x08 ; 8 Initialize stack pointer 5c: de bf out 0x3e, r29 ; 62 0x3e = SPH 5e: cd bf out 0x3d, r28 ; 61 0x3d = SPL 00000060 <__do_copy_data>: 60: 10 e0 ldi r17, 0x00 ; 0 r17=0 62: a0 e6 ldi r26, 0x60 ; 96 X=0x0060 64: b0 e0 ldi r27, 0x00 ; 0 (start of free SRAM) 66: e8 ea ldi r30, 0xA8 ; 168 Z=0x01a8 68: f1 e0 ldi r31, 0x01 ; 1 (end of program) 6a: 02 c0 rjmp .+4 ; 0x70 <.do_copy_data_start> 0000006c <.do_copy_data_loop>: ; Doesn't get here in this case 6c: 05 90 lpm r0, Z+ ; Move from program memory 6e: 0d 92 st X+, r0 ; to data memory 00000070 <.do_copy_data_start>: 70: a0 36 cpi r26, 0x60 ; 96 72: b1 07 cpc r27, r17 74: d9 f7 brne .-10 ; 0x6c <.do_copy_data_loop>
00000076 <__do_clear_bss>: 76: 10 e0 ldi r17, 0x00 ; 0 78: a0 e6 ldi r26, 0x60 ; 96 7a: b0 e0 ldi r27, 0x00 ; 0 7c: 01 c0 rjmp .+2 ; 0x80 <.do_clear_bss_start> 0000007e <.do_clear_bss_loop>: 7e: 1d 92 st X+, r1 00000080 <.do_clear_bss_start>: 80: a0 36 cpi r26, 0x60 ; 96 82: b1 07 cpc r27, r17 84: e1 f7 brne .-8 ; 0x7e <.do_clear_bss_loop> 86: 0c 94 97 00 jmp 0x12e <main> 0000008a <__bad_interrupt>: ; Don't know how to deal with 8a: 0c 94 00 00 jmp 0x0 <__vectors> ; this, just start at reset vector
0000008e <delay_ms>:
// delay for ms milli-seconds
// delay times are only half-way accurate if optimization is turned on!
void delay_ms(uint16_t ms)
{
8e: cf 93 push r28
90: df 93 push r29
92: cd b7 in r28, 0x3d ; 61
94: de b7 in r29, 0x3e ; 62
96: 24 97 sbiw r28, 0x04 ; 4
98: 0f b6 in r0, 0x3f ; 63
9a: f8 94 cli
9c: de bf out 0x3e, r29 ; 62
9e: 0f be out 0x3f, r0 ; 63
a0: cd bf out 0x3d, r28 ; 61
a2: 9a 83 std Y+2, r25 ; 0x02
a4: 89 83 std Y+1, r24 ; 0x01
volatile uint16_t i;
for(i=ms;i>0;i--)
a6: 89 81 ldd r24, Y+1 ; 0x01
a8: 9a 81 ldd r25, Y+2 ; 0x02
aa: 9c 83 std Y+4, r25 ; 0x04
ac: 8b 83 std Y+3, r24 ; 0x03
ae: 8b 81 ldd r24, Y+3 ; 0x03
b0: 9c 81 ldd r25, Y+4 ; 0x04
b2: 00 97 sbiw r24, 0x00 ; 0
b4: 51 f0 breq .+20 ; 0xca <delay_ms+0x3c>
{
delay_us(1000);
b6: 88 ee ldi r24, 0xE8 ; 232
b8: 93 e0 ldi r25, 0x03 ; 3
ba: 0e 94 6e 00 call 0xdc <delay_us>
be: 8b 81 ldd r24, Y+3 ; 0x03
c0: 9c 81 ldd r25, Y+4 ; 0x04
c2: 01 97 sbiw r24, 0x01 ; 1
c4: 9c 83 std Y+4, r25 ; 0x04
c6: 8b 83 std Y+3, r24 ; 0x03
c8: f2 cf rjmp .-28 ; 0xae <delay_ms+0x20>
ca: 24 96 adiw r28, 0x04 ; 4
cc: 0f b6 in r0, 0x3f ; 63
ce: f8 94 cli
d0: de bf out 0x3e, r29 ; 62
d2: 0f be out 0x3f, r0 ; 63
d4: cd bf out 0x3d, r28 ; 61
d6: df 91 pop r29
d8: cf 91 pop r28
da: 08 95 ret
000000dc <delay_us>:
}
}
// delay for us micro-seconds
// delay times are only half-way accurate if optimization is turned on to level 3!
// max value for us is 65535/4*CYCLES_PER_US
// which is app. 17777 for 14.7456MHZ
void delay_us(uint16_t us)
{
dc: cf 93 push r28
de: df 93 push r29
e0: cd b7 in r28, 0x3d ; 61
e2: de b7 in r29, 0x3e ; 62
e4: 24 97 sbiw r28, 0x04 ; 4
e6: 0f b6 in r0, 0x3f ; 63
e8: f8 94 cli
ea: de bf out 0x3e, r29 ; 62
ec: 0f be out 0x3f, r0 ; 63
ee: cd bf out 0x3d, r28 ; 61
f0: 9a 83 std Y+2, r25 ; 0x02
f2: 89 83 std Y+1, r24 ; 0x01
uint16_t _count;
_count=us/4*CYCLES_PER_US;
f4: 89 81 ldd r24, Y+1 ; 0x01
f6: 9a 81 ldd r25, Y+2 ; 0x02
f8: 96 95 lsr r25
fa: 87 95 ror r24
fc: 96 95 lsr r25
fe: 87 95 ror r24
100: 88 0f add r24, r24
102: 99 1f adc r25, r25
104: 88 0f add r24, r24
106: 99 1f adc r25, r25
108: 88 0f add r24, r24
10a: 99 1f adc r25, r25
10c: 9c 83 std Y+4, r25 ; 0x04
10e: 8b 83 std Y+3, r24 ; 0x03
asm volatile (
110: 8b 81 ldd r24, Y+3 ; 0x03
112: 9c 81 ldd r25, Y+4 ; 0x04
114: 01 97 sbiw r24, 0x01 ; 1
116: f1 f7 brne .-4 ; 0x114 <delay_us+0x38>
118: 9c 83 std Y+4, r25 ; 0x04
11a: 8b 83 std Y+3, r24 ; 0x03
11c: 24 96 adiw r28, 0x04 ; 4
11e: 0f b6 in r0, 0x3f ; 63
120: f8 94 cli
122: de bf out 0x3e, r29 ; 62
124: 0f be out 0x3f, r0 ; 63
126: cd bf out 0x3d, r28 ; 61
128: df 91 pop r29
12a: cf 91 pop r28
12c: 08 95 ret
0000012e <main>:
* return:
* never
*/
int main(void)
{
12e: cf e3 ldi r28, 0x3F ; 63
130: d8 e0 ldi r29, 0x08 ; 8
132: de bf out 0x3e, r29 ; 62
134: cd bf out 0x3d, r28 ; 61
sei(); /* Sets global interrupt flag so ATmon works */
136: 78 94 sei
configPortB(0xff); /* Configure all pins on PORTB for output */
138: 8f ef ldi r24, 0xFF ; 255
13a: 0e 94 cf 00 call 0x19e <configPortB>
while(1) /* Loop forever */
{
PORTB = getPattern(0); /* Turn every other light on */
13e: 80 e0 ldi r24, 0x00 ; 0
140: 0e 94 b2 00 call 0x164 <getPattern>
144: 80 93 38 00 sts 0x0038, r24
delay_ms(500); /* Pass for 0.5 seconds */
148: 84 ef ldi r24, 0xF4 ; 244
14a: 91 e0 ldi r25, 0x01 ; 1
14c: 0e 94 47 00 call 0x8e <delay_ms>
PORTB = getPattern(1); /* Toggle all the lights on/off */
150: 81 e0 ldi r24, 0x01 ; 1
152: 0e 94 b2 00 call 0x164 <getPattern>
156: 80 93 38 00 sts 0x0038, r24
delay_ms(500); /* Pass for 0.5 seconds */
15a: 84 ef ldi r24, 0xF4 ; 244
15c: 91 e0 ldi r25, 0x01 ; 1
15e: 0e 94 47 00 call 0x8e <delay_ms>
162: ed cf rjmp .-38 ; 0x13e <main+0x10>
00000164 <getPattern>:
}
return 0; /* We never get here */
}
uint8_t getPattern(uint8_t type)
{
164: cf 93 push r28
166: df 93 push r29
168: cd b7 in r28, 0x3d ; 61
16a: de b7 in r29, 0x3e ; 62
16c: 22 97 sbiw r28, 0x02 ; 2
16e: 0f b6 in r0, 0x3f ; 63
170: f8 94 cli
172: de bf out 0x3e, r29 ; 62
174: 0f be out 0x3f, r0 ; 63
176: cd bf out 0x3d, r28 ; 61
178: 89 83 std Y+1, r24 ; 0x01
uint8_t pattern = 0b01010101;
17a: 85 e5 ldi r24, 0x55 ; 85
17c: 8a 83 std Y+2, r24 ; 0x02
if(type==1)
17e: 89 81 ldd r24, Y+1 ; 0x01
180: 81 30 cpi r24, 0x01 ; 1
182: 11 f4 brne .+4 ; 0x188 <getPattern+0x24>
{
pattern = 0b10101010;
184: 8a ea ldi r24, 0xAA ; 170
186: 8a 83 std Y+2, r24 ; 0x02
}
return pattern;
188: 8a 81 ldd r24, Y+2 ; 0x02
18a: 99 27 eor r25, r25
18c: 22 96 adiw r28, 0x02 ; 2
18e: 0f b6 in r0, 0x3f ; 63
190: f8 94 cli
192: de bf out 0x3e, r29 ; 62
194: 0f be out 0x3f, r0 ; 63
196: cd bf out 0x3d, r28 ; 61
198: df 91 pop r29
19a: cf 91 pop r28
19c: 08 95 ret
Nothing too spectacular happens here. The assembly code was:
0000019e <configPortB>: 19e: 0f 93 push r16 1a0: 08 2f mov r16, r24 1a2: 07 bb out 0x17, r16 ; 23 1a4: 0f 91 pop r16 1a6: 08 95 ret