AVR GCC and AVRDUDE

The Arduino IDE is great for being able to dive right in and spin up a sketch quickly with a minimum of fuss. However, there are some situations where you want to get a little “closer to the metal” – without some of the limitations that come with that ease-of-use. Maybe you want to use a program or library that’s been created for AVR GCC or Atmel Studio. Here’s how to get a working build environment up and running on an Linux system quickly and easily.

For this walk-through, we’ll be targeting the ATmega32u4 in an Arduino Pro Micro – the same board that we used in the Macro Keypad project. This should work regardless if you have a real Arduino or one of the cheap Chinese clone boards that you can get off of eBay for a few dollars. These boards are great if you want to interact via the USB port to act as a keyboard, mouse, or MIDI source/receiver.

The first thing you need to do is install the AVR GCC and AVRDUDE utilities:

sudo apt-get install binutils gcc-avr avr-libc uisp avrdude flex byacc bison

Create a new folder, maybe something like home/avr/blink. Navigate to the new folder and create a new blink.c file in your favorite text editor.

#ifndef F_CPU
#define F_CPU 16000000UL // or whatever may be your frequency
#endif

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

int main(void)
{
   DDRB = 0xFF;	// set all PORTB pins to output
   while(1)
   {
       // LED on
	PORTB = 0xFF;	// Turn on all PBx pins
	_delay_ms(500); // wait 500 milliseconds

	//LED off
	PORTB = 0x00; 	// Turn off all PBx pins
	_delay_ms(500); // wait 500 milliseconds
   }
}

Then create a new build file and save it as build_script:

avr-gcc -g -Os -mmcu=atmega32u4 -c blink.c
avr-gcc -g -mmcu=atmega32u4 -o blink.elf blink.o
avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex
avr-size --format=avr --mcu=atmega32u4 blink.elf 

Again, this assumes you are targeting an ATmega32u4 controller, so adjust as needed if you’re using a different chip. Then make sure that the script has execute permissions:

sudo chmod 755 build_script

To compile and build your program, just execute the script:

./build_script

You should see a little output that looks like this:

AVR Memory Usage
----------------
Device: atmega32u4

Program:     246 bytes (0.8% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)

Now, if your Pro Micro may or may not have a small momentary button on it. If it does, this normally connects the RST (reset) pin to ground and puts the ATmega32u4 into Device Firmware Update (DFU) mode. If your board does not have a button, you’ll need to add one with a 10k pullup resistor. Most of the time, though, you can get away with just using a jumper wire connecting RST to GND.

If you haven’t already done so, connect your board via USB and verify that the power light comes on. Then push the button or ground the RST pin, release it, and run AVRDUDE to flash the hex file to your controller:

avrdude -v -c avr109 -p atmega32u4 -P /dev/ttyACM0 -b 57600 -D -U flash:w:blink.hex

You only have about 8 seconds to upload the hex file after resetting the board, so it’s handy to have the avrdude command ready to go in your terminal window first. Assuming that you’ve done everything correctly, you should see something like:

avrdude: Version 6.3-20171130
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/etc/avrdude.conf"
         User configuration file is "/home/digitorus/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/ttyACM0
         Using Programmer              : avr109
         Overriding Baud Rate          : 57600
         AVR Part                      : ATmega32U4
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PA0
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  9000  9000 0x00 0x00
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : butterfly
         Description     : Atmel AppNote AVR109 Boot Loader

Connecting to programmer: .
Found programmer: Id = "CATERIN"; type = S
    Software Version = 1.0; No Hardware Version given.
Programmer supports auto addr increment.
Programmer supports buffered memory access with buffersize=128 bytes.

Programmer supports the following devices:
    Device code: 0x44

avrdude: devcode selected: 0x44
avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e9587 (probably m32u4)
avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as D8
avrdude: safemode: efuse reads as CB
avrdude: reading input file "led.hex"
avrdude: input file led.hex auto detected as Intel Hex
avrdude: writing flash (246 bytes):

Writing | ################################################## | 100% 0.02s

avrdude: 246 bytes of flash written
avrdude: verifying flash memory against led.hex:
avrdude: load data flash data from input file led.hex:
avrdude: input file led.hex auto detected as Intel Hex
avrdude: input file led.hex contains 246 bytes
avrdude: reading on-chip flash data:

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

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

avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as D8
avrdude: safemode: efuse reads as CB
avrdude: safemode: Fuses OK (E:CB, H:D8, L:FF)

avrdude done.  Thank you.

Depending on your board, the built-in light may start blinking at this point. If not, just hook up an LED with a suitable current-limiting resistor to one of the PORTB pins. On my board, I used physical pin 16.

Troubleshooting

Your board may show up on a different port. If you’re not sure what port it is on, you can see a list of candidates using the ls command. Your board will probably be something like ttyACM0 or ttyUSB0.

ls /dev/tty*

You may see an error like this during the flashing operation:

avrdude: stk500_recv(): programmer is not responding

This normally means that the chip is not in update mode. If your board has a button, make sure you are fully depressing it. Try shorting the RST using a (different) jumper wire.