関数を呼び出すとなぜかリセットがかかる件について

AVRのプログラムで関数呼び出しすると、なぜかマイコンリセットがかかる現象に悩まされています。

わけがわからないので、以下の簡単なLEDチカチカプログラムでテスト。

  • Osで最適化、ターゲットはATMEL AVR ATMega64です。PC3にLEDのアノードが接続されています。

うまく動けば、0.5秒点灯、5秒点灯を繰り返すはず。

#include <avr/io.h>
#include <util/delay.h>

#define PIN_LED_GREEN	PC3
#define PIN_LED_RED		PC2
#define PIN_LED_POWER	PC5

static void initialize(void);

void FlushLED(uint8_t flag) {
	PORTC |= _BV(PIN_LED_GREEN);
	if(flag) {
		_delay_ms(500);
	} else {
		_delay_ms(5000);
	}
	PORTC &= ~_BV(PIN_LED_GREEN);
	_delay_ms(500);
}

int main(void) {
	initialize();
	for(;;) {
		FlushLED(1);
		FlushLED(0);
	}
	return 0;
}


static void initialize(void)
{
	//PORTC
	//LEDと電源制御用のピンを出力設定
	//その他のピンはプルアップ入力
	DDRC = _BV(PIN_LED_GREEN) | _BV(PIN_LED_RED) | _BV(PIN_LED_POWER);
	PORTC = ~(_BV(PIN_LED_GREEN) | _BV(PIN_LED_RED) | _BV(PIN_LED_POWER));
}

結果:

LEDが約0.5秒ごとに点滅を繰り返す。

一応アセンブラ出力も載せておきます。誰か助けてください><


main.elf: file format elf32-avr

Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000100 00000000 00000000 00000054 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .debug_aranges 00000020 00000000 00000000 00000154 2**0
CONTENTS, READONLY, DEBUGGING
2 .debug_pubnames 00000028 00000000 00000000 00000174 2**0
CONTENTS, READONLY, DEBUGGING
3 .debug_info 000001fe 00000000 00000000 0000019c 2**0
CONTENTS, READONLY, DEBUGGING
4 .debug_abbrev 0000011d 00000000 00000000 0000039a 2**0
CONTENTS, READONLY, DEBUGGING
5 .debug_line 0000018b 00000000 00000000 000004b7 2**0
CONTENTS, READONLY, DEBUGGING
6 .debug_frame 00000030 00000000 00000000 00000644 2**2
CONTENTS, READONLY, DEBUGGING
7 .debug_str 00000110 00000000 00000000 00000674 2**0
CONTENTS, READONLY, DEBUGGING
8 .debug_loc 0000009e 00000000 00000000 00000784 2**0
CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
0: 0c 94 46 00 jmp 0x8c ; 0x8c <__ctors_end>
4: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
8: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
10: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
14: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
18: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
1c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
20: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
24: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
28: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
2c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
30: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
34: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
38: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
3c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
40: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
44: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
48: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
4c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
50: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
54: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
58: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
5c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
60: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
64: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
68: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
6c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
70: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
74: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
78: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
7c: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
80: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
84: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>
88: 0c 94 50 00 jmp 0xa0 ; 0xa0 <__bad_interrupt>

0000008c <__ctors_end>:
8c: 11 24 eor r1, r1
8e: 1f be out 0x3f, r1 ; 63
90: cf ef ldi r28, 0xFF ; 255
92: d0 e1 ldi r29, 0x10 ; 16
94: de bf out 0x3e, r29 ; 62
96: cd bf out 0x3d, r28 ; 61
98: 0e 94 73 00 call 0xe6 ; 0xe6


9c: 0c 94 7e 00 jmp 0xfc ; 0xfc <_exit>

000000a0 <__bad_interrupt>:
a0: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>

000000a4 :
#define PIN_LED_POWER PC5

static void initialize(void);

void FlushLED(uint8_t flag) {
PORTC |= _BV(PIN_LED_GREEN);
a4: ab 9a sbi 0x15, 3 ; 21
if(flag) {
a6: 88 23 and r24, r24
a8: 51 f0 breq .+20 ; 0xbe
aa: 88 e8 ldi r24, 0x88 ; 136
ac: 93 e1 ldi r25, 0x13 ; 19
milliseconds can be achieved.
*/
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
ae: 28 ec ldi r18, 0xC8 ; 200
b0: 30 e0 ldi r19, 0x00 ; 0
b2: f9 01 movw r30, r18
b4: 31 97 sbiw r30, 0x01 ; 1
b6: f1 f7 brne .-4 ; 0xb4
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
b8: 01 97 sbiw r24, 0x01 ; 1
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
ba: d9 f7 brne .-10 ; 0xb2
bc: 09 c0 rjmp .+18 ; 0xd0
be: 80 e5 ldi r24, 0x50 ; 80
c0: 93 ec ldi r25, 0xC3 ; 195
c2: 28 ec ldi r18, 0xC8 ; 200
c4: 30 e0 ldi r19, 0x00 ; 0
c6: f9 01 movw r30, r18
c8: 31 97 sbiw r30, 0x01 ; 1
ca: f1 f7 brne .-4 ; 0xc8
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
cc: 01 97 sbiw r24, 0x01 ; 1
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
ce: d9 f7 brne .-10 ; 0xc6
_delay_ms(500);
} else {
_delay_ms(5000);
}
PORTC &= ~_BV(PIN_LED_GREEN);
d0: ab 98 cbi 0x15, 3 ; 21
d2: 88 e8 ldi r24, 0x88 ; 136
d4: 93 e1 ldi r25, 0x13 ; 19
d6: 28 ec ldi r18, 0xC8 ; 200
d8: 30 e0 ldi r19, 0x00 ; 0
da: f9 01 movw r30, r18
dc: 31 97 sbiw r30, 0x01 ; 1
de: f1 f7 brne .-4 ; 0xdc
{
// wait 1/10 ms
_delay_loop_2(((F_CPU) / 4e3) / 10);
__ticks --;
e0: 01 97 sbiw r24, 0x01 ; 1
__ticks = 1;
else if (__tmp > 65535)
{
// __ticks = requested delay in 1/10 ms
__ticks = (uint16_t) (__ms * 10.0);
while(__ticks)
e2: d9 f7 brne .-10 ; 0xda
_delay_ms(500);
}
e4: 08 95 ret

000000e6

:
static void initialize(void)
{
//PORTC
//LEDと電源制御用のピンを出力設定
//その他のピンはプルアップ入力
DDRC = _BV(PIN_LED_GREEN) | _BV(PIN_LED_RED) | _BV(PIN_LED_POWER);
e6: 8c e2 ldi r24, 0x2C ; 44
e8: 84 bb out 0x14, r24 ; 20
PORTC = ~(_BV(PIN_LED_GREEN) | _BV(PIN_LED_RED) | _BV(PIN_LED_POWER));
ea: 83 ed ldi r24, 0xD3 ; 211
ec: 85 bb out 0x15, r24 ; 21
}

int main(void) {
initialize();
for(;;) {
FlushLED(1);
ee: 81 e0 ldi r24, 0x01 ; 1
f0: 0e 94 52 00 call 0xa4 ; 0xa4
FlushLED(0);
f4: 80 e0 ldi r24, 0x00 ; 0
f6: 0e 94 52 00 call 0xa4 ; 0xa4
fa: f9 cf rjmp .-14 ; 0xee

000000fc <_exit>:
fc: f8 94 cli

000000fe <__stop_program>:
fe: ff cf rjmp .-2 ; 0xfe <__stop_program>


追記

解決しました。結論からいうとATMega103互換動作で動いてました。互換動作中は拡張I/O空間がなくなる分、少しメモリ空間が小さくなります。それによってスタックが割り当てられてたアドレスにはメモリが割り当てられず、関数呼び出しのようなスタックにアクセスする動作をすると落ちてしまったというわけです。

と、いうところまではいいんだけど、なぜ!なぜ!デフォルトの動作がATMega103互換動作なんだああああ!!!!


結論。ATMega64を使うときは、拡張ヒューズビットのM103Cのビットを1(プログラム)にしてから使いましょう。