Monday, January 20, 2014

programming the attiny10 in linux

The attiny10 (and it's brothers attiny4,5 and 9) is a cute little 6-pin SOT23-6 AVR micro-controller. The very tiny footprint and low price makes it interesting as replacement for e.g. the 555 in simple circuits.

attiny10 sitting between a 5050 RGB LED and a 555 timer IC


Programming it seems to have been quite involved but the more recent gcc supports it just fine, making it finally easier to use. I tested with 4.8.1 downloaded from Atmel, as the one provided by Debian (also 4.8.1) did not yet have the definitions for the attiny10. It seems like the public source tree for the avr tool lags behind quite a bit against the Atmel provided toolchain ...

For programming I'm using an AVRISP-MKII. I updated it to the latest firmware. This updating unfortunately requires avrstudio in windows; programming itself works fine in Linux.. You may also need a recent avrdude. I'm using 6.0.1.

Programming requires that the chip is powered by 5V according to the spec. I can confirm that this is the case because I tried it with 3.3V and it didn't work, it tries to program but fails on verification.

Once programmed the chip runs all the way down to 1.8V.

The pin mapping is pretty obvious:

attiny10 pinout:

  1. PB0/TPIDATA
  2. GND
  3. PB1/TPICLK
  4. PB2
  5. VCC
  6. PB3/RESET
AVRISP-MkII pinout:

  1. MISO
  2. VCC
  3. SCK
  4. MOSI
  5. RESET
  6. GND
And the mapping:

  • TPIDATA - MISO
  • TPISCK - SCK
  • RESET - RESET
  • GND - GND
  • VCC - VCC
The following C++ code blinks a LED every second on pin PB2:
#include <util/delay.h>
#include <avr/io.h>

static inline void setup() {
  // configure PB2 pin
  PUEB &= ~_BV(PUEB2);   // disable Pull-Up
  DDRB |= _BV(DDB2);     // enable Output mode
  PORTB &= ~_BV(PORTB2); // set output to Low
}

int main() {

  setup();

  while (true) {

    PORTB &= ~_BV(PORTB2);
    _delay_ms(500);

    PORTB |= _BV(PORTB2);
    _delay_ms(500);
  }

  return 0;
}
The following makefile builds it and uploads it with the help of avrdude:

# Makefile loosely derived from generated avr toolchain makefile

PROG   := avrispmkii
MCU    := attiny10
F_CPU  := 1000000
TARGET := blink

COMMONFLAGS = -g -Os -funsigned-char -funsigned-bitfields \
  -fpack-struct -fshort-enums -Wall -DF_CPU=$(F_CPU) -mmcu=$(MCU)

CFLAGS = -std=gnu99 $(COMMONFLAGS) -Wstrict-prototypes \
  -Wa,-adhlns=$(<:.c=.lst) \

CXXFLAGS = -std=gnu++11 $(COMMONFLAGS) -fno-exceptions -fno-rtti \
  -Wa,-adhlns=$(<:.cc=.lst) \

ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref

# TODO fuses
# FUSE:=-U lfuse:w:0xff:m -U hfuse:w:0xd9:m -U efuse:w:0xff:m

AVRDUDE:=avrdude -c $(PROG) -p $(MCU)
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex

TC = /your/path/to/avr8-gnu-toolchain-linux_x86_64

CC      = $(TC)/bin/avr-gcc
CXX     = $(TC)/bin/avr-c++
OBJCOPY = $(TC)/bin/avr-objcopy
OBJDUMP = $(TC)/bin/avr-objdump
SIZE    = $(TC)/bin/avr-size

default: $(TARGET).hex

check:
 $(AVRDUDE)

fuse:
 $(AVRDUDE) $(FUSE)

upload:
 $(AVRDUDE) $(AVRDUDE_WRITE_FLASH)

%.hex: %.elf
 $(OBJCOPY) -O ihex -R .eeprom $< $@
 $(SIZE) $@

.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: %.o
 $(CC) $(CFLAGS) $< --output $@ $(LDFLAGS)

%.o : %.c
 $(CC) -c $(CFLAGS) $< -o $@

%.o : %.cc
 $(CXX) -c $(CXXFLAGS) $< -o $@

%.s : %.c
 $(CC) -S $(CFLAGS) $< -o $@

%.o : %.S
 $(CC) -c $(ALL_ASFLAGS) $< -o $@

clean:
 -rm *.hex
 -rm *.lst
 -rm *.obj
 -rm *.elf
 -rm *.o
In action: