AVR
AVR is a family of microcontrollers (MCUs) developed by Microchip Technology (former AVR). AVRs are especially common in hobbyist and educational embedded applications, popularized by Arduino project. This page deals with 8-bit series of these MCUs.
Toolchain
Install avr-gcc to get toolchain and GNU compiler.
Programmers
To flash compiled firmware to the AVR chip you will need programmer and software to rule it. Most popular programmers are USBasp, AVRISP mkII, Atmel-ICE and STK500. There is also exists the simplest DIY-programmer which works with LPT port. avrdude supports them all great.
udev issues
If you are using AVRISP mkII or USBasp programmers please consider installing avrisp-udevAUR and/or usbasp-udevAUR respectively to be able to run avrdude without superuser rights.
If you are using a USBtiny programmer, you need to create
/etc/udev/rules.d/99-usbtiny.rules
# Set Group for USBtiny SUBSYSTEM=="usb", ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c9f", GROUP="uucp"
This will automatically mount the USBtiny accessible to group uucp whenever it is connected. If your user is a member of that group, you will be able to run avrdude without superuser rights.
If your programmer is from another vendor or has a different product id, use the following command to find the proper values:
$ lsusb
Usage
To compile C program for AVR chip (let us consider ATmega8A running at 8 MHz as example) you can use avr-gcc
directly. You should only specify target MCU (full list of supported MCUs could be found in avr-gcc man page) and its working frequency:
$ avr-gcc -DF_CPU=8000000UL -mmcu=atmega8a -std=gnu99 main.c -o main.elf
avrdude is smart enough to work with the resulting ELF file but you can convert it explicitly to Intel HEX:
$ avr-objcopy -O ihex -j .text -j .data main.elf main.hex
Then run avrdude and specify flash ROM as destination for formware burning (in this example AVRISP mkII is used and clock speed is lowered to the 125 kHz to be on safe side):
$ avrdude -p atmega8 -c avrispmkII -B 125kHz -U flash:w:main.hex
That's all. Among other things avrdude can work with EEPROM memory, fuse and lock bits. For example, to set up low and high fuses to the 0x9F and 0xD1 respectively use the following incantation:
$ avrdude -p atmega8 -c avrispmkII -B 125kHz -U lfuse:w:0x9F:m -U hfuse:w:0xD1:m
Just remember that ISP programming speed should not exceed 1/8 of MCU's working frequency. A lot of new chips comes with 1 MHz speed settings so using 125 kHz as starting value should be fine enough.
Tips and tricks
Optimization
Because AVRs come with tight flash ROM size and relatively weak CPUs you can consider some optimizations to improve space usage and overall performance of your device. It is common practice to enable GCC optimization level -Os
and turn on some extra features: -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
. To exclude unnecessary library references perform garbage collection: -ffunction-sections -fdata-sections -Wl,--gc-sections
.
Sample Makefile
Managing huge project could be tedious and Makefile workflow is the most efficient way to deal with it. Here are sample Makefile based on AVRfreaks version:
CC = avr-gcc
OBJCOPY = avr-objcopy
SIZE = avr-size
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
MCU = atmega8a
F_CPU = 8000000
LFUSE = 0x9f
HFUSE = 0xd1
TARGET = firmware
SRC = main.c lcd.c twi.c
OBJ = $(SRC:.c=.o)
LST = $(SRC:.c=.lst)
FORMAT = ihex
OPTLEVEL = s
CDEFS =
CFLAGS = -DF_CPU=$(F_CPU)UL
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPTLEVEL)
CFLAGS += -mmcu=$(MCU)
CFLAGS += -std=gnu99
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -Wall -Wstrict-prototypes
CFLAGS += -Wa,-adhlns=$(<:.c=.lst)
LDFLAGS = -Wl,--gc-sections
LDFLAGS += -Wl,--print-gc-sections
AVRDUDE_MCU = atmega8
AVRDUDE_PROGRAMMER = avrispmkII
AVRDUDE_SPEED = -B 1MHz
AVRDUDE_FLAGS = -p $(AVRDUDE_MCU)
AVRDUDE_FLAGS += -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_SPEED)
MSG_LINKING = Linking:
MSG_COMPILING = Compiling:
MSG_FLASH = Preparing HEX file:
all: gccversion $(TARGET).elf $(TARGET).hex size
.SECONDARY: $(TARGET).elf
.PRECIOUS: $(OBJ)
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) -j .text -j .data __SUB_LEVEL_SECTION_6__lt; $@
%.elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) -mmcu=$(MCU) $(LDFLAGS) $^ --output $(@F)
%.o : %.c
@echo $(MSG_COMPILING) __SUB_LEVEL_SECTION_6__lt;
$(CC) $(CFLAGS) -c __SUB_LEVEL_SECTION_6__lt; -o $(@F)
gccversion:
@$(CC) --version
size: $(TARGET).elf
@echo
$(SIZE) -C --mcu=$(AVRDUDE_MCU) $(TARGET).elf
analyze: $(TARGET).elf
$(NM) -S --size-sort -t decimal $(TARGET).elf
isp: $(TARGET).hex
$(AVRDUDE) $(AVRDUDE_FLAGS) -U flash:w:$(TARGET).hex
fuses:
$(AVRDUDE) $(AVRDUDE_FLAGS) -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m
release: fuses isp
clean:
$(REMOVE) $(TARGET).hex $(TARGET).elf $(OBJ) $(LST) *~
Calculating control register values
To speed up development of your projects you can use avrcalcAUR utility which helps to calculate different parameters for control registers regarding timers, frequencies etc.