Atmel AVR 8-Bit Microcontrollers


The Atmel AVR microprocessors are very similar functionally to the PIC microprocessors, with the same range in size from 8-bit, 8-pin PDIP to 32-bit processors with 100 pins, and similar features. The letters "AVR" are not an acronym and have no meaning other than identification. I think of it as Alf and Vegard's Rechner, after the architects' first names (but "computer" in Norwegian is "datamaskin"). In this page, I shall use as an example the ATtiny13A, which has 512 words of program memory, 160 bytes of datas memory consisting of 32 registers, 64 I/O bytes, 64 data bytes, and 64 bytes of EEpROM memory, which is ample for our purposes. The main restriction is that there are only 6 I/O pins with the 8-pin PDIP package. If more I/O pins are required, there are similar MCU's with up to 28 pins in a narrow DIP. The AVR is a modified Harvard architecture, with 16-bit instructions and 8-bit data. It is possible to copy bytes between program and data memory. The programming model is quite different from that of the PIC, since the AVR has no accumulator but instead the 32 registers with access to the ALU. All arithmetic must be done with these registers, not with the general data registers. Copying from one register to another can be done in a single instruction, without using an accumulator.

Most instructions can be executed in a single clock cycle, though an extra cycle is neessary if the PC is changed to anything but PC+1 because of pipelining. The internal clock can be selected as 9.6 or 4.8 MHz. As delivered, the 9.6 MHz clock with a 1:8 division is selected, giving a 1.2 MHz clock for the serial programming. A large variety of clock speeds can be chosen. The slower the clock, the smaller the supply current.

The ATtiny13A will operate from a supply voltage as low as 1.8V (maximum clock speed 4 Mhz), and with a full 20 MHz clock speed at 4.5V and above. The current drain is much reduced at the lower supply voltages and clock frequencies. There are provisions for reducing current drain to a minimum with Idle and Sleep modes, as well as turning off unnecessary features. Here, we will assume a 5 V supply and largely ignore these possibilities.

The tool equivalent to the MPLAB is AVR Studio, available free from Atmel (see References). The basic program will allow you to use the assembler and single-step through instructions. The programming tools operate in connection with the Studio program, and are not independent as the PICkit 2 is. I chose the AVRISPmkII in-system serial programmer, which is easy to connect. There may be others where the device can be plugged directly into a board, such as the Dragon. In general, the Atmel tools are not as beginner-friendly as the PIC tools. For example, there is not a single example program furnished with AVR Studio, and only one program with the assembler that can be found with some digging. However, if you are familiar with the PIC tools the experience will help you greatly.

The AVR family is used in the Basic Stamp and Arduino microcontroller boards.

The AVR Assembler

The assembler produces absolute code, so there is no need for a linker, though you can define code and data segments that are concatenated. The assembler is not case-sensitive. Decimal is the default radix. Hex numbers may be preceded by $ or 0x. Binary numbers begin with 0b. Labels must be followed by : as in main:, while assembler directives must be preceded by a ., as in .include or .org. There are no column restrictions. The program counter starts at $0000, so .org $0 is not required. Assembley stops when EOF (end of file0 is reached, so no .exit directive is required either. Make sure you have a line feed at the end of the file by hitting Enter after the last line. Comments begin with ; as in the PIC assembler. The assembler does not recognize $ as a symbol for the current PC.

The PC counts words. Byte addresses are twice the word address when this is needed, since bytes can be stored to and loaded from program memory space. Data addresses from $00 to $1F are the registers, but are normally denoted by r0, r1, ..., r31. The important instruction ldi Rr only works for r16 to r31, possibly so it will fit in 16 bits. Addresses from $20 to $5F are the "I/O" registers, like the SPR's of the PIC. In some instructions (like IN and OUT) they are denoted by $00 to $3F, which are like port numbers. In general instructions, $20 must be added to them to get the absolute address. The .equ directive has a distinctive form, for example, .equ var = $43 gives the symbol var the value $43, which cannot be changed. Use .set instead if the value will be redefined.

The first ten words of program memory, $0 to $9 are reserved for interrupt vectors, with $0 the reset vector. If interrupts are used, they should be occupied by rjmp instructions pointed to the service routines. The instruction sei enables interrupts, while cli disables them. Other bits enable the individual interrupt sources, and the interrupt flags should be cleared in the service routine. An interrupt automatically clears the interrupt enable bit, disabling further interrupts, while reti automatically sets it, enabling interrupts again. The vectored interrupts is a very convenient feature, eliminating tedious polling of the interrupt flags. On reset, interrupts are disabled.

Read the data sheet carefully to find out how to use configuration bits and interrupt flags correctly. Interrupt flags are set by hardware and cannot be set by writing a "1" to them. In fact, writing a "1" to them is the way to clear them to "0". When a "1" is written to initiate an action, the bit may be automatically cleared when the action is complete. Use SBIC to wait for the bit to clear (or SBIS if you are waiting for the bit to set). Sometimes the setting of one bit (like WDTF) causes another to be set (like WDE) so the first bit must be cleared before the second. Other bits (like WDTCE) when set, will be cleared automatically after four clock cycles (in this case) so the enabled changes then have to be made promptly and in a single instruction. Not all of these behaviours will be exhibited in the simulator, so care is advised.

Note that only the lowest 32 I/O Registers 0-31 can be bit-addressed. This includes the I/O pins, the ADC and the EEPROM. Only the upper General Purpose Registers 16-31 can be loaded immediate by LDI. When using IN and oUT, the I/O register numbers $0-$3F are used, while with LD and ST the data space address, which is $20 larger, must be used. The AVR is "little-endian"--that is, word data is stored with the low byte at the smaller address, the high byte at the higher address. Thus, the word $5B32 is stored in the byte order $32 $5B.

The ATtiny13A has 105 instructions. Practically all will be single words, since the addressing space is small. Use rjmp and rcall, which are relative, and can reach anywhere in the limited program space, rather than jmp or call which have a second word to contain the target address. The conditional branches are relative, with a range of -64 to +64. The signed integer displacement is counted from the instruction following the rjmp or rcall. The stack is located at the high end of the data memory, at $9F and builds upward. The stack pointer at I/O $3D (absolute $5D) is decremented on a PUSH or RCALL. This is the SPL, since only the low byte is required here, and SPH, which would be at $3E, is not implemented. SPL is automatically loaded with $9F on reset. The highest 6 general-purposeregisters are the word-size index registers X, Y and Z used with the LD and ST instructions. When they are not used as index registers, they can be used as normal registers. In the ATtiny13, only the low bytes are used, so $27, $29 and $31 can be used as general registers.

The most important bits are the 8 bits of the status register at I/O $3F = 63. The six lower bits are called H, S, V, N, Z and C and are affected by arithmetic and logical instructions. They are tested by branch instructions to determine magnitude relations between bytes used in compare (CP, CPC and CpI) instructions, which perform a subtraction but do not change the registers. The highest bit is I, the interrupt enable bit, which enables interrupts when it is set. Bit 6 is the transfer bit T, which can be loaded into or stored from any general register bit, and can be tested with a conditional branch, using the instructions BLD, BST, BRTC and BRTS. Any of these bits can be cleared or set by individual instructions. Actually, there are only 4 instructions to manage these bits, BCLR, BSET, BRBC and BRBS, but the assembler has 16 mnemonics that it translates into the desired instructions. The conditional branches for numerical order come in pairs each testing one bit: C, BRSH and BRLO; Z, BRNE and BREQ; N, BRMI and BRPL; S, BRGE and BRLT. in each case for the bit clear and the bit set. The C bit is used for unsigned comparisons, the S bit for signed.

The terms SH, same or higher and LO, lower are used for unsigned integers from 0 to 255, while GE, greater or equal and LT, less than are used for signed integers from -128 to + 127. Bit 7 = 1 is a negative signed integer; to find the corresponding positive integer, interchange 1 and 0 (find the 1's complement) and add 1. This is the same as subtracting the number from $00. When adding two signed integers, if the sign bit changes there is 2's complement overflow, and the V bit will be set. The S bit is always C xor V. Logical operations do not change C and always clear the V bit. INT and DEC do not change C. The odd instruction CPSE Rd,Rr skips the next instruction if Rd and Rr are equal, without changing any register or status bit. The instruction TST Rd AND's Rd with itself, not changing it but setting the status bytes, mainly for testing the Z bit. An OR would have the same effect. A register is cleared by EORing with itself with CLR Rd.

Any bit in the lower 32 I/O registers can be individually set or cleared with CBI A,b and SBI A,b, and tested with the skip instructions SBIC and SBIS. Any bit can be individually set or cleared in the upper general registers r16 to r31 with CBR Rd,k and SBR Rd,K. Here, K is an 8-bit mask with a 1 in the bit place to be affected. The assembler uses ANDI to clear a bit (automatically complementing the mask) and ORI to set a bit. There are also the corresponding SBRC and SBRS instructions to test these bits.

When AVR Studio starts, the edit window is restricted to a small patch. First, create a project by givin it a name and assigning a directory. If you clear away some windows, sufficient space can be created to edit the .asm file which will be automatically created. All you have to do when starting Studio later is click on the project from the list presented. The line number appears in the status bar at the bottom of the screen, so you can identify the line when you have an error message. The .asm file is assembled by selecting Build or pressing F7. The assembler will display its progress and list the lines it objects to if the assembly did not complete. When you have a successful assembly, it is then easy to single-step through it in the simulator. You have to pick the simulator from the list of debugging tools presented.

At the top of the .asm file the line: .include "" should appear. This file contains the specification of the target device (in a .device directive) and the symbols you may use in place of numbers. It is good to print out this file for reference. If you wish a .lst listing file, the box should be checked in the assembler configuration window. The assembler will always produce a .hex file for the use of the programmer.

The low pin count of small MCU's can be overcome for input and outut by shifting data in and out via a shift register, which requires only two pins, for data and clock. It is very easy to transfer 8 or 16 bits in this way when required.


After a successful assembly, the Debug tab will show Start Debugging in black. Selecting this will place a yellow arrow at the current PC (at $0) in the .asm file. The status bar will show the device indentification and the AVR Simulator tool. If you have not already selected the debug tool, click on Select Platform and Device and choose AVR Simulator and ATtiny13A. A processor window will appear at the left, and you may have to make some room for it. Up to 3 windows can be opened to show various parts of the data memory simultaneously. Pressing F11 performs a single step, after which you can observe its effects. The Debug tab also lets you define breakpoints at any line number. Then if you Run from any point before the breakpoint, the program will execute and stop at the breakpoint. Before you Run, you can zero the Stop Watch. Then, when the breakpoint is reached, the stop watch will show how much real time would be required to do the same. Note that the clock speed must be selected in a configuration window.

I recommend using the simulator to study the actions of the processor instructions, and to observe the various addressing modes. Note that bits and bytes can be directly set in the various memories in Studio to see how the system behaves. If a program simulates correctly, it will probably run correctly.


After installing the AVR Studio program, the USB driver can be installed. Disconnect the AVRISP from the targer system. When you plug in the USB connector, Windows XP will detect the new device and prompt you with an installation window. A green LED will light near the USB connector of the ISP, and a red LED will show that target power is not detected. Now connect the target system (using a 2-row 6-pin 0.1" header, Jameco 696950) and turn on the target power. The red LED should now turn green. I managed to solder 6 wires to the short ends of the header, and used a solderless breadboard to make the connections. The connections are ground, +5 (only for detecting target voltage--does not supply power), reset, MISO, MOSI and SCK, as shown in the diagram.

When you launch Studio, clicking on the left-hand PDIP icon marked Con will bring up the connection dialog, in which you can select AVRISP. For our purposes, the updates are not really necessary and can be declined. There are tabs for Program, Fuses, Lock and so forth. Clicking on the Fuses tab brings up the Fuses dialog. The current stat of the fuses can be read by pressing Read. A check in the box means that the fuse is, or will be, programmed (0) and no check means that the fuse will be unprogrammed (1). Select the clock source and frequency here. You may want to uncheck the CLKDIV8 fuse. It would seem that checking the WDTON fuse would disable the watchdog timer, but that is wrong. All this does is guarantee that a timeout will result in a System Reset, not a maskable interrupt, and makes the WDE and WDTIE bits ineffective. To disable the watchdog timer requires leaving the fuse unprogrammed, and setting the WDE and WDTIE bits in WDTCR to zero at the start of the program. This is not as simple as might appear, since the WDRF flag in MCUSR must be cleared, then 1's written to WDCE and WDE in WDTCR, and only then can 0's be written to WDTIE and WDE in WDTCR, which will turn off the watchdog timer. The instructions required are shown in the figure. Note that MCUSR cannot be reached by the CBI and SBI instructions, which is annoying. To program the fuses as you have selected, simply press Program.

The program dialog allows you to program the Flash memory, using hex files produced by the assembler. Simply select the .hex file to use, and press Program, The program will be loaded into the target system and Reset released, so the program will execute immediately. This is very fast and simple. Once you have chosen the ISP, simply pressing the right-hand PDIP icon will bring up the programming dialog. My programming setup is shown at the left. The ATtiny13 blinks two LED's alternately at 0.5 Hz. The ISP should be connected and disconnected to the target system when it is active and the LED's are lighted. The green LED at the USB connection and the red LED showing target power not detected can be seen. The pushbuton is Reset, and the 6-pin header is just to its right. The DIP switches are not used in this example.

Using the Timer-Counter

As a timer, this facility counts the system clock with prescaler factors of 1, 8, 64, 256 or 1024. As a counter, it counts positive or negative edges of a signal applied to the T0 pin (pin 7). In the normal mode, it increments from 00 to FF ane then rolls over and starts from 00 again. The timer contents can be written or read at the register TCNT0 at any time. There are two 8-bit output compare registers OCR0A and OCR0B. They detect when the timer contents are equal to their contents and take a prescribed action. They control output pins OC0A and OC0B, which they can set, reset or toggle. In the CTC (counter reset on compare) OCOA resets the timer to 00. If it is configured to toggle the output, a square wave of any desired frequency appears at OC0A. There are also modes in which the counter behaves as in normal mode, but the output compare turns the output off or on at a selected point, producing a pule-width modulated (PWM) wave that can be used, for example, for motor control. There are actually two PWM modes, one in which the counter counts from 00 to FF and rolls over, and another in which it increments from 00 to FF and then decrements from FF to 00.

A successful output compare or the rolling over of the counter can generate an interrupt. The interrupt enables are in the TIMSK0 register, OCIE0A, OCIE0B and TOIE0 as bits 3, 2 and 1. A 1 enables the corresponding interrupt. The flags are in TIFR0 at the same bit numbers. They are cleared by writing a 1 to them, and TOV0 is cleared by hardware when the interrupt is serviced.

The timer is configured with registers TCCR0A and TCCR0B. In TCCR0A, bits 7 and 6 are COMOA1 and COMOA0, controlling the OC0A output. 00 is off, 01 is toggle, 10 is clear and 11 is set. Pins 5 and 4 do the same for OC0B. Bits 1 and 0 are WGM01 and WGM00, which toogether with WGM02 in TCCR0B select the counter mode. 000 gives normal mode, 010 the CTC mode, 001 the fast PWM mode that counts from 00 to FF, and 011 the phase correct PWM mode that increments to FF and then decrements back to 00 (incidentally, the TOV0 flag is only set after a complete cycle in this mode). There are a few details with the PWM modes that are described in the data sheet. Bits 2, 1 and 0 in TCCR0B select the clock source. 000 stops the counter. 001 to 101 select the system clock with prescaling 1, 8, 64, 256 and 1024. 110 selects an external clock on T0 triggering on falling edge, while 111 selects an external clock with positive-edge triggering.

The timer can be stopped by writing a 1 to TSM and 1 to PSR10 in the GTCCR, which holds the timer in reset. When 0 is written to TSM, the timer starts and the PSR10 bit is automatically cleared. This allows synchronization of the timer.

To make a 1 kHz square wave at pin 5, PB2, configure the counter as follows. Write a 1 bit to bit 0 of DDRB to make the pin a digital output. If the system clock is 4.8 MHz, a prescaler factor of 64 with the counter counting to 75 = $4B will give the desired frequency. Write $4B to OCR0A, $03 to TCCR0B, and $43 to TCCR0A.

An analog output voltage can be made by creating a PWM square wave, and applying it to a low-pass filter consisting of a capacitor with a resistor in series, the capacitor voltage buffered with an op-amp. This allows control of the voltage by what is loaded into OCR0A, in effect a digital-to-analog converter.

Usung the ADC

The analog-to-digital converter (ADC) is a very useful input device for a small MCU, since it requires only a single input pin. It can represent a set level, or measure temperature, in a thermostat. In the ATtiny13A, the analog input can be applied to any of four pins, and the reference voltage can be either Vcc or the internal 1.1V bandgap reference. The 10-bit resolution gives a precision of 0.1% or 5 mV, which is ample for any normel application. The ADC is a successive-approximation converter with a clock that should be between 50 kHz and 200 kHz for maximum accuracy. The ADC clock is obtained froma the system clock by a prescaler giving factors from 2 to 128. In this example, I suggest dividing the 4.8 MHz system clock by 64, giving an ADC clock of 75 kHZ.

The ADC resut appears in two 8-bit registers, ADCH and ADCL. We may choose left-justified when the high byte is in ADCH and the remaining two bits are in ADCL, or right-justified when the low byte is in ADCL and the remaining two bits are in ADCH. If we only need 8-bit precision, the first alternative is selected, and we read only ADCH. In any case, if we read ADCL, then ADCH is locked until we read it, guaranteeing that the two reads are from the same conversion.

If we load the ADMUX register with $23, we select Vcc as the reference voltage, a left-justified result, and pin 2, ADC3 or PB3, as the analog input. Then we load the value $08 in the DIDR0 register to disable the digital input circuitry for the pin. This may not be necessary, but it reduces the power consumption. If we now load ADCSRA with $B6, we turn on the ADC (but do not trigger a conversion), set automatic triggering, and select the prescaler factor of 64 for the ADC clock. Since we have chosen automatic triggering, we must load ADCSRB with $00 to select free running. To start conversions, we must now set the ADSC bit in ADCSRA, with sbi ADCSRA,6. In free running, the completion of a conversion triggers the next conversion. If we had not set the ADATE bit, then we would not need to load ADCSRB, but simply set ADSC to start a conversion and then test it until it cleared at the end of the conversion. A free running convrsion takes 2 ADC clock cycles for the sampling and 13.5 clocks for the conversion. With the 4.8 MHz system clock, this means a conversion about every 0.2 ms.

Using the Analog Comparator

The analog comparator can compare two analog inputs and set the ACO bit if the voltage at the +V input is greater than that at the -V input. The voltage applied to +V can be selected to be the internal bandgap reference of 1.1V or the voltage applied to the AIN1 pin, while the voltage applied to the -V input can be the voltage applied to the AIN0 pin, or a selcted ADC input pin, if the ADC is not being used. The digital function at AIN1 and AIN0 can be disabled by writing 1's to bits 1 and 0 of DIDR0 to reduce current drain. Most functions are controlled by the ACSR register. The ACD bit (7) can disable the comparator, the ACBG bit (6) puts the bandgap voltage reference on +V if set, ACo (5) is the comparator output bit. ACI (4) is the interrupt flag, automatically cleared when the interrupt is serviced or by writing a "1" to it. ACIE (3) enables the interrupt when set. Bit 2 is not used, but bits 1 and 0 select the change that will cause an interrupt--00 on toggle, 10 on fall, 01 on rise, of ACO.

To use the ADC multiplexer, ADEN in ADCSRA must be cleared, and ACME in ADCSRB must be set. Then ACMUX selects the input, which can have its digital function disabled to save power. If ACME is cleared, AIN1 is the input to -V. If the ADC is shut down to save power in PRR register, the comparator is also shut down.

The comparator is useful for detecting levels, as for illumination or alarms, but is not directly useful in a closed-loop control system because it lacks hysteresis. In a temperature controller, the heater should turn off at a higher temperature than it turns on, to avoid rapid cycling or "hunting" at a set point. The ADC may be better suited in this case. One easy way to overcome the lack of hysteresis is to examine ACO at regular intervals, and turn the heater (say) off or on accordingly. This will prevent too frequent cycling.


The Atmel website is at Atmel of San Jose, CA, organized in 1984. AVR Studio can be downloaded free. First download Build 684, 116MB, which is the complete basic program, with assembler and simulator. Updates are included in further files of size about 28MB, but do not seem to be absolutely necessary for our purposes. Also download user's guides for the assembler, instruction set and data sheets for the devices you will use. You can register with support and submit questions. The support function is based in Norway, the home of the inventors, and can be reaced at Support. You will need to register to submit questions. Atmel support actually talks with the common man, and gives prompt and useful answers, unlike Microchip.

Another website with information on AVR hardware is AVR Freaks.

Return to Electronics Index

Composed by J. B. Calvert
Created 16 May 2010
Last revised 26 May 2010