Wed 26 May 2021

Introduction

The ATtiny series consists of microcontrollers that are a fit for most hobbyists. The ATtiny85 has 8-pins with 5 of them usable as I/Os (6 if you count deactivating the reset). It packs 8 kiB (8192 Byte) Flash, 512 Byte RAM and 512 Byte EEPROM for long term storage.

Pinout of the ATtiny85

Of course the specs aren't mouth-watering, but the chips capabilities are enough for almost every simple project. What makes them so easy to use is their lack of need for external components. They already have a weak integrated pull-up for the reset, so you don't need an external one. You don't need an external oscillator as they have an internal one (using the PLL of the ATtiny85 you can even go up to the maximum rated 20 Mhz using only the internal oscillator and some tricks). And with a low noise power supply you don't even need a decoupling capacitor.

A simple example program

This is a simple program written in C to blink a LED that is connected to PB4 of the ATtiny85.

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

#define LED PB4

int main(void) 
{   
    DDRB = 0xFF; // Set everything as an output

    while (1)
    {
        _delay_ms(1000);
        PORTB |= (1<<LED); // Turn the LED on
        _delay_ms(1000);
        PORTB &= ~(1<<LED); // Turn the LED off
    }

    return 0;  
}

Compiling and Uploading

Compiling this example is just a matter of calling the Open Source tools in correct order. Let's say the source file is named blink.c and resides in src/.

avr-gcc src/blink.c -Wall -Os -mmcu=attiny85 -DF_CPU=8000000 -o program.elf

Now let's strip the binary down to the bare minimum with avr-objcopy:

avr-objcopy -O ihex -R .eeprom program.elf program.hex

Flashing is done via avrdude, I have got a cheap USBasp clone:

avrdude -c usbasp -p attiny85 -P usb -U flash:w:program.hex

Now, if everything was done right you should be greeted by a blinking LED:

Demonstration of the blinky example

Makefile

This is a simple Makefile you can use to compile your code for your ATtiny. In this case put your code into the src/ directory next to the Makefile.

CC         = avr-gcc
CFLAGS     = -Wall -Os -mmcu=attiny85 -DF_CPU=8000000

SRC_DIRS   = src
OBJ_DIR    = obj

HEADERS    := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name "*.h"))
C_SRC      := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name "*.c"))
OBJECTS    := $(addprefix $(OBJ_DIR)/, $(C_SRC:.c=.o))

DIRS       := $(BUILD_DIR) $(sort $(dir $(OBJECTS)))

default: program.hex

$(OBJECTS) : | $(DIRS)

$(DIRS): 
    @echo Creating $(@)
    @mkdir -p $(@)

$(OBJ_DIR)/%.o: %.c $(HEADERS)
    @echo Compiling $(<F)
    $(CC) -o $@ -c $< $(CFLAGS)

program: $(OBJECTS)
    @echo Linking $(@)
    $(CC) -o $@ $^ $(CFLAGS)

program.hex: program
    @echo Creating $(@)
    avr-objcopy -O ihex -R .eeprom $(<) $(@)

upload: program.hex
    @echo Uploading $(<)
    avrdude -c usbasp -p attiny85 -P usb -U flash:w:$(<)

.PHONY: clean upload

clean:
    rm -f $(OBJECTS)
    rm -f program.elf program.hex

Some explanations:

-mmcu=attiny85 tells the compiler which ATtiny we want to compile for

-DF_CPU=8000000 defines F_CPU as 8 MHz, needed for delays (make sure to use the correct frequency)

In the recipes $(@) refers to the file name of the target of the rule and $< to the first prerequisite. For a complete list have a look at this.

What are those Phony targets for? This just means there is no actual file as a result of the recipe.

Fuses

You can change various properties of your ATtiny by setting the fuses. The ATtiny25/45/85 has three fuse bytes: - Fuse Extended Byte - Fuse High Byte - Fuse Low Byte

For example with the extended fuse you could enable self-programming, or with the high fuse you can configure the Brown-out Detector trigger level, the Watchdog timer and a lot more things. But we are actually interested in the low fuse byte because with it we can change the system clock.

How fast can we get? Have a look at the following line:

– ATtiny25/45/85: 0 – 10 MHz @ 2.7 - 5.5V, 0 - 20 MHz @ 4.5 - 5.5V

This means our ATtiny needs at least 2.7 V to run at a frequency of 10 MHz. If we want to go even faster we can increase the system clock to 20 Mhz but as a trade-off need a higher voltage of at least 4.5 V.

From the datasheet we get this table as description for the low fuse byte:

Fuse Low Byte Bit No Description Default Value
CKDIV8 7 Clock divided by 8 0 (programmed)
CKOUT 6 Clock output enabled 1 (unprogrammed)
SUT1 5 Start-up time setting 1 (unprogrammed)
SUT0 4 Start-up time setting 0 (programmed)
CKSEL3 3 Clock source setting 0 (programmed)
CKSEL2 2 Clock source setting 0 (programmed)
CKSEL1 1 Clock source setting 1 (unprogrammed)
CKSEL0 0 Clock source setting 0 (programmed)

Attention: We are dealing with inverse logic!

That means by default the CKDIV8 bit, dividing the internal oscillator by 8, is set to 0 and therefore active. As a result the internal 8 MHz RC oscillator is divided down to 1 MHz.

So let's say we want to get faster. Then just set the CKDIV8 bit, effectively deactiviating the divider and we are running on 8 MHz. Nice.

So how to do that?

We set the Low Fuse to 0b11100010 or in hex: 0xE2.

To do that with avrdude you add

-U lfuse:w:0xE2:m

to your command.

In case of our Makefile

avrdude -c usbasp -p attiny85 -P usb -U lfuse:w:0xE2:m -U flash:w:$(<)

Now, if you have kept your F_CPU the same, your LED should blink 8 times faster. So don't forget to change F_CPU to your effective clock rate!

Tips and Tricks

avr-size

The avr-size tool is a handy program when it comes analyzing the size of your programs.

avr-size program.elf

   text    data     bss     dec     hex filename
    366       0       0     366     16e main.elf

Now it would be good to remember your device's flash and RAM sizes, but there is an easier option. If you tell avr-size which MCU you are developing for, it can tell you exactly how much space is left:

avr-size --mcu=attiny85 --format avr program.elf

AVR Memory Usage
----------------
Device: attiny85

Program:     366 bytes (4.5% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)

That's all for now. Next blog posts will be about a PCB I designed with an ATtiny85V-10SU chip. Stay tuned!