AVR Tutorial - Getting Started: Blinking an LED

Blinking an LED is the "Hello World" of programming microcontrollers. It is a great way to work through the entire development process and make sure all your tools are in working order.

Wiring The Circuit

The schematic diagram for the Blink LED project is shown in first figure. A photo of the circuit wired up on a breadboard is shown in second figure.

Schematic diagram for the Blink LED project

If you are not familiar with wiring integrated circuits (ICs), the AVR chip have a little notch at one end to designate the "top". The pin numbering starts at 1 on the top left, progress squentially down the left side, and then back up the right side as shown in the schematic above.

A 10kΩ "pull-up resister" (R1) is connected to the RESET pin to keep the pin in a digital high state.

A 470Ω resistor (R2) and an LED (LED1) are connected to pin PB0. The resistor is a "current limiting" resistor to limit the current (mA) passing through the LED so that it doesn't burn out. When PB0goes low (0V) the LED will turn on. When PB0 goes high (+5V) the LED turns off.

A 0.1uF "bypass capacitor" (C1) helps prevent noise or "ripple" on the +5V line from effecting the microcontroller.

Circuit wired up on a breadboard

Powering The Circuit

The schematic shows a DC power source of +5V to power the microcontroller, however, it's up to you to provide that +5V. One of the most common ways hobbyists use provide +5V to projects is to use a 9V battery with a 7805 voltage regulator IC to drop the voltage down to +5V.

I prefer to use 4 rechargable AA batteries (4 batteries x 1.2V ea. = 4.8V). You can pick up rechargable AA batteries and chargers just about anywhere these days. You can wire them up to you breadboard using a 9V Battery Clip as shown in figure 2.3.

Of course, having a +5V power source in your "lab" (whatever that may be) is invaluable. Hobbyists often get +5V out of a wall outlet by using an expensive lab power supply (which is awesome if you can afford it), using a +5V AC/DC wall adaptor, using the +5V line of an ATX computer power supply, or tapping the +5V line from a USB bus or USB charger.

DC power source of +5V to power the microcontroller

Compiling the C Program

The C program must be compiled into an Intel HEX formated file. This is the format that is passed to avrdude which tells the AVR programmer what to program into the microcontroller. The HEX file is created in two steps.

First, avr-gcc will be used to compile the C program blink.c into a binary ELF (Executable andLinkable Format) object file. This new file will be named blink.elf.

avr-gcc -mmcu=atmega328p -Wall -Os -o blink.elf blink.c
  • -mmcu, tells the compiler which AVR microcontroller the code is being compiled for. If you are not using an ATmega328P then you will need to change it to the AVR that you are using.
  • -Wall turns on all reasonable compiler warnings which will help make sure you're writing good code. Any time you see a warning you will want to investigate what it means.
  • -Os is the optimization flag which tells the compiler to optimize the code for efficient space utilization.
  • -o argument specifies blink.elf as the output filename.

Next, avr-objcopy copies specific sections of binary data from the blink.elf file into a new Intel HEX format file. The new file will be named blink.hex.

avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex
  • -j specifies Memory Sections to copy from the ELF file. It is used twice, once to copy the .textsection and once for the .data sections. The .text section contains the machine instructions which make up the program. The .data section contains various static data used in the program.
  • -O ihex option specifies Intel HEX as the output format.
  • blink.elf is passed as the input file and blink.hex is specified as the output file.

The Blink LED program doesn't actually use the .data section, but most projects will. Including it now won't hurt anything.

The blink.hex file is now ready to be programmed into the AVR.

The Blink LED Program

As was described in Overview of the Development Process, the "firmware" which tells the AVR microcontroller what to do is written in C. The GNU Toolchain is used to compile that code into a file formatted for programming into the AVR.

The C program for Blink LED is shown below.

#define F_CPU 1000000UL

#include <avr/io.h>
#include <util/delay.h>

int
main (void)
{
    DDRB |= _BV(DDB0); 
    
    while(1) 
    {
        PORTB ^= _BV(PB0);
        _delay_ms(500);
    }
}

This code configures the PB0 pin on the AVR microcontroller as a digital output. Then, it toggles the state of that pin every 500 ms. For now, just copy and paste this code into a file named blink.c.

Programming the AVR Microcontroller

Now for the moment of truth. The blink.hex file will now be programmed into the microcontroller using the avrdude program. Make sure the AVR programmer is connected to your circuit and to your computer and that the circuit has power. Then you can run the avrdude command:

avrdude -p m328p -c usbtiny -e -U flash:w:blink.hex
  • -p specifies the AVR microcontroller part number being programmed. If you are not using an ATmega328P then you will need to specify the AVR you are using.
  • -c specifies the AVR programmer you are using. If you are not using a USBtinyISP then you will need to specify the AVR programmer you are using.
  • -e erases the chip before writing the new contents
  • -U flash:w:blink.hex performs a memory operation: flash is the type of memory, w is for a "write" operation, and blink.hex is the name of the file to write. In other words, "write blink.hex to flash memory".

If the AVR microcontroller was successfully programmed then the LED should start blinking about once per second and the output of avrdude should look like the following:

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e950f
avrdude: erasing chip
avrdude: reading input file "blink.hex"
avrdude: input file blink.hex auto detected as Intel Hex
avrdude: writing flash (200 bytes):

Writing | ################################################## | 100% 0.61s

avrdude: 200 bytes of flash written
avrdude: verifying flash memory against blink.hex:
avrdude: load data flash data from input file blink.hex:
avrdude: input file blink.hex auto detected as Intel Hex
avrdude: input file blink.hex contains 200 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.38s

avrdude: verifying ...
avrdude: 200 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

Congratulations, you have now programmed an AVR microcontroller!

Connecting the AVR Programmer

The AVR microcontroller will be programmed, in it's circuit, right where it is on the breadboard. This is known as In System Programming or ISP. Connecting the AVR Programmer's ISP cable to the microcontroller on the breadboard can be a little confusing at first, so bear with me.

There are 2 standard ISP connections. A 10-pin and a 6-pin connection. The AVR Programmer typically has a 6 or 10 pin ribbon cable comming out of it. This cable is meant to be connected to what's known as a "shrouded header" on a PCB (printed circuit board). The ISP cable does not directly plug directly into a breadboard without some help.

The cheap and simple way to connect the ISP cable to the breadboard is to simply stick hookup wire into the ISP cable connector and then to the corresponding pins on the AVR microcontroller.

Stick hookup wire into the ISP cable connector Corresponding pins on the AVR microcontroller

In order to connect the ISP cable, a pinout diagram is used to determine which pins of the ISP connection correspond to which pins on the AVR microcontroller. The pinouts for the 6 and 10 pin ISP connectors are shown below. The square pin in the pinout depicts pin 1. The red conductor on a ribbon cable also depicts pin 1.

Pinouts for the 6 and 10 pin ISP connectors

The trick to this is that the pinout is for the header, not the cable. In other words, it depicts the pins of the header that the cable would plug into, as would be seen from above. If you are looking into the plug-end of the cable, you are looking at it flipped over (as if from underneath the PCB). It's easy to inverse the connections if you do not understand the pinout diagram.

Plug-end of the cable

Connect hookup wire from the ISP cable to the corresponding pins of the AVR microcontroller on the breadboard.

Troubleshooting

If the AVR programmer's ISP cable is not properly connected to the AVR microcontroller or the circuit does not have power, avrdude will show an error like this:

avrdude: initialization failed, rc=-1
         Double check connections and try again, or use -F to override
         this check.