Nav:  [home][elec][pdev] > [avr]
 
← [What are these? Why?]

Atmel/AVR-programming

The AVR 8bit RISC family of microcontrollers can easily be used in self-made circuits. These pages here describe how to compile software for AVRs and how to actually download it on the chip.

AVRs: Overwiew and Purpose

The Atmel AVRs are a family of 8bit RISC processors. In contrast to Microchip PICs, Atmel's AVRs execute most instructions in a single clock cycle (PICs need 4 clocks) and they come with a pretty well-designed instruction set suitable for higher-level languages such as C (unlike the minimalistic PIC approach). AVRs can be clocked at a rate of up to 16 or 20MHz, they come with several kb flash as well as several hundret bytes to kilobytes of SRAM and EEPROM. Furthremore, they feature PWMs, timers/counters, external interrupts, watchdog and other things you may need.

To make it short, AVRs are well-suited for a wide range of controlling and processing applications. And of course they can be in-system programmed via SPI (serial programming interface).

Writing AVR Firmware

Imagine you have some cool device in your mind which needs to apply an Atmel AVR microcontroller. Then the first critical part is about writing your device's firmware, i.e. the code which will get executed by the microcontroller once the device is running.

Normally, you will choose to write this code in C language, possibly with some amount of inline assembly when precise timing matters. If you have some experience in writing C programs for regular computers, programming an AVR microcontroller will turn out to be pretty straightforward. Here's a hello world program which will run on a variety of AVR controllers (they just need to have a port named B3):

// hello_world.c - Hello world C program for AVR microcontrollers.
//                 Written by Wolfgang Wieser 2007
//                 Public domain: You can do with this file what you want.

#include <inttypes.h>
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>

// Inline assembly: The nop = do nothing for one clock cycle.
#define nop()  __asm__ __volatile__("nop")

// Define some useful types:
typedef signed char int8;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;

int main(void)
{
    // Enable output on port B3:
    DDRB|=(1U<<3);
    
    // Toggle the output level on port B3.
	// This happens at above 100kHz for device running at 1MHz;
	// well visible with an oscilloscope.
    for(;;)
    {
        PORTB|=(1U<<3);    // Port B3 goes HIGH.
        nop();             // Wait for one clock.
        PORTB&=~(1U<<3);   // Port B3 goes LOW.
    }
    
    // Never reached.
    return(0);
}

Types: The AVR family are 8-bit microcontrollers, but with a smart compiler such as the GCC you can also handle larger integers; in fact even 32bit integers are no big deal but always remember that more bits also means more storage size and more 8-bit instructions for whatever you do with your variables. Instead of using semi-defined types int and short, I recommend the typedefs in the program above. Always use uint8 for small positive integers and uint16 if you need more range, etc.

Compiling AVR Firmware

In order to compile C source code (possibly with inline assembly) for the AVR, I recommend using the well-known and high quality free GNU C Compiler gcc as a cross-compiler to the AVR architecture. Currently, I am using the 3.4.5-based version in cdk4avr which is really easy to install (copy it somewhere -- no need to configure paths).

In order to compile the code, use

avr-gcc -s -mmcu=atmega8 source.c -o firmware.elf

Of course, you will need to use -mmcu=atmega162 if you are using an ATMega162 instead of the ATMega8.
The command above will compile your code and output it as an ELF executable. This, however, cannot be downloaded directly to the microcontroller. For this reason,

avr-objcopy -j .text -j .data -O binary firmware.elf firmware.bin

will copy the text and data sections from the compiler output into the binary file firmware.bin which can then be downloaded directly into the AVR's flash memory.
You may need to do the same with the eeprom section if you want to initialize the EEPROM memory in the microcontroller.

My programmer (usb-atmelprg) will accept binary files only. However, in case you have some other programmer device around, you may also want to use -O ihex to output Intel hex format which is widely accepted by in-system programmers and other such devices.

Actually Loading the Firmware onto the AVR

The best to program an AVR microcontroller is via the SPI (requiring only 3 signal lines). (There is usually also the possibility of parallel downloading but since this does not allow in-system programming and requires a lot more pin connections, it is only interesting for large scale production use; see historic pages if you are really interested.)

Electrical connections: So, in order to program your AVR, you need to connect the three SPI pins called MISO, MOSI and SCK. Additionally, you also need to control the RESET pin and you'll need a ground return, of course. Basically, all you have to do is to connect these pins to your programmer's interface cable (like my USB-AtmelPrg cable and download the flash content from the host computer to the AVR microcontroller.

Host computer: Refer to your programmer's manual how to do flash an AVR. For those using usb-atmelprg it is described here and also just below:

usb-atmelprg> erase
usb-atmelprg> load firmware.bin
usb-atmelprg> writeflash firmware.bin
usb-atmelprg> load eeprom.bin ; writeeeprom eeprom.bin
usb-atmelprg> dc

The load command will load the specified file into a buffer with the same name (by default). The writeflash command will then write the specified buffer onto the AVR. It's important to first erase before re-programming. The same can be done with EEPROM if needed. Finally dc disconnects from the microcontroller again and takes it out of reset (always do this as the very last step).

You may find it useful to verify the flash content so check if programming succeeded:

usb-atmelprg> cmpflash firmware.bin
usb-atmelprg> readeeprom ; cmp eeprom eeprom.bin

The cmpflash command is just a shorthand for the read-and-compare steps presented for the EEPROM. It has the advantage to be faster in case the buffer is much shorter than the flash size.

I find it convenient to put all the required commands into one single line and execute them each time I re-compile the firmware:

usb-atmelprg> load firmware.bin ; erase ; writeflash firmware.bin ;
    cmpflash firmware.bin ; dc

Each time you start with a new (not yet touched) AVR chip you will probably want to set the fuse bits so that the correct clock source is selected and so on. This can be done with the commands getfl and setfl. Fuse bits don't get touched by the erase command so you normally change them infrequently.

usb-atmelprg> setfl fuseL=0b11101111 !

Don't forget the exclamation mark for setfl but only use it if you are sure to have the settings right! You can lock yourself out with wrong clock settings (e.g. when switching to external clock sources and not having connected any such external clock).


[home] [site map]
Valid HTML 4.01!
Copyright © 2003-2007 by Wolfgang Wieser
Last modified: 2007-07-10 23:38:46