I am using avr-gcc and avrdude to write programs onto an ATMega8515 micro-controller. I have got the blinking LED program working without a hitch. However, when I started to use interrupts and introduce functions other than main() to the code, I came across bugs. Though I could compile the program and write it onto the chip, it did not run as expected - the LEDs that should have been blinking were completely unresponsive. With tweaking I found out that the introduction of any function, not just an interrupt service routine, caused this issue.
I came across near identical issues here:
https://stackoverflow.com/questions/65427371/why-does-my-isr-declaration-break-my-program
"Now, none of the LEDs blink. Even weirder, none of them blink when I remove the sei(). The only way I've found to make the first LED blink again is to comment out the ISR declaration"
And here:
AVR ATmega32 - C - Gets stuck in function call
"it's just the same statements as before, moved to the pulse_init() function. When I upload this code the timer is set up correctly and the output pulse is OK, but the program never starts blinking the LEDs on PC0..1."
To be clear, these are the commands I am using to compile and write the code to the ATMega:
avr-gcc main.c -O2 -o main.elf
avr-objcopy main.elf -O ihex main.hex
avrdude -c usbasp -p m8515 -U flash:w:"main.hex":a
And this is a sample code snippet that does not work:
#ifndef F_CPU
#define F_CPU 1000000UL // 16 MHz clock speed
#endif
#define __AVR_ATmega8515__
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile uint8_t toggle_blinking = 1;
int main()
{
sei(); /* set global interrupt enable */
MCUCR = 0b00000100; /* Set the INT1 to trigger on any logic change*/
GICR = 0b10000000;
DDRC = 0xFF; // Makes PORTC as output
DDRD=0xe0;
while(1)
{
if(toggle_blinking)
{
PORTC = 0xFF; //Turns ON All LEDs
// _delay_ms(500); //1 second delay
// _delay_ms(500); //1 second delay
}
else
{
PORTC= 0x00; //Turns OFF All LEDs
}
}
}
ISR(INT1_vect)
{
toggle_blinking ^= 1;
}
The common denominator between all of these programs (mine, and the two linked above) is the use of the avr-gcc optimization flag (-O) which is there to ensure that the util/delay.h
functions run correctly. I compiled a program which did not work with the optimization flag again, this time without the optimization flag. And sure enough, the program worked.
To clarify, I am not sure whether other function definitions are "breaking" the program, or if they are just being run instead of main(). Here is the object dump when running running avr-objdump -d main.elf
on the .elf file that was generated by compiling the above program with optimization enabled:
00000000 <__ctors_end>:
0: 10 e0 ldi r17, 0x00 ; 0
2: a0 e6 ldi r26, 0x60 ; 96
4: b0 e0 ldi r27, 0x00 ; 0
6: ea e6 ldi r30, 0x6A ; 106
8: f0 e0 ldi r31, 0x00 ; 0
a: 03 c0 rjmp .+6 ; 0x12 <__zero_reg__+0x11>
c: c8 95 lpm
e: 31 96 adiw r30, 0x01 ; 1
10: 0d 92 st X+, r0
12: a2 36 cpi r26, 0x62 ; 98
14: b1 07 cpc r27, r17
16: d1 f7 brne .-12 ; 0xc <__zero_reg__+0xb>
00000018 <__vector_2>:
18: 1f 92 push r1
1a: 0f 92 push r0
1c: 0f b6 in r0, 0x3f ; 63
1e: 0f 92 push r0
20: 11 24 eor r1, r1
22: 8f 93 push r24
24: 9f 93 push r25
26: 80 91 60 00 lds r24, 0x0060 ; 0x800060 <__data_start>
2a: 91 e0 ldi r25, 0x01 ; 1
2c: 89 27 eor r24, r25
2e: 80 93 60 00 sts 0x0060, r24 ; 0x800060 <__data_start>
32: 9f 91 pop r25
34: 8f 91 pop r24
36: 0f 90 pop r0
38: 0f be out 0x3f, r0 ; 63
3a: 0f 90 pop r0
3c: 1f 90 pop r1
3e: 18 95 reti
00000040 <main>:
40: 78 94 sei
42: 84 e0 ldi r24, 0x04 ; 4
44: 85 bf out 0x35, r24 ; 53
46: 80 e8 ldi r24, 0x80 ; 128
48: 8b bf out 0x3b, r24 ; 59
4a: 8f ef ldi r24, 0xFF ; 255
4c: 84 bb out 0x14, r24 ; 20
4e: 80 ee ldi r24, 0xE0 ; 224
50: 81 bb out 0x11, r24 ; 17
52: 9f ef ldi r25, 0xFF ; 255
54: 80 91 60 00 lds r24, 0x0060 ; 0x800060 <__data_start>
58: 88 23 and r24, r24
5a: 29 f0 breq .+10 ; 0x66 <main+0x26>
5c: 95 bb out 0x15, r25 ; 21
5e: 80 91 60 00 lds r24, 0x0060 ; 0x800060 <__data_start>
62: 81 11 cpse r24, r1
64: fb cf rjmp .-10 ; 0x5c <main+0x1c>
66: 15 ba out 0x15, r1 ; 21
68: f5 cf rjmp .-22 ; 0x54 <main+0x14>
And here is the dump from the compiled program without optimization enabled:
00000000 <__ctors_end>:
0: 10 e0 ldi r17, 0x00 ; 0
2: a0 e6 ldi r26, 0x60 ; 96
4: b0 e0 ldi r27, 0x00 ; 0
6: ea ea ldi r30, 0xAA ; 170
8: f0 e0 ldi r31, 0x00 ; 0
a: 03 c0 rjmp .+6 ; 0x12 <__zero_reg__+0x11>
c: c8 95 lpm
e: 31 96 adiw r30, 0x01 ; 1
10: 0d 92 st X+, r0
12: a2 36 cpi r26, 0x62 ; 98
14: b1 07 cpc r27, r17
16: d1 f7 brne .-12 ; 0xc <__zero_reg__+0xb>
00000018 <main>:
18: cf 93 push r28
1a: df 93 push r29
1c: cd b7 in r28, 0x3d ; 61
1e: de b7 in r29, 0x3e ; 62
20: 78 94 sei
22: 85 e5 ldi r24, 0x55 ; 85
24: 90 e0 ldi r25, 0x00 ; 0
26: 24 e0 ldi r18, 0x04 ; 4
28: e8 2f mov r30, r24
2a: f9 2f mov r31, r25
2c: 20 83 st Z, r18
2e: 8b e5 ldi r24, 0x5B ; 91
30: 90 e0 ldi r25, 0x00 ; 0
32: 20 e8 ldi r18, 0x80 ; 128
34: e8 2f mov r30, r24
36: f9 2f mov r31, r25
38: 20 83 st Z, r18
3a: 84 e3 ldi r24, 0x34 ; 52
3c: 90 e0 ldi r25, 0x00 ; 0
3e: 2f ef ldi r18, 0xFF ; 255
40: e8 2f mov r30, r24
42: f9 2f mov r31, r25
44: 20 83 st Z, r18
46: 81 e3 ldi r24, 0x31 ; 49
48: 90 e0 ldi r25, 0x00 ; 0
4a: 20 ee ldi r18, 0xE0 ; 224
4c: e8 2f mov r30, r24
4e: f9 2f mov r31, r25
50: 20 83 st Z, r18
52: 80 91 60 00 lds r24, 0x0060 ; 0x800060 <__data_start>
56: 88 23 and r24, r24
58: 39 f0 breq .+14 ; 0x68 <__SREG__+0x29>
5a: 85 e3 ldi r24, 0x35 ; 53
5c: 90 e0 ldi r25, 0x00 ; 0
5e: 2f ef ldi r18, 0xFF ; 255
60: e8 2f mov r30, r24
62: f9 2f mov r31, r25
64: 20 83 st Z, r18
66: f5 cf rjmp .-22 ; 0x52 <__SREG__+0x13>
68: 85 e3 ldi r24, 0x35 ; 53
6a: 90 e0 ldi r25, 0x00 ; 0
6c: e8 2f mov r30, r24
6e: f9 2f mov r31, r25
70: 10 82 st Z, r1
72: ef cf rjmp .-34 ; 0x52 <__SREG__+0x13>
00000074 <__vector_2>:
74: 1f 92 push r1
76: 0f 92 push r0
78: 0f b6 in r0, 0x3f ; 63
7a: 0f 92 push r0
7c: 11 24 eor r1, r1
7e: 8f 93 push r24
80: 9f 93 push r25
82: cf 93 push r28
84: df 93 push r29
86: cd b7 in r28, 0x3d ; 61
88: de b7 in r29, 0x3e ; 62
8a: 90 91 60 00 lds r25, 0x0060 ; 0x800060 <__data_start>
8e: 81 e0 ldi r24, 0x01 ; 1
90: 89 27 eor r24, r25
92: 80 93 60 00 sts 0x0060, r24 ; 0x800060 <__data_start>
96: 00 00 nop
98: df 91 pop r29
9a: cf 91 pop r28
9c: 9f 91 pop r25
9e: 8f 91 pop r24
a0: 0f 90 pop r0
a2: 0f be out 0x3f, r0 ; 63
a4: 0f 90 pop r0
a6: 1f 90 pop r1
a8: 18 95 reti
It seems as though the memory address location of main() is being affected by compiler optimizations which is causing the issues. Does anyone have a proper explanation for this and/or a fix that would allow me to use compiler optimizations with interrupt routines?