Developing for the Atmel AVR Microcontroller on Linux

by Patrick Deegan

Whether you are creating a small Internet appliance, some hardware instrumentation, data loggers or an army of autonomous robots to do your bidding, in numerous situations you need the flexibility of a programmable computer. In many cases, a general-purpose system, such as the workhorse sitting under your desk, doesn't meet size, cost or power-consumption constraints and is simply overkill. What you need is a microcontroller.

This article provides step-by-step instructions for setting up a complete development system for the Atmel AVR series of microcontrollers, using free software and Linux. The detailed instructions provided here will allow you to transform your Linux system into a complete AVR development environment. This article walks you through all the steps of building, debugging and installing a simple program.

What Is a Microcontroller?

When all the electronic components required to make a central processing unit (CPU)—instruction decoder, arithmetic/logic unit, registers and so on—are integrated into a single chip, you have a microprocessor. When, in turn, you bundle this CPU with supporting components, memory and I/O peripherals, you've got a microcomputer. Extending the integration and miniaturization even further, you can combine all the elements of a microcomputer onto a single integrated circuit—behold the microcontroller.

The semiconductor industry evolves rapidly, making it difficult to provide an accurate and complete definition of the term microcontroller. Consider this: some microcontroller chips have capacities and clock speeds that surpass the 74KB of program memory and 4KB of RAM available to the 30kg Apollo Lunar Module computer. You can expect today's screamer PCs to be running tomorrow's embedded applications, with the definition of microcontroller shifting accordingly.

Microcontrollers all have a microprocessor core, memory and I/O interfaces, and many have additional peripherals onboard. The specific configuration of a particular chip influences its physical packaging, number of pins and cost. If you are accustomed to working with microcomputers, you may feel that microcontrollers are tight spots. They have a handful of kilobytes of program ROM and in the area of 256 bytes of RAM. Don't fret though; a lot can be done in this space, as the MIT Instrumentation Lab demonstrated when developing the Apollo Lunar Module software that controls its moon landing, return from the surface and rendezvous in orbit.

AVR Microcontrollers

The AVRs are 8-bit RISC platforms with a Harvard architecture (program and data memory are separate). Figure 1 details the ATtiny26 AVR chip internal organization. Like each member of a family, it has its own particular combination of I/O and peripherals, but it shares a basic architecture and instruction set with all the other AVRs. The ATtiny26 has 2KB of program Flash memory, 128 bytes of onboard SRAM and EEPROM, two 8-bit counters and pulse-width modulators, 11 interrupts, 16 I/O pins spread over two 8-bit ports, an 11-channel 10-bit analog-to-digital converter and more—all on a single tiny 20-pin DIP.

A number of factors make the AVR microcontrollers a good choice, especially for beginners. AVRs are:

  • Easy to code for: AVRs were designed from the ground up to allow easy and efficient programming in high-level languages, with a particular focus on C.

  • Easy to program: the combination of onboard reprogrammable Flash program memory and the in-system programming interface keeps the process of transferring software to the microcontroller simple and cheap.

  • Powerful and inexpensive: AVRs pack a lot of power (1 MIPS/MHz, clocks up to 16MHz) and space (up to 128K of Flash program memory and 4K of EEPROM and SRAM) at low prices. Most AVRs even include additional peripherals, such as UARTs and analog-to-digital converters.

  • Hobbyist-friendly: most of the chips in the AVR family come in easy-to-use 8-, 20-, 28- or 40-pin dual in-line packages (DIPs) and can be ordered in unit quantities from a number of distributors.

Figure 1. ATtiny26 Block Diagram


The processor core, composed of the components in the upper-left portion of Figure 1, includes elements to read the program memory and to decode and execute the instructions within that memory. The CPU also can fetch and store data to and from the EEPROM, SRAM and the 32 registers. The registers act as extremely efficient storage for 8-bit values (1 byte), and the ALU (arithmetic/logic unit) can operate directly on each of the 32 registers. This AVR features a RAM-based stack. In a few other AVRs, which don't have any SRAM, the stack is hardware-based, limiting the stack depth to three.

Most instructions take only a single clock cycle to execute, and there is no internal clock division on AVRs. The CPU fetches and decodes the next instruction as it is executing the current instruction. These combined facts mean that AVRs can reach performances of nearly 1 MIPS (million instructions per second) per MHz. With clock rates of up to 16MHz, you can choose the right balance of speed, power consumption and electromagnetic noise for your particular application.




I/O and Peripherals



Development Workstation Setup





$ make
# make install






$ make
# make install


AVR Libc


$ unset CC
$ PREFIX=/usr/local/AVR ./doconf
$ ./domake
# ./domake install
Makefile Template


GDB and SimulAVR

Using avr-gdb and simulavr in tandem, you can run your software on a choice of AVR microcontrollers through the simulator, while using GDB to step through and observe the executing code. Acquire the simulavr source from the project site and perform the installation:

$ make # make install

Install GDB, built for AVR targets, by compiling the source as follows:

$ ./configure --target=avr \
$ make
# make install

When you finally have a program ready for testing on actual hardware, you need some way to upload the data and write it to the microcontroller's Flash program memory. AVRDUDE and a compatible hardware programmer are the last components of the development kit. Grab a copy of the AVRDUDE source and install it with:

$ make
# make install

You now have installed every software component required for a complete AVR development environment. All you need is the physical means to transfer programs to microcontrollers.

AVRDUDE supports a number of different hardware programmer configurations. The simplest systems are described on the AVRDUDE site and are comprised of little more than a parallel port connector, a ceramic oscillator and a DIP socket. These are powered directly off the computer's port and may not work for everyone.

Figure 2. Home-Brew PPI Programmer PCB

A step up in complexity, independently powered, buffered in-system programmers can be built easily (see Resources). Two programmers requiring only a few parts are discussed on the Psychogenic Web page, which describes the schematics, provides artwork and has complete instructions on creating your own printed circuit boards (as depicted in Figure 2) for the programmers.

Figure 3. Atmel STK500 Development Kit

A number of commercial solutions also are available. If you're interested in easily programming a wide selection of the AVR family, go with Atmel's STK500 kit. More than a simple programmer, the STK500 is a starter kit that allows you to program the microcontrollers and easily prototype new designs. It includes a number of LEDs and switches, an oscillator, RS-232 interface and other niceties that easily can be interfaced with your target chip.

A Complete AVR Project

Our focus here is on the development system rather than on programming for the AVR platform. The AVR Libc documentation is a good place to start for information on programming AVRs in Assembly, C and C++.

The Hello World program of the microcontroller universe is the classic flashing LEDs. A slightly different take on this theme, which Knight Rider fans should appreciate, is available on the Linux Journal FTP site, where you can download C (Listing 2) or C++ (Listing 3) versions of an example program that cycles each of eight light-emitting diodes (LEDs) back and forth.

Building the Program

Create a project directory—for instance, ~/helloavr/—and retrieve the program, saving Listing 2 as ~/helloavr/kr.c and Listing 3 as ~/helloavr/kitt.cpp. Also, copy the Makefile template, /usr/local/AVR/Makefile.tpl, to ~/helloavr/Makefile.

Using this Makefile is easy and makes compilation a snap. Open the Makefile in your favourite editor and modify the configuration section, near the top of the file, so that the MCU, PROJECTNAME and PRJSRC variables are set as shown in Listing 4. The MCU variable determines the AVR family member for which we are compiling the program, and the PRJSRC variable lists all the Assembly, C and C++ source files used in the project.

Listing 4. HelloAVR Project Makefile Configuration Options


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

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

# Source files
# List C/C++/Assembly source files:
# (list all files to compile, e.g. 'a.c b.cpp as.S')

Once you've configured the Makefile, compiling and linking the program is as simple as typing make.

You can perform the compilation and linking steps manually instead, by issuing:

  $ avr-gcc -I.  -g -mmcu=at90s8515 -Os       \
             -fpack-struct -fshort-enums               \
             -funsigned-bitfields -funsigned-char \
             -Wall -Wstrict-prototypes -c kr.c

  $ avr-gcc -o helloavr.out kr.o

The most notable difference is the addition of the required -mmcu command-line argument, used to specify the target microcontroller. Either method compiles kr.c and creates the helloavr.out ELF-format program. This file cannot be executed on your development station but is used later during the debugging stage.

You also can build the C++ version of the program by doing a make clean, changing the Makefile PRJSRC variable to kitt.cpp and then issuing another make.

Debugging the Program



$ simulavr --gdbserver --device at90s8515  &
$ make gdbinit


$ avr-gdb -x gdbinit-helloavr


71       PORTB = ~currentValue;


Installing the Program




Figure 4. HelloAVR Program Test Circuit


Where to from Here?




Resources for this article:


Load Disqus comments