How to compile and burn the code to AVR chip on Linux/MacOSX/Windows ?

This is a quick tutorial for beginners that aims to show how to install tools, compile the code with avr-gcc and send it to the MCU with avrdude. It also introduce basics of automation of this task by putting the all instructions into Makefile. The example files (main.c, main.bin, main.hex, Makefile) has been packaged as a .ZIP file and can be downloaded here.

Updates

[28.10.2019] Take a look at docker version of AVR Toolchain

1. Installing avr-gcc and tools

To compile C and/or C++ source code of your firmware you will need gcc-avr compiler, the avr-libc C library and avrdude. What is extremely useful, there are complete and easy to install packages for all major platforms.

Linux, Ubuntu

Ubuntu provides packages, so you can just install them using this command.

$ sudo apt-get install gcc-avr avr-libc avrdude

Mac OSX

Download AVR MacPack. The MacPack disk image has an installer that does everything for you.

Windows

Download WinAVR, which includes everything you need and has a nice installer.

2. Compiling and burning the code

Now that you have the compiler installed, a next step is to compile simple source code into a .BIN file, then generate Intel .HEX file and finally burn this .HEX file to AVR chip using USBasp programmer.

Example code

Here is an example content of main.c file. The code does nothing except getting stuck in an endless loop but it’s always something!

int
main(void)
{

        while (1);
}

Compiling

The command below will compile your code. It’s GCC so I assume it looks familiar to you and no additional information is required. If you want perform compilation for some other MCU then you need specify appropriate -mmcu option.

$ avr-gcc -Wall -g -Os -mmcu=attiny13 -o main.bin main.c

After performing successful compilation, you can check program and data memory size with this command.

$ avr-size -C main.bin
AVR Memory Usage
----------------
Device: Unknown

Program:      40 bytes
(.text + .data + .bootloader)

Data:          0 bytes
(.data + .bss + .noinit)

Generating .HEX

Most programmers will not accept a GNU executable as an input file, so we need to do a little more processing. So the next step is about converting the information form .BIN into .HEX file. The GNU utility that does this is called avr-objcopy.

$ avr-objcopy -j .text -j .data -O ihex main.bin main.hex

Burning

The utility called avrdude can program processors using the contents of the .HEX files specified on the command line. With the command below, the file main.hex will be burned into the flash memory. The -p attiny13 option lets avrdude know that we are operating on an ATtiny13 chip. In other words – this option specifies the device. The full list of supported parts can be found here. Note that full-length names are also acceptable (i.e. t13 equals attiny13).

$ avrdude -p attiny13 -c usbasp -U flash:w:main.hex:i -F -P usb

Voila! Chip is programmed.

3. Make and makefiles

Now, we can automate this process by creating a Makefile and putting our commands there. The structure of a Makefile is very simple, and more information about it can be found here. Utility make reads automatically a Makefile file in the folder where you launch it. Take a look at a ready-made example.

MCU=attiny13
F_CPU=1200000
CC=avr-gcc
OBJCOPY=avr-objcopy
CFLAGS=-std=c99 -Wall -g -Os -mmcu=${MCU} -DF_CPU=${F_CPU} -I.
TARGET=main
SRCS=main.c

all:
        ${CC} ${CFLAGS} -o ${TARGET}.bin ${SRCS}
        ${OBJCOPY} -j .text -j .data -O ihex ${TARGET}.bin ${TARGET}.hex

flash:
        avrdude -p ${MCU} -c usbasp -U flash:w:${TARGET}.hex:i -F -P usb

clean:
        rm -f *.bin *.hex

If you launch a simple make in the terminal, only label “all” will be executed. When you launch (sudo) make flash label “flash” will be executed, and so on.

$ make
avr-gcc -std=c99 -Wall -g -Os -mmcu=attiny13 -DF_CPU=1200000 -I. -o main.bin main.c 
avr-objcopy -j .text -j .data -O ihex main.bin main.hex    
$ make flash
avrdude -p attiny13 -c usbasp -U flash:w:main.hex:i -F -P usb

avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9007
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: reading input file "main.hex"
avrdude: writing flash (40 bytes):

Writing | ################################################## | 100% 0.05s

avrdude: 40 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex contains 40 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.03s

avrdude: verifying ...
avrdude: 40 bytes of flash verified

avrdude: safemode: Fuses OK (H:FF, E:FF, L:6A)

avrdude done.  Thank you.

4. Summary

Essentially, assuming that our program is in main.c, only those three things are needed to compile and burn the code to AVR chip.

$ avr-gcc -Wall -g -Os -mmcu=attiny13 -o main.bin main.c
$ avr-objcopy -j .text -j .data -O ihex main.bin main.hex
$ avrdude -p attiny13 -c usbasp -U flash:w:main.hex:i -F -P usb

It’s important to highlight that we can easily automate whole process with Makefiles. Sooner or later you will need it!

Attachments

23 thoughts on “How to compile and burn the code to AVR chip on Linux/MacOSX/Windows ?

  1. Hi Łukasz, excellent description. I was just about to write one for my students and got stuck at one point until I found yours. Now I mangled both and sent it to my boys and girls under your and my name, including a translation into German. I hope that it is ok for you….I am using mainly atmega88 and a selfmade STK500 clone. It also works from a virtual linux (Ubuntu 20.04.2 on an Oracle Virtual Box VM) which does not make much sense but even that works fine.
    Ansgar

  2. Hi Łukasz can you add an attention next to the WinAVR option because instead of appending to sytem path it just overwrites on it and now my system path is gone. Hope this helps newcomers.

  3. Hey, thanks a lot for this, its super useful for a beginner like me.
    I had to set fuses with avrdude -U lfuse:w:0x6A:m […], so the frequences were correct, my attiny13a had different defaults probably.
    The frequency is still a tiny bit off, is that normal?

  4. Hi Lukasz, firstly many thanks for this. I have not done something like this before and so I am just working through this page step by step to see what happens. I downloaded “034_rainbow_on_single_led_ws2812” and then from within that folder ran

    avr-gcc -Wall -g -Os -mmcu=attiny13 -o main.bin main.c

    The result was

    In file included from main.c:8:
    /usr/avr/include/util/delay.h:92:3: warning: #warning “F_CPU not defined for ” [-Wcpp]
    92 | # warning “F_CPU not defined for ”
    | ^~~~~~~
    /usr/lib/gcc/avr/9.2.0/../../../../avr/bin/ld: /tmp/cckCbTmF.o: in function `main’:
    /home/abasel/Dropbox/Transfer/WorkingOn/Night-Light/Podkalicki/blog-master/avr/attiny13/034_rainbow_on_single_led_ws2812/main.c:36: undefined reference to `ws2812_setleds’
    collect2: error: ld returned 1 exit status

    What am I doing wrong or missing?

  5. I have programmed ATTinys with the Arduino IDE before and with success, but when I put your firmware for the ATtiny13 IR remote control of LEDS in my Arduino IDE and check the code, it gives me the following error:
    sketch_aug22a:51:9: error: ‘void IR_init()’ was declared ‘extern’ and later ‘static’ [-fpermissive]

    IR_init()

    Obviously, I’m doing something wrong, can you help?

    The settings in the Arduino IDE are: ATTiny13, 9.6MHz, BOD disabled, LTO enabled (default)
    I am beginner in this so please help. Thanks!

    • I’m not using arudino as a programmer but I have a tip for all my code examples used by Arduino IDE – change file extensions *.c to *.cpp to make the compiler and linker know what sources they need to use.

      • Hi Lukasz, Thanks for your suggestion, but unfortunately I could not get it to work. Same error keeps coming up.

  6. Wow, this tutorial was unique and extraordinary, no where I could solve my problems while working with gcc-avr like here. Thanks a ton!

  7. thank you very much, a very helpful document, I have been able to burn a program to my ATtiny13a

    • Great! Thanks Robert for leaving a comment. I’m sure it will serve here as a nice recommendation for other readers.
      /LP

  8. Hey, Thanks for the instruction on Makefiles, I’m temporarily stuck using my Linux box while the other one is in the shop. Your file had the basics that I needed to produce a Hex file. I never used just avr – gcc and a makefile but figured it’s time. Feeling naked without my assembler, simulator and windoze.
    Thanks

  9. First, thanks for the tutorial!
    Is there no other way to write to the AVR chip without using the USBasp programmer?
    Say, use the Arduino IDE as a programmer? Thank you

    • There is few ways to make it happen. It mostly depend on chip ID and user choice. One way is to use build-in protocol and other way is to use bootloader – i.e. from Arduino.

  10. HI,
    I am getting an error while uploading it using the avrdude
    avrdude: error: program enable: target doesn’t answer. 1
    avrdude: initialization failed, rc=-1
    avrdude: AVR device initialized and ready to accept instructions
    avrdude: Device signature = 0x88dbe5
    avrdude: Expected signature for ATmega328P is 1E 95 0F
    avrdude: NOTE: “flash” memory has been specified, an erase cycle will be performed
    To disable this feature, specify the -D option.

    avrdude done. Thank you.

    It would be really nice if you could help me with it.

    • Hi, unfortunately a lot of things could happen here:

      • check connections MOSI and MISO.
      • check MCU power supply
      • maybe your programmer is in Slow SCK mode
      • check all GND are connected
      • invalid clock source / crystal (fuse flags)
      • many more..

Leave a Comment