cavratmegaavr-gcc

Why are functions executed in the order they are defined and not in the order they are called from the int main() in avr-c?


I am trying to learn AVR C, and was tinkering with the atmega328p microcontroller. I am using the avr-gcc toolchain on Linux Mint to compile and flash my code to the Arduino board.

So I was trying to blink two LED lights, using function calls. I made two functions - one for blinking LED connected to pin 7 and another for blinking LED connected to pin 13 of my Arduino board.

The functions are working, but while I was tinkering with the code, I noticed a strange behavior. The functions are called and executed in the order they are defined in, outside of the main(); and not in the order they are called in from inside the int main().

This is my code

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

void blinkPin13() {
    while(1) {
        DDRB = DDRB | (1 << DDB5);
        PORTB = PORTB | (1 << PORTB5);
        _delay_ms(5000);
        PORTB = PORTB & ~(1 << PORTB5);
        _delay_ms(500);
    }
}

void blinkPin7() {
    while(1) {
        DDRD = DDRD | (1 << DDD7);
        PORTD = PORTD | (1 << PORTD7);
        _delay_ms(1000);
        PORTD = PORTD & ~(1 << PORTD7);
        _delay_ms(500);
    }
}


int main(void) {    
    blinkPin7();
    blinkPin13();
    return 0;
}

and this is the makefile used to compile and flash the code

default:
    avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o led.o led.c
    avr-gcc -o led.bin led.o
    avr-objcopy -O ihex -R .eeprom led.bin led.hex
    sudo avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:w:led.hex

So, when I flash the above code to my Arduino board, the led connected to pin 13 blinks even though the function blinkPin7() is called first. I am noticing that the order of execution of the function always corresponds to the order in which the functions are defined outside of the main(), and not to the order in which they are called from inside the main().

Why is this so?


Solution

  • There is nothing wrong with your code. But your Makefile isn't correct.

    avr-gcc -o led.bin led.o
    

    It does not pass -mmcu=atmega328p in link stage. Without this option, you should get an ld error like this:

    avr:103 architecture of input file `led.o' is incompatible with avr output
    

    Meaning you don't have a target mcu. With the proper linker script, the main() starts from address 0 (reset vector), and everything would work properly. But with the wrong linker script, no startup code and interrupt vector table added, whatever function comes first now will be at address 0 and will start to execute as per what you observed.

    Add the target mcu would fix the problem:

         avr-gcc -o led.bin led.o -mmcu=atmega328p