Question

I don't know how to precisely described the error I am seeing. If I set up my port register in main() everything works as intended. However if I try to do it in a function, the program halts.

main.c:

__attribute__((OS_main)) int main(void);
int main(void) {                                           
    DDRD = 0xF0;
    PORTD = 0xF0;
    led( LED_GREEN, true );
    while( true );
}

This turns on the green LED. However if I move the port setup to a seperate function nothing happens, like so:

__attribute__((OS_main)) int main(void);
int main(void) {                                           
    hwInit();  
    led( LED_GREEN, true );
    while( true );
}

The culprit seems to be the attribute line because if I comment it out the second example works as expected. My problem is understanding why, since as I understand it the OS_main attribute should only tell the compiler that it should not store any registers upon entry or exit to the function. Is this not correct?

Was it helpful?

Solution

The following was compiled with avr-gcc 4.8.0 under ArchLinux. The distribution should be irrelevant to the situation, compiler and compiler version however, may produce different outputs. The code:

#include <avr/io.h>

#define LED_GREEN PD7
#define led(p, s) { if(s) PORTD |= _BV(p); \
                else PORTD  &= _BV(p); }

__attribute__((OS_main)) int main(void);
__attribute__((noinline)) void hwInit(void);

void hwInit(void){
    DDRD = 0xF0;
}

int main(void){

    hwInit();
    led(LED_GREEN, 1);

    while(1);
}

Generates:

000000a4 <hwInit>:
  a4:   80 ef           ldi r24, 0xF0   ; 240
  a6:   8a b9           out 0x0a, r24   ; 10
  a8:   08 95           ret

000000aa <main>:
  aa:   0e 94 52 00     call    0xa4    ; 0xa4 <hwInit>
  ae:   5f 9a           sbi 0x0b, 7 ; 11
  b0:   ff cf           rjmp    .-2         ; 0xb0 <main+0x6>

when compiled with avr-gcc -Wall -Os -fpack-struct -fshort-enums -std=gnu99 -funsigned-char -funsigned-bitfields -mmcu=atmega168 -DF_CPU=1000000UL -MMD -MP -MF"core.d" -MT"core.d" -c -o "core.o" "../core.c" and linked accordingly.

Commenting __attribute__((OS_main)) int main(void); from the above sources has no effect on the generated assembly. Curiously, however, removing the noinline directive from hwInit() has the effect of the compiler inlining the function into main, as expected, but the function itself still exists as part of the final binary, even when compiled with -Os.

This leads me to believe that your compiler version/arguments to the compiler are generating some assembly which is not correct. If possible, can you post the disassembly for the relevant areas for further examination?

Edited late to add two contributions, second of which resolves the problem at hand: Hanno Binder states: "In order to remove those 'unused' functions from the binary you would also need -ffunction-sections -Wl,--gc-sections."

Asker adds [paraphrased]: "I followed a tutorial which neglected to mention the avr-objcopy step to create the hex file. I assumed that compiling and linking the project for the correct target was sufficient (which it for some reason was for basic functionality). After having added an avr-objcopy step to generate the file everything works."

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top