Programming the AVR Microcontroller with GCC

ArticleCategory: [Choose a category, do not translate this]

Hardware

AuthorImage:[Here we need a little image from you]

[Photo of the Author]

TranslationInfo:[Author + translation history. mailto: or http://homepage]

original in en Guido Socher

AboutTheAuthor:[A small biography about the author]

Guido loves Linux not only because it is fun to discover the great possibilities of this systems but also because of the people involved in its design.

Abstract:[Here you write a little summary]

The AVR 8-Bit RISC Microcontroller from Atmel is a very common Microcontroller It's a single integrated circuit with EEPROM, Ram, Analog to Digital converter, a lot of digital input and output lines, timers, UART for RS 232 communication and many other things.

The best is however that a complete programming environment is available under Linux: You can program this Microcontroller in C using GCC. In this article I will explain how to install and use GCC. I will as well explain how to load the software into the Microcontroller. All you need for this are an AT90S4433 Microcontroller, a 4Mhz crystal, some cable and a few other very cheap parts.

This article shall be only an introduction. In a later article we will build a LCD display with a few push buttons, analog and digital inputs, hardware watchdog and LEDs. The idea is that this will be a general purpose control panel for a Linux Server but first we will learn how to setup the programming environment and that is what this article is about.

ArticleIllustration:[This is the title picture for your article]

[Illustration]

ArticleBody:[The article body]

Software installation: What you need

To use the GNU C development environment you need the following software:

binutils-2.11.2.tar.bz2 Available from:
ftp://ftp.informatik.rwth-aachen.de/pub/gnu/binutils/
or
ftp://gatekeeper.dec.com/pub/GNU/binutils/
gcc-core-3.0.3.tar.gz Available from: ftp://ftp.informatik.rwth-aachen.de/pub/gnu/gcc/
or
ftp://gatekeeper.dec.com/pub/GNU/gcc/
avr-libc-20020106 .tar.gz The AVR C-library is available from: http://www.amelek.gda.pl/avr/libc/ You can as well download it from this server: download page
uisp-20011025.tar.gz The AVR programmer is available from: http://www.amelek.gda.pl/avr/libc/ You can as well download it from this server: download page
We will install all the programs to /usr/local/atmel. This is to keep the program separate from your normal Linux C compiler. Create this directory with the command:

mkdir /usr/local/atmel

Software installation: GNU binutils

The binutils package provides all the low-level utilities needed for building object files. It includes an AVR assembler (avr-as), linker (avr-ld), library handling tools (avr-ranlib, avr-ar), programs to generate object files loadable to the Microcontroller's EEPROM (avr-objcopy), disassembler (avr-objdump) and utilities such as avr-strip and avr-size.

Run the following commands to build and install the binutils :

bunzip2 -c binutils-2.11.2.tar.bz2 | tar xvf -
cd binutils-2.11.2
./configure --target=avr --prefix=/usr/local/atmel
make
make install

Add the line /usr/local/atmel/lib to the file /etc/ld.so.conf and run the command /sbin/ldconfig to rebuild the linker cache.

Software installation: AVR gcc

avr-gcc will be our C compiler.

Run the following command to build and install it:

tar zxvf gcc-core-3.0.3.tar.gz
cd gcc-core-3.0.3
./configure --target=avr --prefix=/usr/local/atmel --disable-nls --enable-language=c
make
make install

Software installation: The AVR C-library

The C-library is still under development. The installation might still change a bit from release to release. I recommend to use the version as shown in the above table if you want to follow the instructions step by step. I have tested this version and it works fine for all the programs that we will write in this and the following articles.

Set some environment variables (syntax is for bash):
export CC=avr-gcc
export AS=avr-as
export AR=avr-ar
export RANLIB=avr-ranlib
export PATH=/usr/local/atmel/bin:${PATH}

./configure --prefix=/usr/local/atmel --target=avr --enable-languages=c --host=avr
make
make install

Software installation: The Programmer

The programmer software loads the specially prepared object code into the EEPROM of our Microcontroller.

The uisp programmer for Linux is a very good programmer. It can be used directly from within a Makefile. You just add a "make load" rule and you can compile and load the software in one go.

uisp is installed as follows:

tar zxvf uisp-20011025.tar.gz
cd uisp-20011025/src
make
cp uisp /usr/local/atmel/bin

A small test project

We will start with a small test circuit. The purpose of this circuit is just to test our development environment. We can use it to compile, download and test a simple program. The program will just cause a LED to blink.

I suggest to make a small printed circuit board for the Microcontroller. You can later on extent this circuit to do your own experiments. A good idea is to use a breadboard for this. You should however not try to put the AVR with it's 4Mhz crystal directly onto the breadboard. It is better to use a few short wires to connect input and output lines with the breadboard since such breadboards are not made for fast digital circuits. The 4Mhz crystal and the capacitors should be physically very close to the Microcontroller.
[circuit diagram]
The resistors on the connector for the programmer are actually not needed in our case. You need them only if you plan to use the port-B input/output lines for other purposes.

Udo Puetz has provided a possibly more newbie friendly schematic which you find here: avr_layout_newbiefriendly.gif.

Needed Hardware

You need the parts listed in the table below. All of them are very common and cheap. Only the Microcontroller is a bit more expensive, about 7.50 Euro. Although it is a very common Microcontroller it might not be available in every local radio shop but bigger distributors for electronic components like ( www.reichelt.de (germany), www.conrad.de (germany), www.selectronic.fr (france), etc..., probably there are similar sites in your country) have them all in stock.
[avr] 1 x AT90S4433, Atmel 8 bit Avr risc processor.
[socket] 2 x 14 pin IC socket
or
1 x 28 pin 7.5mm IC socket
The 28 pin socket is a bit more difficult to get. Usually the 28 sockets are 14mm wide but we need a 7.5mm socket.
[resistor crystal capacitor] 1 x 10K resistor (color code: brown,black,orange)
3 x 470 Ohm resistor (color code: yellow,purple,brown)
1 x 1K resistor (color code: brown,black,red)
1 x 220 Ohm resistor (color code: red,red,brown)
1 x 4Mhz Crystal
2 x 27pf ceramic capacitor
[connector] Any kind of 5 pin connector/socket for the programmer. I usually buy these strips of connectors and break off 5 of them.
[matrix board] matrix board
[db25] 1 x DB25 connector to plug into the parallel port.
[led] 1 x LED
[beardboard] A breadboard. We don't use it here but it is very useful if you want to do further experiments with the AVR. I suggest you leave the Microcontroller together with the crystal and the capacitors on the matrix board and connect the input/output lines via short cables to the breadboard.
In addition to the above parts you need a 5V electronically stabilized DC power supply or you can use a 4.5V battery as power supply.

Building the programmer hardware

The AT90S4433 allows for in circuit programming (ISP). [AVR programmer]
That is: you can do not need to remove the Microcontroller form the board to program it. You will see that you can buy ready made programmer hardware for 50-150 Euro. You do not need to invest that much in a programmer. With Linux, the uisp software and a free parallel port you can build a very good and simple AVR programmer. It's a simple cable. The wiring for the programmer cable must be as follows:
pin on AVR Pin on parallel port
Reset (1) Init (16)
MOSI (17) D0 (2)
MISO (18) Busy (11)
SCK (19) Strobe (1)
GND GND (18)

The cable should not be longer than 70cm.

Writing software

The AT90S4433 can be programmed in plain C with the help of gcc. To know some AVR assembler can be useful but it is not needed. The AVR libc comes with an avr-libc-reference which documents most of the functions. Harald Leitner has written a document with a lot of useful examples on how to use the AVR and GCC (haraleit.pdf, 286Kb, originally from http://www.avrfreaks.net/AVRGCC/). From Atmel's website, (www.atmel.com, go to: avr products -> 8 bit risc-> Datasheets), you can download the complete data sheet (local copy: avr4433.pdf, 2361Kb) . It describes all the registers and how to use the CPU.

One thing to keep in mind when using the 4433 is that it has only 128Byts of Ram and 4K EEPROM. That means you must not declare large data structures or strings. Your program should not use deeply nested function calls or recursion. Writing a line like
char string[90];
will already be too much. An integer is 16 bit. If you need a small integer then use
unsigned char i; /* 0-255 */
You will however be surprised how big programs you can write. It's a really powerful processor!

Much better than all theory is a real example. We will write a program that causes our LED to blink in 0.5 seconds intervals. Not very useful but good to get started and to test the development environment and the programmer.

void main(void)
{
      /* enable PD5 as output */
      sbi(DDRD,PD5);
      while (1) {
            /* led on, pin=0 */
            cbi(PORTD,PD5);
            delay_ms(500);
            /* set output to 5V, LED off */
            sbi(PORTD,PD5);
            delay_ms(500);
      }
}

The above code snipt shows how simple it is to write a program. You see only the main program the delay_ms function is included in the full listing (avrledtest.c). To use pin PD5 as output you need to set the PD5 bit in the data direction register for port D (DDRD). After that you can set PD5 to 0V with the function cbi(PORTD,PD5) (clear bit PD5) or to 5V with sbi(PORTD,PD5) (set bit PD5). The value of "PD5" is defined in io4433.h which is included via io.h. You don't have to worry about it. If you have already written programs for multi user / multi tasking systems such as Linux you know that one must never program a non blocking endless loop. This would be a waste of CPU time and slow the system very much down. In the case of the AVR this is different. We don't have several tasks and there is no other program running. There is not even an operating system. It is therefore quite normal to busy loop forever.

Compiling and loading

Before you start make sure that you have /usr/local/atmel/bin in the PATH. If needed edit your .bash_profile or .tcshrc and add:

export PATH=/usr/local/atmel/bin:${PATH} (for bash)
setenv PATH /usr/local/atmel/bin:${PATH} (for tcsh)

We use the parallel port and uisp to program the AVR. Uisp uses the ppdev interface of the kernel. Therefore you need to have the following kernel modules loaded:

# /sbin/lsmod
parport_pc
ppdev
parport

Check with the command /sbin/lsmod that they are loaded other wise load them (as root) with

modprobe parport
modprobe parport_pc
modprobe ppdev

It is a good idea to execute these commands automatically during startup. You can add them to a rc script (e.g for Redhat /etc/rc.d/rc.local).
To use the ppdev interface as normal user root needs to give you write access by running once the command

chmod 666 /dev/parport0

Make as well sure that no printer daemon is running on the parallel port. If you have one running then stop it before you connect the programmer cable. Now everything is ready to compile and program our Microcontroller.

The package for our test program (avrledtest-0.1.tar.gz) includes a make file. All you need to do is type:
make
make load
This will compile and load the software. I will not go into the details of all the commands. You can see them in the Makefile and they are always the same. I can my self not remember all of them. I just know that I need to use "make load". If you want to write a different program then just replace all occurrences of avrledtest in the Makefile with the name of your program.

Some interesting binutils

More interesting than the actual compilation process are some of the binutils.

avr-objdump -h avrledtest.out

Shows the size of the different sections in our program. .text is the instruction code and loads into the flash EEPROM. .data is initialized data such as
static char str[]="hello";
and .bss is uninitialized global data. Both are zero in our case. The .eeprom is for variables stored in eeprom. I never had any use for this. stab and stabstr is debugging info and will not make it into the AVR.
avrledtest.out:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000008c  00000000  00000000  00000094  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00800060  0000008c  00000120  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00800060  0000008c  00000120  2**0
                  ALLOC
  3 .eeprom       00000000  00810000  00810000  00000120  2**0
                  CONTENTS
  4 .stab         00000750  00000000  00000000  00000120  2**2
                  CONTENTS, READONLY, DEBUGGING
  5 .stabstr      000005f4  00000000  00000000  00000870  2**0
                  CONTENTS, READONLY, DEBUGGING
You can as well use the command avr-size to get this in a more compressed form:

avr-size avrledtest.out

   text    data     bss     dec     hex filename
    140       0       0     140      8c avrledtest.out
When working with the AVR you need to watch out that text+data+bss is not more than 4k and data+bss+stack (you can not see the size of the stack, it depends on how many nested function calls you have) must not be more than 128 Bytes.

As well interesting is the command

avr-objdump -S avrledtest.out

It will generate an assembler listing of your code.

Conclusion

Now you know enough to start your own projects with the AVR hardware and GCC. There will as well be further articles in LinuxFocus with more complex and more interesting hardware.

References