1

Background

In 2019, Microchip acquired Atmel and released several new AVR microcontrollers, including the Tiny-0 and Tiny-1 Series. On these mircocontrollers, traditional Atmel ICSP programming was not supported. Instead, they feature a new one-wire programming interface called Unified Programming and Debug Interface (UPDI). The new hardware also made existing TTL-serial bootloader programming obsolete. Thus, one must use a native UPDI programmer to work with these microcontrollers, such as pyupdi.

However, Optiboot's developers have subsquently developed a new version of the bootloader called Optiboot_X and implemented the STK500 programming protocol on these new microcontrollers, allowing one to program these microcontrollers using the traditional TTL-serial bootloader approach, and it appears that the Arduino community has already supported them for a while, with MegaCoreX and megaTinyCore, which was good news to me. Nevertheless, it seems that there's little resource beyond these prepackaged Arduino cores, in particular, there's almost no documentation on how to program them manually from the commandline.

What I've already done

I designed a custom AVR development board based on the Atmel ATTiny1604 microcontroller, which is a member of the new Tiny-0 family. Due to technical considerations, it must be programmed via the serial port using the bootloader similar to a traditional Arduino, not UPDI (UPDI is only used to burn the bootloader).

To achieve this goal, I installed the latest version of binutils, GCC and an experimental patch to avr-libc, so the compiler is able to generate code targeting my microcontroller. Then, I compiled my personal Optiboot_X bootloader.

$ git clone https://github.com/Optiboot/optiboot.git
$ cd optiboot/optiboot/bootloaders/optiboot
$ make -f Makefile.mega0 optiboot_attiny1604.hex UARTTX=A1 TIMEOUT=8 LED=A7 BAUD_RATE=57600 LED_START_FLASHES=10

Using Compiler at: /home/user/code/optiboot/optiboot/bootloaders/optiboot/avr-gcc avr-gcc -g -Wall -Os -fno-split-wide-types -mrelax -DWDTTIME=8 -DLED_START_FLASHES=10 -DLED=A7 -DUARTTX=A1 -DBAUD_RATE=57600 -Wl,-section-start=.text=0 -Wl,--section-start=.application=0x200 -Wl,--section-start=.version=0x1fe -Wl,--relax -nostartfiles -nostdlib -mmcu=attiny1604 -o optiboot_attiny1604.elf optiboot_x.c avr-size optiboot_attiny1604.elf text data bss dec hex filename 494 9 0 503 1f7 optiboot_attiny1604.elf avr-objdump -S optiboot_attiny1604.elf > optiboot_attiny1604.lst avr-objcopy -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex optiboot_attiny1604.elf optiboot_attiny1604.hex

Then I uploaded the Optiboot_X bootloader to the ATTiny1604 microcontroller via UPDI, using pyupdi.

# set fuse BOOTEND
$ pyupdi -d tiny1604 -c /dev/ttyUSB0 -fs 8:0x02

burn Optiboot_X

$ pyupdi -d tiny1604 -c /dev/ttyUSB0 -f optiboot_attiny1604.hex

reset

$ pyupdi -d tiny1604 -c /dev/ttyUSB0 -r

After burning the Optiboot_X via UPDI, I was able to see 10 pulses during power-on at A7 on my oscilloscope, indicating that Optiboot_X was alive.

Note: Technically the installation is not complete yet. Since UPDI and /RESET share the same pin, UPDI must be permanently disabled via fuse to allow programming via bootloader, but it means a nonfunctional bootloader can brick the chip. I decided to manually reset the chip by power cycling the board for now.

Next, I wrote a test program.

$ cat blink.c

#define F_CPU 20000000UL #include <avr/io.h> #include <util/delay.h>

int main(void) { PORTB.DIRSET = 0b00000001;

while(1) {
    PORTB.OUTSET = 0b00000001;
    _delay_ms(500);
    PORTB.OUTCLR = 0b00000001;
    _delay_ms(500);
}

}

And I compiled it.

$ make
avr-gcc -mmcu=attiny1604 -Wall -Os -o blink.elf blink.c
avr-objcopy -j .text -j .data -j .rodata -O ihex blink.elf blink.hex

Question

Now what? How do I upload blink.hex to the Optiboot_X on the microcontroller?

On a traditional Arduino, the command is something like...

$ avrdude -C/etc/avrdude/avrdude.conf -v -patmega328p \
  -carduino -P/dev/ttyUSB0 -b38400 -D -Uflash:w:blink.hex:i

But this is not an ATMega328P and there's nearly zero documentation on the web, I have a lot of questions and I'm not sure how to proceed.

To begin with, in man avrdude, there's no mention of any Tiny0 or Tiny1 devices. What should the -p argument be? Also, do I need to use a patched version of avrdude? Do I need a customized avrdude.conf? If so, where can I find them?

比尔盖子
  • 439
  • 2
  • 12

1 Answers1

2

After poking around in the git repository for a while, I've solved the problem. To work with these new TinyAVR-0/1 microcontrollers, a new version of avrdude is needed. Since avrdude hasn't made a stable release yet, it's necessary to build a new avrdude from source from SVN.

$ svn co https://svn.savannah.nongnu.org/svn/avrdude/trunk avrdude
$ cd avrdude/avrdude
$ ./bootstrap
$ mkdir build && cd build
$ ../configure
$ make
$ make install

After installation, /usr/local/bin/avrdude and /usr/local/etc/avrdude.conf should be available. One can see that a bunch of new TinyAVR parts have been added...

$ avrdude -p?

Valid parts are: [...] t10 = ATtiny10 t11 = ATtiny11 t12 = ATtiny12 t13 = ATtiny13 t15 = ATtiny15 t1604 = ATtiny1604 t1606 = ATtiny1606 t1607 = ATtiny1607 t1614 = ATtiny1614 t1616 = ATtiny1616 t1617 = ATtiny1617 t1634 = ATtiny1634 t20 = ATtiny20 t202 = ATtiny202 t204 = ATtiny204 t212 = ATtiny212 t214 = ATtiny214 t2313 = ATtiny2313 t24 = ATtiny24 t25 = ATtiny25 t26 = ATtiny26 t261 = ATtiny261 t28 = ATtiny28 t3214 = ATtiny3214 t3216 = ATtiny3216 t3217 = ATtiny3217 t4 = ATtiny4 t40 = ATtiny40 t402 = ATtiny402 t404 = ATtiny404 t406 = ATtiny406 t412 = ATtiny412 t414 = ATtiny414 t416 = ATtiny416 t417 = ATtiny417 t4313 = ATtiny4313 t43u = ATtiny43u t44 = ATtiny44 t441 = ATtiny441 t45 = ATtiny45 t461 = ATtiny461 t5 = ATtiny5 t804 = ATtiny804 t806 = ATtiny806 t807 = ATtiny807 t814 = ATtiny814 t816 = ATtiny816 t817 = ATtiny817 t84 = ATtiny84 t841 = ATtiny841 t85 = ATtiny85 t861 = ATtiny861 t88 = ATtiny88 t9 = ATtiny9 [...]

To program the ATTiny1604, simply run...

$ avrdude -C/usr/local/etc/avrdude.conf -v -pt1604 \
  -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:blink.hex:i

Don't forget to modify the -b57600 argument to match the baud of your Optiboot_X build.

Lesson learned: When RTFM is impossible, use the source, Luke!

Potential Problems

avrdude: verification error; content mismatch

It's possible that avrdude successfully establishes communication with the board via the serial port, reads the correct device signature, then attempts to upload a program, but ultimately fails verification.

$ avrdude -v -pattiny1604 -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:blink.hex:i

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9425 (probably t1604) avrdude: reading input file "blink.hex" avrdude: writing flash (204 bytes):

Writing | ################################################## | 100% 0.06s

avrdude: 204 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 contains 204 bytes avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.06s

avrdude: verifying ... avrdude: verification error, first mismatch at byte 0x0000 0x01 != 0x0c avrdude: verification error; content mismatch

Solution: In TinyAVR 0/1, the bootloader is located at the beginning of the flash memory, occupies the first 512 bytes. When compiling the program to be uploaded via the bootloader, the correct 512-byte text section offset must be specified. Otherwise, avrdude will attempt to program from 0x00, which is impossible, because it's the location of the bootloader. Upon readback, instead of your program, avrdude reads the bootloader, which triggers the verification failure in question (it's worth noticing that 0x01, the first mismatched byte that triggers verification failure, is actually the first byte in the Optiboot_X binary code).

Instead of using...

avr-gcc -mmcu=attiny1604 -Wall -Os -o blink.elf blink.c

Recompile your program with `

avr-gcc -mmcu=attiny1604 -Wall -Os -o blink.elf blink.c \
-Wl,--section-start=.text=0x200

avr-objcopy -j .text -j .data -j .rodata -O ihex blink.elf blink.hex

And reupload it.

$ avrdude -v -pattiny1604 -carduino -P/dev/ttyUSB0 -b57600 -D -Uflash:w:blink.hex:i

avrdude: Device signature = 0x1e9425 (probably t1604) avrdude: reading input file "blink.hex" avrdude: writing flash (716 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 716 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 contains 716 bytes avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.00s

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

avrdude: safemode: Fuses OK (E:FF, H:FF, L:FF)

avrdude done. Thank you.

avrdude: programmer type jtagice3_updi not found

It's possible that avrdude reports the following error...

/usr/bin/avrdude -C/usr/local/etc/avrdude.conf -v -pattiny1604 -carduino -P/dev/ttyUSB0 -b38400 -D -Uflash:w:blink.hex:i

avrdude: Version 6.3, compiled on Jul 24 2019 at 00:00:00 Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/ Copyright (c) 2007-2014 Joerg Wunsch

     System wide configuration file is &quot;/usr/local/etc/avrdude.conf&quot;

avrdude: error at "/usr/local/etc/avrdude.conf:1091: programmer type jtagice3_updi not found avrdude: error reading system wide configuration file "/usr/local/etc/avrdude.conf"

Solution: You are trying to run an old version of avrdude with a new configuration file. Make sure the avrdude executable you are running is actually the up-to-date version compiled from the upstream SVN repository.

比尔盖子
  • 439
  • 2
  • 12