avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-gcc-list] Setting pin to high in function instead of main, instruct


From: Richard Zetterberg
Subject: [avr-gcc-list] Setting pin to high in function instead of main, instructions in main never run?
Date: Thu, 01 Mar 2012 11:25:20 +0100
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20120216 Thunderbird/10.0.2

I have a ATmega328-PU chip which I have programmed with a bare minimum
program which sets PB0 to output and then runs a function which sets the
pin to HIGH. The problem is that the voltage output of the pin is at
10-20% of what it should be, identical to what it would be if the pin
was set as input and the pull upp would be active. However if I set the
function as static, it works as expected. I have tried this on 3
ATMega328-PU's with default fuse settings to minimize the things that
could contribute to the problem.

I was hoping someone with better knowledge of avr-gcc could help me
explain this behavior. My guess is that the instruction setting the pin
to output is somehow never run so when setting the pin to HIGH it is
actually in input mode and turns on the pull up resistor. But why?

So, to get started. Here's the bare minimum program and makefile with
information about the platform. I've included 3 different code examples
of when the program behaves as expected.

=== // Bare minimum start (faulty behavior) ===

#include <avr/io.h>

void turn_on_pb(void);

int main(void)
{
        DDRB |= (1 << PB0);
        turn_on_pb();

        for (;;) {

        }

        return 0;
}

void turn_on_pb(void)
{
        PORTB |= (1 << PB0);
}

--- --- Disassembly start --- ---

00000000 <turn_on_pb>:
        return 0;
}

void turn_on_pb(void)
{
        PORTB |= (1 << PB0);
   0:   28 9a           sbi     0x05, 0 ; 5
}
   2:   08 95           ret

00000004 <main>:

void turn_on_pb(void);

int main(void)
{
        DDRB |= (1 << PB0);
   4:   20 9a           sbi     0x04, 0 ; 4
        turn_on_pb();
   6:   0e 94 00 00     call    0       ; 0x0 <turn_on_pb>
   a:   00 c0           rjmp    .+0             ; 0xc <main+0x8>

--- --- Disassembly end --- ---

=== \\ Bare minimum end ===


Here's the code and disassembly of the function set to static which
works as expected:

=== // Static bare minimum start (expected behavior) ===

#include <avr/io.h>

static void turn_on_pb(void);

int main(void)
{
        DDRB |= (1 << PB0);
        turn_on_pb();

        for (;;) {

        }

        return 0;
}

static void turn_on_pb(void)
{
        PORTB |= (1 << PB0);
}

--- --- Disassembly start --- ---

00000000 <main>:

static void turn_on_pb(void);

int main(void)
{
        DDRB |= (1 << PB0);
   0:   20 9a           sbi     0x04, 0 ; 4
        return 0;
}

static void turn_on_pb(void)
{
        PORTB |= (1 << PB0);
   2:   28 9a           sbi     0x05, 0 ; 5
   4:   00 c0           rjmp    .+0             ; 0x6 <__zero_reg__+0x5>

--- --- Disassembly end --- ---

=== \\ Static bare minimum end ===



=== // Bare minimum setting portb by hexadecimal begin (expected
behaviour) ===

#include <avr/io.h>

static void turn_on_pb(void);

int main(void)
{
        DDRB |= (1 << PB0);
        turn_on_pb();

        for (;;) {

        }

        return 0;
}

static void turn_on_pb(void)
{
        PORTB = 0xFF;
}

--- --- Disassembly start --- ---

00000000 <main>:

static void turn_on_pb(void);

int main(void)
{
        DDRB |= (1 << PB0);
   0:   20 9a           sbi     0x04, 0 ; 4
        return 0;
}

static void turn_on_pb(void)
{
        PORTB = 0xFF;
   2:   8f ef           ldi     r24, 0xFF       ; 255
   4:   85 b9           out     0x05, r24       ; 5
   6:   00 c0           rjmp    .+0             ; 0x8 <__zero_reg__+0x7>

--- --- Disassembly end --- ---

=== \\ Bare minimum setting portb by hexadecimal end ===


=== // Bare minimum setting portb in main begin (expected behaviour) ===

#include <avr/io.h>

int main(void)
{
        DDRB |= (1 << PB0);
        PORTB |= (1 << PB0);

        for (;;) {

        }

        return 0;
}

--- --- Disassembly start --- ---

00000000 <main>:
#include <avr/io.h>

int main(void)
{
        DDRB |= (1 << PB0);
   0:   20 9a           sbi     0x04, 0 ; 4
        PORTB |= (1 << PB0);
   2:   28 9a           sbi     0x05, 0 ; 5
   4:   00 c0           rjmp    .+0             ; 0x6 <__zero_reg__+0x5>

--- --- Disassembly end --- ---


=== \\ Bare minimum setting portb in main end ===


The platform I use is OS X 10.7.3 with the following tools in the
compilation and upload:

- avr-gcc 4.5.1
- avr-objcopy 2.20.1.20100303
- avr-objdump 2.20.1.20100303
- avrdude 5.11.1

And here's my makefile:

=== // Make file begin ===

main:
        avr-gcc -g -Os -Wall -mmcu=atmega328 -c ../src/example.c

elf:
        avr-gcc example.o -o example.elf

hex:
        avr-objcopy -O ihex example.elf example.hex

dump:
        avr-objdump -h -S example.o > example.lst

upload:
        avrdude -p m328 -c avrispmkII -P usb -U flash:w:example.hex

clean:
        rm -f *.o
        rm -f *.hex
        rm -f *.lst
        rm -f *.elf

=== \\ Make file end ===


And here's how I used the different commands to produce program, dump
and upload program:

make clean // remove old files
make // compile
make elf // run the linker
make hex // turn in to hex to upload
make dump // produce disassembly
make upload // upload to the chip

Thank you for taking time helping me



reply via email to

[Prev in Thread] Current Thread [Next in Thread]