AVR 用の USB プログラマ「USBasp」を製作したときのメモです。

今回製作した USBasp の写真

概要

海外の有志の方が AVR 一石だけで動作する USB 接続型の AVR 向けプログラマの回路図およびファームウェアのコードを公開されています。 これを独自の変更を加えつつ (自分の好みに合わせて) 製作しました。

使用したバージョンは usbasp.2011-05-28.tar.gz。 次のような流れで作業していきます。

  1. 回路図を書き、ユニバーサル基板上に実装 (ハンダ付け)
  2. Atmel 社公式のプログラマ AVRISP mkII を用いてファームウェアを書き込む
  3. 動作確認

回路図

回路図は以下のよう。

今回製作した USBasp の回路図

オリジナルからの主な変更点は以下のとおりです。

完成写真

ブレッドボード上に実装してテストをし、正しく動作することを確認すると、ハンダ付け後に悲しみが広がる可能性がグッと減ります。

今回は部品点数が比較的少なめなため、電子工作では定番の「フリスクケース」に収納できるサイズにしてみました。

おもて

かなりギッシリ詰め込んでいます

うら

UEW を用いて配線してあります。右下部分の配線は白色のグルーで固定しています

フリスクケースに収納したところ。おもて

スライドさせるとフリスクではなく USBasp が顔を出します

うら

ピンヘッダ部分と USB コネクタ部分を切り取っています

ファームウェア

最後にマイコンにファームウェアを書き込みます。

ビルド

すでにビルド済みのバイナリ (hex ファイル) が同梱されているのでそれを使ってもいいけれど、 今回は自分の環境でビルドしてみました。

まずは Makefile の修正。 ターゲット (TARGET=atmega88p)、ヒューズビット (HFUSE=0xdd, LFUSE=0xf0) とプログラマの設定 (ISP=avrispmmkII, PORT=usb) を書き込みます。 また、特別な設定をしないと avrdude が一般ユーザ権限では動作しないため、sudo をつけます。

   1 Index: usbasp.2011-05-28/firmware/Makefile
   2 ===================================================================
   3 --- usbasp.2011-05-28.orig/firmware/Makefile    2011-05-28 16:57:49.000000000 +0900
   4 +++ usbasp.2011-05-28/firmware/Makefile 2013-07-24 22:42:30.007297644 +0900
   5 @@ -7,9 +7,9 @@
   6  # TARGET=atmega8    HFUSE=0xc9  LFUSE=0xef
   7  # TARGET=atmega48   HFUSE=0xdd  LFUSE=0xff
   8  # TARGET=at90s2313
   9 -TARGET=atmega8
  10 -HFUSE=0xc9
  11 -LFUSE=0xef
  12 +TARGET=atmega88p
  13 +HFUSE=0xdd
  14 +LFUSE=0xf0
  15  
  16  
  17  # ISP=bsd      PORT=/dev/parport0
  18 @@ -17,8 +17,8 @@
  19  # ISP=stk500   PORT=/dev/ttyS1
  20  # ISP=usbasp   PORT=/dev/usb/ttyUSB0
  21  # ISP=stk500v2 PORT=/dev/ttyUSB0
  22 -ISP=usbasp
  23 -PORT=/dev/usb/ttyUSB0
  24 +ISP=avrispmkII
  25 +PORT=usb
  26  
  27  help:
  28         @echo "Usage: make                same as make help"
  29 @@ -76,13 +76,13 @@
  30         $(COMPILE) -E main.c
  31  
  32  flash:
  33 -       avrdude -c ${ISP} -p ${TARGET} -P ${PORT} -U flash:w:main.hex
  34 +       sudo avrdude -c ${ISP} -p ${TARGET} -P ${PORT} -U flash:w:main.hex
  35  
  36  fuses:
  37 -       avrdude -c ${ISP} -p ${TARGET} -P ${PORT} -u -U hfuse:w:$(HFUSE):m -U lfuse:w:$(LFUSE):m
  38 +       sudo avrdude -c ${ISP} -p ${TARGET} -P ${PORT} -u -U hfuse:w:$(HFUSE):m -U lfuse:w:$(LFUSE):m
  39  
  40  avrdude:
  41 -       avrdude -c ${ISP} -p ${TARGET} -P ${PORT} -v
  42 +       sudo avrdude -c USBasp -p ${TARGET} -P ${PORT} -v
  43  
  44  # Fuse atmega8 high byte HFUSE:
  45  # 0xc9 = 1 1 0 0   1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000)

コンパイラのバージョンが違うせいか、flash が指定されている変数に const をつけろ、 というエラーを吐いてビルドに失敗するので、以下のように修正します。

   1 Index: usbasp.2011-05-28/firmware/usbdrv/usbdrv.c
   2 ===================================================================
   3 --- usbasp.2011-05-28.orig/firmware/usbdrv/usbdrv.c     2011-01-20 02:17:36.000000000 +0900
   4 +++ usbasp.2011-05-28/firmware/usbdrv/usbdrv.c  2013-07-17 01:39:58.898812000 +0900
   5 @@ -67,7 +67,7 @@
   6  #if USB_CFG_DESCR_PROPS_STRING_0 == 0
   7  #undef USB_CFG_DESCR_PROPS_STRING_0
   8  #define USB_CFG_DESCR_PROPS_STRING_0    sizeof(usbDescriptorString0)
   9 -PROGMEM char usbDescriptorString0[] = { /* language descriptor */
  10 +const PROGMEM char usbDescriptorString0[] = { /* language descriptor */
  11      4,          /* sizeof(usbDescriptorString0): length of descriptor in bytes */
  12      3,          /* descriptor type */
  13      0x09, 0x04, /* language index (0x0409 = US-English) */
  14 @@ -77,7 +77,7 @@
  15  #if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN
  16  #undef USB_CFG_DESCR_PROPS_STRING_VENDOR
  17  #define USB_CFG_DESCR_PROPS_STRING_VENDOR   sizeof(usbDescriptorStringVendor)
  18 -PROGMEM int  usbDescriptorStringVendor[] = {
  19 +const PROGMEM int  usbDescriptorStringVendor[] = {
  20      USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
  21      USB_CFG_VENDOR_NAME
  22  };
  23 @@ -86,7 +86,7 @@
  24  #if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 && USB_CFG_DEVICE_NAME_LEN
  25  #undef USB_CFG_DESCR_PROPS_STRING_PRODUCT
  26  #define USB_CFG_DESCR_PROPS_STRING_PRODUCT   sizeof(usbDescriptorStringDevice)
  27 -PROGMEM int  usbDescriptorStringDevice[] = {
  28 +const PROGMEM int  usbDescriptorStringDevice[] = {
  29      USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN),
  30      USB_CFG_DEVICE_NAME
  31  };
  32 @@ -95,7 +95,7 @@
  33  #if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN
  34  #undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
  35  #define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    sizeof(usbDescriptorStringSerialNumber)
  36 -PROGMEM int usbDescriptorStringSerialNumber[] = {
  37 +const PROGMEM int usbDescriptorStringSerialNumber[] = {
  38      USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN),
  39      USB_CFG_SERIAL_NUMBER
  40  };
  41 @@ -108,7 +108,7 @@
  42  #if USB_CFG_DESCR_PROPS_DEVICE == 0
  43  #undef USB_CFG_DESCR_PROPS_DEVICE
  44  #define USB_CFG_DESCR_PROPS_DEVICE  sizeof(usbDescriptorDevice)
  45 -PROGMEM char usbDescriptorDevice[] = {    /* USB device descriptor */
  46 +const PROGMEM char usbDescriptorDevice[] = {    /* USB device descriptor */
  47      18,         /* sizeof(usbDescriptorDevice): length of descriptor in bytes */
  48      USBDESCR_DEVICE,        /* descriptor type */
  49      0x10, 0x01,             /* USB version supported */
  50 @@ -139,7 +139,7 @@
  51  #if USB_CFG_DESCR_PROPS_CONFIGURATION == 0
  52  #undef USB_CFG_DESCR_PROPS_CONFIGURATION
  53  #define USB_CFG_DESCR_PROPS_CONFIGURATION   sizeof(usbDescriptorConfiguration)
  54 -PROGMEM char usbDescriptorConfiguration[] = {    /* USB configuration descriptor */
  55 +const PROGMEM char usbDescriptorConfiguration[] = {    /* USB configuration descriptor */
  56      9,          /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */
  57      USBDESCR_CONFIG,    /* descriptor type */
  58      18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT3 +
  59 Index: usbasp.2011-05-28/firmware/usbdrv/usbdrv.h
  60 ===================================================================
  61 --- usbasp.2011-05-28.orig/firmware/usbdrv/usbdrv.h     2011-01-20 02:17:36.000000000 +0900
  62 +++ usbasp.2011-05-28/firmware/usbdrv/usbdrv.h  2013-07-17 01:39:06.094814000 +0900
  63 @@ -448,43 +448,43 @@
  64   * arrays as declared below:
  65   */
  66  #ifndef __ASSEMBLER__
  67 -extern
  68 +extern const
  69  #if !(USB_CFG_DESCR_PROPS_DEVICE & USB_PROP_IS_RAM)
  70  PROGMEM
  71  #endif
  72  char usbDescriptorDevice[];
  73  
  74 -extern
  75 +extern const
  76  #if !(USB_CFG_DESCR_PROPS_CONFIGURATION & USB_PROP_IS_RAM)
  77  PROGMEM
  78  #endif
  79  char usbDescriptorConfiguration[];
  80  
  81 -extern
  82 +extern const
  83  #if !(USB_CFG_DESCR_PROPS_HID_REPORT & USB_PROP_IS_RAM)
  84  PROGMEM
  85  #endif
  86  char usbDescriptorHidReport[];
  87  
  88 -extern
  89 +extern const
  90  #if !(USB_CFG_DESCR_PROPS_STRING_0 & USB_PROP_IS_RAM)
  91  PROGMEM
  92  #endif
  93  char usbDescriptorString0[];
  94  
  95 -extern
  96 +extern const
  97  #if !(USB_CFG_DESCR_PROPS_STRING_VENDOR & USB_PROP_IS_RAM)
  98  PROGMEM
  99  #endif
 100  int usbDescriptorStringVendor[];
 101  
 102 -extern
 103 +extern const
 104  #if !(USB_CFG_DESCR_PROPS_STRING_PRODUCT & USB_PROP_IS_RAM)
 105  PROGMEM
 106  #endif
 107  int usbDescriptorStringDevice[];
 108  
 109 -extern
 110 +extern const
 111  #if !(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER & USB_PROP_IS_RAM)
 112  PROGMEM
 113  #endif

ビルドする。

$ cd firmware
$ make main.hex 
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega88p  -c usbdrv/usbdrv.c -o usbdrv/usbdrv.o
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega88p  -x assembler-with-cpp -c usbdrv/usbdrvasm.S -o usbdrv/usbdrvasm.o
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega88p  -c usbdrv/oddebug.c -o usbdrv/oddebug.o
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega88p  -c isp.c -o isp.o
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega88p  -c clock.c -o clock.o
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega88p  -x assembler-with-cpp -c tpi.S -o tpi.o
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega88p  -c main.c -o main.o
avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=atmega88p  -o main.bin usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o isp.o clock.o tpi.o main.o -Wl,-Map,main.map
rm -f main.hex main.eep.hex
avr-objcopy -j .text -j .data -O ihex main.bin main.hex

書き込み

Atmel 社の AVRISP mkII を用いて書き込みます。

まずは今回作った USBasp の Self Programming ジャンパを短絡させます。 ピンヘッダの取り付け方が正しくない()ので、ジャンパピンではなくハンダで無理矢理導通させることにしました。

左下部分のピンヘッダにハンダを巻いて短絡させています

続いて AVRISP mkII と今回作った USBasp を次の写真のように接続します。 USBasp 側に電源が来ていないとエラーになるので、USBasp にも USB ケーブルを挿すこと! あと AVRISP mkII のマニュアルには 1 番ピン (RESET) にプルアップを入れろとか書いてあるけど、なくても動いたので省略。

両者ともブレッドボードに挿して接続します

まずはファームウェア書き込み。

$ make flash 
sudo avrdude -c avrispmkII -p atmega88p -P usb -U flash:w:main.hex

avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e930f
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as Intel Hex
avrdude: writing flash (4438 bytes):

Writing | ################################################## | 100% 1.53s

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

Reading | ################################################## | 100% 1.27s

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

avrdude: safemode: Fuses OK

avrdude done.  Thank you.

つぎにヒューズビットの書き込み。

$ make fuses 
sudo avrdude -c avrispmkII -p atmega88p -P usb -u -U hfuse:w:0xdd:m -U lfuse:w:0xf0:m

avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e930f
avrdude: reading input file "0xdd"
avrdude: writing hfuse (1 bytes):

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

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xdd:
avrdude: load data hfuse data from input file 0xdd:
avrdude: input file 0xdd contains 1 bytes
avrdude: reading on-chip hfuse data:

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

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xf0"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xf0:
avrdude: load data lfuse data from input file 0xf0:
avrdude: input file 0xf0 contains 1 bytes
avrdude: reading on-chip lfuse data:

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

avrdude: verifying ...
avrdude: 1 bytes of lfuse verified

avrdude done.  Thank you.

最後に USBasp の Self Programming ジャンパを開放して完成です!

動作確認

認識させる

ファームウェア書き込み後、一度 USBasp の USB ケーブルを挿し直し、ターミナルから dmesg をすると

$ dmesg | tail -n5
[46381.362754] usb 2-1.1.4: new low-speed USB device number 21 using ehci-pci
[46381.462457] usb 2-1.1.4: New USB device found, idVendor=16c0, idProduct=05dc
[46381.462464] usb 2-1.1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[46381.462468] usb 2-1.1.4: Product: USBasp
[46381.462472] usb 2-1.1.4: Manufacturer: www.fischl.de

といった具合に製品名や製造者名が表示されるはずです。 もし何も表示されなかったり、エラーっぽい表示がされたらどこかが間違っています。 頑張ってデバッグしましょう。

avrdude してみる

USBasp に (USBasp 製作に用いたものではない) 別の AVR を接続します。

USBasp を直接ブレッドボードに挿し、別のマイコンに接続させます。マイコンの電源は USBasp から供給させています

そしてパソコンから avrdude を叩いて正常に応答するかどうか確認してみましょう。 ターゲットのクロックが遅い場合には -B オプションでビットクロックを指定してあげないといけないことに注意します。

$ sudo avrdude -c USBasp -p atmega88p -v -B4

avrdude: Version 5.11.1, compiled on Oct 30 2011 at 10:37:28
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "/etc/avrdude.conf"
         User configuration file is "/home/epii/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/parport0
         Using Programmer              : USBasp
         Setting bit clk period        : 4.0
         AVR Part                      : ATMEGA88P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no        512    4      0  3600  3600 0xff 0xff
           flash         65     6    64    0 yes      8192   64    128  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : usbasp
         Description     : USBasp, http://www.fischl.de/usbasp/

avrdude: set SCK frequency to 187500 Hz
avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e930f
avrdude: safemode: lfuse reads as 62
avrdude: safemode: hfuse reads as DF
avrdude: safemode: efuse reads as 1

avrdude: safemode: lfuse reads as 62
avrdude: safemode: hfuse reads as DF
avrdude: safemode: efuse reads as 1
avrdude: safemode: Fuses OK

avrdude done.  Thank you.

特にエラーが出ずに正常に終了すれば、動作確認は完了です。 これでどんなプログラムでも書き込めるはずです! (・ω<)

非root権限で使う (Linux)

「USBasp のアーカイブ内の『bin/linux-nonroot/99-USBasp.rules』を『/dev/udev/rules.d』以下にコピーすると sudo しなくても使えるよ!」 と書いてあるものの、こちらの環境 (Ubuntu) ではできなかった。 仕方ないのでしばらく sudo しながら avrdude してた。

ところがどうやらこのサイトによると、

/etc/udev/rules.d/99-USBasp.rules:

ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", MODE="0666"

などとするといけるらしい。 実際いけた。

AVR/USBasp (last edited 2013-09-10 14:11:52 by epii)