Electronic – Using avr-gcc _delay_ms causes chip to freeze

atmegaavrdelay

I have a ATmega328-PU chip which is setup to use the internal oscillator without dividing clock speed by 8. The first thing I did was to use a really simple program I uploaded; a program which turned on and off all pins on PORTB. Like so:

#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/delay.h>

int main(void) {
    DDRB = 0xFF;
        PORTB = 0xFF;

    while(1) {
            PORTB = 0x00;
            _delay_ms(50);
            PORTB = 0xFF;
            _delay_ms(50);
    }

    return 0;
}
  • Update: I have tried what Jon L suggested. Still the same result.
  • Update 2: I have tried what Kevin Vermeer suggested. The chip seems to freeze when it enter the first loop. Using the timer with a value < 65000 makes the LED turn on directly, using a value > 65000 results in the LED never turn on.
  • Update 3: I have tried following with a new identical chip with the same results
  • Update 4: I plugged in simulavr and avr-gdb to see whether I found something, this was the output:

    memory.c:267: WARNING: * * Attempt to write invalid io reg: ADCL at 0x0024
    memory.c:267: WARNING: * * Attempt to write invalid io reg: ADCH at 0x0025
    memory.c:267: WARNING: * * Attempt to write invalid io reg: ADCH at 0x0025
    decoder.h:59: WARNING: Unknown opcode: 0xffff

Then unknown opcode loops forever.

However, when I have uploaded the program it reaches the second instruction in main and then freezes. Leaving all PORTB pins in HIGH. So far I have tried:

  • Different ms between 10 – 1000 to see whether there are some values that can't be used
  • Changed F_CPU to 1000000UL in case it would use CKDIV8.
  • Looping _delay_ms(1) in a separate function until it iterates to the given amount
  • Re-compiled and re-uploaded multiple times
  • Tried resetting multiple times
  • Used different PORTB pins
  • Defined F_CPU from the compiler arguments -DF_CPU=8000000

Why I'm asking here and not stackoverflow.com is because I think I should start to eliminate errors on the lowest level of abstraction, that is; hardware.

So what could be the problem?

Here are some information about my setup:

  • Operating system: OS X 10.7.3
  • Programmer: AVRisp MKII
  • Uploader: avrdude
  • Compiler: avr-gcc
  • Bin 2 hex: avr-objcopy

Fuse settings:

avrdude: safemode: lfuse reads as E2
avrdude: safemode: hfuse reads as D9
avrdude: safemode: efuse reads as 7

Input into AVR fuse calculator:

Fuse settings in AVR fuse calculator

makefile:

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

hex:
        avr-objcopy -j .text -j .data -O ihex example.o 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

Pins used on chip:

  • Pin 7 (VCC): 5 volts supply
  • Pin 8 (GND): ground
  • Pin 14 (PB0): resistor and LED

Best Answer

I suspect the problem is not with your C code but with your Makefile.

The following lines in your Makefile produce an example.o object file.

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

The created .o file only contains the symbols and code from example.c, not the additional source required to actually make it run on a target system such as interrupt vector jump tables and code to initialise the BSS RAM segment to zeros, and load your initialised data sections.

You'll need to add an additional line something like this to run the linker and produce an output object suitable for download to the AVR part. Alternatively, use avr-ld, but you'll have to work out all the required linker options.

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

You can use avr-objdump --disassemble-all <filename> on both example.o and main.elf yourself to verify the different content of each file.

It's always a good idea to try to reduce your problem in steps to the most simple example possible. In this case, it would probably mean dropping into the AVR Studio software and creating a project running on the simulator using their managed build process. From there, you could them export the Makefile in use by their build process by using the 'Export Makefile' menu option. The generated makefile could then be compared with your version.

Actually, it's probably a good idea to use a Makefile similar to the one generated by AVR Studio because it has the correct rules already defined, you just have to set up some variables with regard to which objects need to be generated and the final target file name.