AVR Microcontrollers

Date: 02 june 2016

Please refer to avr.programming page for a quick reference about compilation and programming.

Introduction

Microcontrollers are small computers with poor features in numbers (few memory, slow cpu) but a lot of hardware is integrated in a small and cheap integrated circuit.

Between the various manufacturers, Atmel's AVRs are the most diffused for their reduced cost and the availability of lots of documentation and tools under FOSS operating systems.

If you know Arduino, go away from here. Arduino uses a microcontroller but is a different approach of programming, using a bootloader and a simplified development environment.

You are supposed to use GNU Linux. You should install:

  • avr-libc
  • gcc-avr
  • avr-binutils

Fundamentals

  • Microcontrollers are not supposed to run any operating system. They usually run only your piece of software.
  • Software running in microcontrollers is called firmware, you can write it in assembly, C or other languages. C is preferred and suggested by the writer.
  • Microcontrollers will do all and only what you tell them to do. You (trought the firmware) have the responsability of managing every piece of hardware the way you want.
  • The microcontroller datasheet is the BIBLE. Expecially Atmel ones are very well documented. You should always keep by hand the datasheet of the microcontroller you are using and use it as a reference during programming.

How To

Hardware

Choose a development platform of your choice or build your own hardware. You should have handy the schematics referring the hardware to know every part how is connected to the microcontroller.

Normally a microcontroller does not need any additional hardware, but often you apply at least an external clock to have a precise and stable clock source, needed for timing-critical applications such as asyncronous serial communication.

C code editing and tips

You don't need any IDE. Just write your code in your preferred editor, eventually sintax highlighting might be useful.

A main.c file for an AVR usually contains:

  • almost an #include <avr/io.h> that loads all the hardware definitions and macros;
  • a void main() { } function that contains the main code;
  • optionally one or more ISR(vector) { } functions that contain interrupt routines.

Reaching the end of the main function means halting the micro so usually the main(){ } contains:

  • the initializations;
  • a while(1){ } cycle for the main process.

Note about ISRs

Interrupt Service Routines should not contain long pieces of code, it is better to raise a flag and eventually do other quick tasks, and then let the main loop test these flags and react consequently.

The variables shared between main and ISRs should be declared “volatile” to let the compiler know that their contents could be changed casually.

Other notes about programming

You normally won't use integer, long, float types… but the simple and hardware-friendly types such uint8_t, that have an immediate corrispondency with the hardware.

You'll often deal with binary operators such as & (bit-to-bit AND), | (bit-to-bit OR), ^ (XOR), ~ (NOT) and shifts « ».

When you need a boolean variable you can use a uint8_t flag and access every bit with masks, for example:

#define BIT 0
flags |= (1<<BIT);
if (flags & (1<<BIT)) flags &=~(1<<BIT);

Compile

To compile you should run:

  • avr-gcc (passing the part name)
  • avr-objcopy

However it is simpler to use a Makefile and run make to compile (and also to write the code to the microcontroller, as described later). A valid Makefile (included within the example) is available here http://wwww.psychogenic.com/

Programming

You must then transfer the compiled code onto the microcontroller. You will need a programmer. Valid programmers are:

The program avrdude will download the firmware to the AVR, with any of the above programmers. In brackets the name of the programmer that should be passed to avrdude between its options.

Important: you should read the part of the datasheet called “Fuse bits” under the “Memory programming” chapter. When programming for the first time, you normally have to adjust some fuse bit to tell the micro to use external crystal quartz for the clock. Avrdude will let you program also fuse bytes just refer to the reference mentioned at the beginning and to its manual page.

Example

The following example is a simplified Fibonacci clock, that shows the SECONDS (yes, only the seconds) over 5 leds.

simplified fibonacci clock - C Example Code

#include <avr/io.h>
#include <avr/interrupt.h>
 
volatile uint8_t flags;
uint8_t seconds;
 
enum {TICK};
 
void main()
{
	DDRA |= (1<<PA7);    /* INITIALIZE PORT "A" : PA7 IS OUTPUT */
	DDRC |= 0b00001111;
	TCCR1B|=(1<<CS12);	 /* CLOCK SOURCE /256 */
	//TIMSK|=(1<<TOIE1); /* ENABLE OVERFLOW INTERRUPT */
	OCR1A=62500UL;		 /* SET COMPARE A VALUE */
	TIMSK|=(1<<OCIE1A);  /* ENABLE OPTION COMPARE A INTERRUPT */
	seconds=0;
	sei();
	while(1)
	{
		if (flags & (1<<TICK))
		{
			flags &=~ (1<<TICK);
			PORTA &=~ (1<<PA7);	
			//seconds = (seconds++)%60;
			if (++seconds >59 ) seconds = 0;
			PORTC &=~ 0b00001111;
			uint8_t a = seconds / 5;
			if (a >= 5)
			{
				PORTA |= (1<<PA7);
				a-=5;
			}
			if (a >= 3)
			{
				PORTC |= (1<<PC3);
				a-=3;
			}
			if (a >= 2)
			{
				PORTC |= (1<<PC2);
				a-=2;
			}
			if (a >= 1)
			{
				PORTC |= (1<<PC1);
				a-=1;
			}
			if (a) PORTC |= (1<<PC0);
		}
	}
}
 
 
ISR(TIMER1_COMPA_vect)
{
	flags |= (1<<TICK);
	//PORTA ^= (1<<PA7);	/* TOGGLE PA7 */
}

Makefile

Source: http://wwww.psychogenic.com/

My addition: 'fuse' target.

#########  AVR Project Makefile Template   #########
######                                        ######
######    Copyright (C) 2003-2005,Pat Deegan, ######
######            Psychogenic Inc             ######
######          All Rights Reserved           ######
######                                        ######
###### You are free to use this code as part  ######
###### of your own applications provided      ######
###### you keep this copyright notice intact  ######
###### and acknowledge its authorship with    ######
###### the words:                             ######
######                                        ######
###### "Contains software by Pat Deegan of    ######
###### Psychogenic Inc (www.psychogenic.com)" ######
######                                        ######
###### If you use it as part of a web site    ######
###### please include a link to our site,     ######
###### http://electrons.psychogenic.com  or   ######
###### http://www.psychogenic.com             ######
######                                        ######
####################################################


##### This Makefile will make compiling Atmel AVR 
##### micro controller projects simple with Linux 
##### or other Unix workstations and the AVR-GCC 
##### tools.
#####
##### It supports C, C++ and Assembly source files.
#####
##### Customize the values as indicated below and :
##### make
##### make disasm 
##### make stats 
##### make hex
##### make writeflash
##### make gdbinit
##### or make clean
#####
##### See the http://electrons.psychogenic.com/ 
##### website for detailed instructions


####################################################
#####                                          #####
#####              Configuration               #####
#####                                          #####
##### Customize the values in this section for #####
##### your project. MCU, PROJECTNAME and       #####
##### PRJSRC must be setup for all projects,   #####
##### the remaining variables are only         #####
##### relevant to those needing additional     #####
##### include dirs or libraries and those      #####
##### who wish to use the avrdude programmer   #####
#####                                          #####
##### See http://electrons.psychogenic.com/    #####
##### for further details.                     #####
#####                                          #####
####################################################

## fuse target addition by Alessandro Mauro (c) 2016
##  (www.maetech.it)
## please ADJUST this section to your needs!!!
## use 'make fuse' to write the fuse byte

fuse:
        $(AVRDUDE) -c $(AVRDUDE_PROGRAMMERID)   \
         -p $(PROGRAMMER_MCU) -P $(AVRDUDE_PORT) \
         -U lfuse:w:0xef:m

#####         Target Specific Details          #####
#####     Customize these for your project     #####

# Name of target controller 
# (e.g. 'at90s8515', see the available avr-gcc mmcu 
# options for possible values)
MCU=atmega32

# id to use with programmer
# default: PROGRAMMER_MCU=$(MCU)
# In case the programer used, e.g avrdude, doesn't
# accept the same MCU name as avr-gcc (for example
# for ATmega8s, avr-gcc expects 'atmega8' and 
# avrdude requires 'm8')
PROGRAMMER_MCU=$(MCU)

# Name of our project
# (use a single word, e.g. 'myproject')
PROJECTNAME=example

# Source files
# List C/C++/Assembly source files:
# (list all files to compile, e.g. 'a.c b.cpp as.S'):
# Use .cc, .cpp or .C suffix for C++ files, use .S 
# (NOT .s !!!) for assembly source code files.
PRJSRC=example.c

# additional includes (e.g. -I/path/to/mydir)
#INC=-I/path/to/include

# libraries to link in (e.g. -lmylib)
#LIBS=

# Optimization level, 
# use s (size opt), 1, 2, 3 or 0 (off)
OPTLEVEL=s


#####      AVR Dude 'writeflash' options       #####
#####  If you are using the avrdude program
#####  (http://www.bsdhome.com/avrdude/) to write
#####  to the MCU, you can set the following config
#####  options and use 'make writeflash' to program
#####  the device.


# programmer id--check the avrdude for complete list
# of available opts.  These should include stk500,
# avr910, avrisp, bsd, pony and more.  Set this to
# one of the valid "-c PROGRAMMER-ID" values 
# described in the avrdude info page.
# 
AVRDUDE_PROGRAMMERID=stk200

# port--serial or parallel port to which your 
# hardware programmer is attached
#
AVRDUDE_PORT=/dev/parport0


####################################################
#####                Config Done               #####
#####                                          #####
##### You shouldn't need to edit anything      #####
##### below to use the makefile but may wish   #####
##### to override a few of the flags           #####
##### nonetheless                              #####
#####                                          #####
####################################################


##### Flags ####

# HEXFORMAT -- format for .hex file output
HEXFORMAT=ihex

# compiler
CFLAGS=-I. $(INC) -g -mmcu=$(MCU) -O$(OPTLEVEL) \
	-fpack-struct -fshort-enums             \
	-funsigned-bitfields -funsigned-char    \
	-Wall -Wstrict-prototypes               \
	-Wa,-ahlms=$(firstword                  \
	$(filter %.lst, $(<:.c=.lst)))

# c++ specific flags
CPPFLAGS=-fno-exceptions               \
	-Wa,-ahlms=$(firstword         \
	$(filter %.lst, $(<:.cpp=.lst))\
	$(filter %.lst, $(<:.cc=.lst)) \
	$(filter %.lst, $(<:.C=.lst)))

# assembler
ASMFLAGS =-I. $(INC) -mmcu=$(MCU)        \
	-x assembler-with-cpp            \
	-Wa,-gstabs,-ahlms=$(firstword   \
		$(<:.S=.lst) $(<.s=.lst))


# linker
LDFLAGS=-Wl,-Map,$(TRG).map -mmcu=$(MCU) \
	-lm $(LIBS)

##### executables ####
CC=avr-gcc
OBJCOPY=avr-objcopy
OBJDUMP=avr-objdump
SIZE=avr-size
AVRDUDE=avrdude
REMOVE=rm -f

##### automatic target names ####
TRG=$(PROJECTNAME).out
DUMPTRG=$(PROJECTNAME).s

HEXROMTRG=$(PROJECTNAME).hex 
HEXTRG=$(HEXROMTRG) $(PROJECTNAME).ee.hex
GDBINITFILE=gdbinit-$(PROJECTNAME)

# Define all object files.

# Start by splitting source files by type
#  C++
CPPFILES=$(filter %.cpp, $(PRJSRC))
CCFILES=$(filter %.cc, $(PRJSRC))
BIGCFILES=$(filter %.C, $(PRJSRC))
#  C
CFILES=$(filter %.c, $(PRJSRC))
#  Assembly
ASMFILES=$(filter %.S, $(PRJSRC))


# List all object files we need to create
OBJDEPS=$(CFILES:.c=.o)    \
	$(CPPFILES:.cpp=.o)\
	$(BIGCFILES:.C=.o) \
	$(CCFILES:.cc=.o)  \
	$(ASMFILES:.S=.o)

# Define all lst files.
LST=$(filter %.lst, $(OBJDEPS:.o=.lst))

# All the possible generated assembly 
# files (.s files)
GENASMFILES=$(filter %.s, $(OBJDEPS:.o=.s)) 


.SUFFIXES : .c .cc .cpp .C .o .out .s .S \
	.hex .ee.hex .h .hh .hpp


.PHONY: writeflash clean stats gdbinit stats

# Make targets:
# all, disasm, stats, hex, writeflash/install, clean
all: $(TRG)

disasm: $(DUMPTRG) stats

stats: $(TRG)
	$(OBJDUMP) -h $(TRG)
	$(SIZE) $(TRG) 

hex: $(HEXTRG)


writeflash: hex
	$(AVRDUDE) -c $(AVRDUDE_PROGRAMMERID)   \
	 -p $(PROGRAMMER_MCU) -P $(AVRDUDE_PORT) -e        \
	 -U flash:w:$(HEXROMTRG)

install: writeflash

$(DUMPTRG): $(TRG) 
	$(OBJDUMP) -S  $< > $@


$(TRG): $(OBJDEPS) 
	$(CC) $(LDFLAGS) -o $(TRG) $(OBJDEPS)


#### Generating assembly ####
# asm from C
%.s: %.c
	$(CC) -S $(CFLAGS) $< -o $@

# asm from (hand coded) asm
%.s: %.S
	$(CC) -S $(ASMFLAGS) $< > $@


# asm from C++
.cpp.s .cc.s .C.s :
	$(CC) -S $(CFLAGS) $(CPPFLAGS) $< -o $@



#### Generating object files ####
# object from C
.c.o: 
	$(CC) $(CFLAGS) -c $< -o $@


# object from C++ (.cc, .cpp, .C files)
.cc.o .cpp.o .C.o :
	$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@

# object from asm
.S.o :
	$(CC) $(ASMFLAGS) -c $< -o $@


#### Generating hex files ####
# hex files from elf
#####  Generating a gdb initialisation file    #####
.out.hex:
	$(OBJCOPY) -j .text                    \
		-j .data                       \
		-O $(HEXFORMAT) $< $@

.out.ee.hex:
	$(OBJCOPY) -j .eeprom                  \
		--change-section-lma .eeprom=0 \
		-O $(HEXFORMAT) $< $@


#####  Generating a gdb initialisation file    #####
##### Use by launching simulavr and avr-gdb:   #####
#####   avr-gdb -x gdbinit-myproject           #####
gdbinit: $(GDBINITFILE)

$(GDBINITFILE): $(TRG)
	@echo "file $(TRG)" > $(GDBINITFILE)
	
	@echo "target remote localhost:1212" \
		                >> $(GDBINITFILE)
	
	@echo "load"        >> $(GDBINITFILE) 
	@echo "break main"  >> $(GDBINITFILE)
	@echo "continue"    >> $(GDBINITFILE)
	@echo
	@echo "Use 'avr-gdb -x $(GDBINITFILE)'"


#### Cleanup ####
clean:
	$(REMOVE) $(TRG) $(TRG).map $(DUMPTRG)
	$(REMOVE) $(OBJDEPS)
	$(REMOVE) $(LST) $(GDBINITFILE)
	$(REMOVE) $(GENASMFILES)
	$(REMOVE) $(HEXTRG)
	


#####                    EOF                   #####
Navigazione

Table of contents

Contact

For any info you can write to:
Per qualunque info potete scrivere a:
info[at]maetech[dot]it

Ads

Stampa/Esporta
QR Code
QR Code talks:avr-microcontrollers (generated for current page)