本記事では Atmel STK500 スターターキットを改造し、 HVSP/PP や ISP だけではなく、 TPI や PDI でもプログラムできるようにします。
注意: GoPro や Genlock は本ブログでよく話題にされていますが、この記事は全くそれらと関係ありません。
イントロダクション
Atmel STK500 は2001年に発売されて以来、現在まで使われている寿命の長い製品です。ただし、今日ではほとんどのユーザが STK500 を単にプログラマとして用いていると思われ、DIP パッケージのマイクロコントローラを試すためのスターターキットとしては用いていないのではないかと思います。
STK500のボード上には2つのマイクロコントローラ ATmega8535L (主)、ATtiny2313V (従) が搭載されており、次の特徴があります:
HVPP (High Voltage Parallel Programming) プログラマ
HVSP (High Voltage Serial Programming) プログラマ
ISP (In-System Programming) プログラマ
本稿で述べる改造では、主マイクロコントローラの ATmega8535L をフラッシュメモリの容量が大きい 、ピン互換のマイクロコントローラに換装し、従マイクロコントローラの ATtiny2313V は除去します。後者の改造が可能なのは、Atmel が2009年以降は現在に至るまで主マイクロコントローラ用の新しいファームウェアを提供しておらず、従マイクロコントローラの唯一の役割であるところの主マイクロコントローラのファームウェアを更新するという機能はもはや不要であるとみなされるからです。STK500 のボードにメモリ容量の大きなマイクロコントローラが載ってしまえば、オープンソースのファームウェア、たとえばMatthias Neeracherさんが作ったScratchMonkey (Orangkucing Labでそれを改良しました )が動かせて、しかも TPI や PDIプログラマの機能も追加できます。
ハードウェアの改造
純正のSTK500から次の4つの部品を除去します:
U200 : ATtiny2313V
U202 : ATmega8535L
C200 : 47n のコンデンサ
R200 : 10k の抵抗
オレンジ色の部品を除去。赤色の部品を追加。
(上図は Atmel の公式ページの “STK500 component placement: STK500_asm.pdf” からとりました。部品番号は同様に公式回路図 “Atmel STK500 schematic: STK500.pdf” に合わせてあります。)
上記の部品を除去した後のボードは次の写真のようになります:
STK500から4つの部品を除去
そして次の部品を実装します:
U202 : ATmega1284P
R213 : 0 オームのジャンパ (はんだで橋をかけてしまっても可です)
J200 : 2×3 ヘッダーピン
新しく実装するマイクロコントローラはATmega8535とピン互換ならなんでも大丈夫です。具体的には ATmega16/32/64/128 や ATmega164/324/644/1284 ファミリーから選んでください。この稿では、もったいないくらい高機能な ATmega1284P を使いましたが、表面実装のマイクロコントローラの細かいはんだ付けで将来、何度も外したり付けたりを繰り返したくないと思ったからです。
これらの部品をはんだ付けし終わったら、STK500 のハードウェアの改造は完成です。改造後の写真が次です:
STK500 改造後の基板。(1) と記されたシールはJ200 ISP6コネクタの1ピンの目印です
ソフトウェア
U202に実装した主マイクロコントローラにファームウェアを焼くには、別のISPプログラマが必要です。本稿では、どうやってファームウェアを焼くかとか、そもそもISPプログラマとは何かとかについては説明しません。そういうことに関してはたぶん、この記事の読者のほうが筆者よりも詳しいと思われます。:)
ですから、別のISPプログラマを新しくJ200に実装したISP6ピンヘッダに接続し、ここ からダウンロードしたファームウェアを焼くだけです。 (このリンク先は ScratchMonkey を筆者がフォークしたブランチです。近い将来、トランクにマージされることを期待しているところです。)
ソースコードからコンパイルしたいという方は、Arduino IDE に DIP-40 コア(”Mighty Core”)が必要です。ここ に書いてある説明にしたがってインストールしてください。”Mighty Core” がインストールできたら、IDE のTools メニューで board: “Mighty Core”->あなたのマイクロコントローラー, clock: “External 7.3728MHz”, pinout: “Standard pinout” を選び、ソースコードをコンパイルしてできた hex ファイルをあなたのマイクロコントローラーに焼いてください。
参考のために書いておくと、マイクロコントローラのヒューズは次のように設定して動作しています:
CKDIV8/CKOUT unprogrammed
SPIEN programmed
SUT_CKSEL = FSOSC_16KCK_65MS_XOSC_SLOWPWR
さて、STK500 改造基板は今や Atmel Studio 4/5/6/7 や avrdude (ISPの場合は stk500v2、HVPPの場合は stk500pp、HVSPの場合は stk500spを指定して) に純正の Atmel STK500 として認識されるはずです。
その上、今やこの改造基板は TPI や PDI のプログラマにもなっているのです。このことの詳細は次章以降で述べます。
STK500 改造基板を TPI/PDI プログラマとして使う — そのソフトウェア
残念ながら Atmel Studio は STK500 改造基板を TPI/PDI プログラマとしては認識しません。TPI/PDIプログラマとして使いたいときには、avrdudeのソースコードにパッチを当てて、STK500 改造基板はいつも avrdude から使うという風にしないといけません。
avrdude へのパッチは8個の部分からなります:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*** stk500v2.c.orig Mon Jan 18 00:16:55 2016
--- avrdude/stk500v2.c Wed Nov 18 17:03:41 2015
***************
*** 1254,1263 ****
{
if ((PDATA(pgm)->pgmtype == PGMTYPE_STK600 ||
PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII ||
PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII) != 0
&& (p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_TPI)) != 0) {
--- 1255,1263 ----
{
if ((PDATA(pgm)->pgmtype == PGMTYPE_STK600 ||
+ PDATA(pgm)->pgmtype == PGMTYPE_STK500 ||
PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII ||
PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII) != 0
&& (p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_TPI)) != 0) {
***************
*** 3712,3719 ****
{
unsigned char buf[16];
unsigned int eepagesize = 42;
unsigned int nvm_base;
! AVRMEM *mem = NULL;
int use_tpi;
use_tpi = (p->flags & AVRPART_HAS_TPI) != 0;
--- 3677,3686 ----
{
unsigned char buf[16];
unsigned int eepagesize = 42;
+ unsigned int flashpagesize = 256;
unsigned int nvm_base;
! AVRMEM *eepmem = NULL;
! AVRMEM *flashmem = NULL;
int use_tpi;
use_tpi = (p->flags & AVRPART_HAS_TPI) != 0;
***************
*** 3724,3736 ****
progname);
return -1;
}
! if ((mem = avr_locate_mem(p, "eeprom")) != NULL) {
! if (mem->page_size == 0) {
avrdude_message(MSG_INFO, "%s: stk600_xprog_program_enable(): no EEPROM page_size parameter for PDI device\n",
progname);
return -1;
}
! eepagesize = mem->page_size;
}
}
--- 3691,3711 ----
progname);
return -1;
}
! if ((eepmem = avr_locate_mem(p, "eeprom")) != NULL) {
! if (eepmem->page_size == 0) {
avrdude_message(MSG_INFO, "%s: stk600_xprog_program_enable(): no EEPROM page_size parameter for PDI device\n",
progname);
return -1;
}
! eepagesize = eepmem->page_size;
! }
! if ((flashmem = avr_locate_mem(p, "flash")) != NULL) {
! if (flashmem->page_size == 0) {
! avrdude_message(MSG_INFO, "%s: stk600_xprog_program_enable(): no flash page_size parameter for PDI device\n",
! progname);
! return -1;
! }
! flashpagesize = flashmem->page_size;
}
}
***************
*** 3795,3801 ****
return -1;
}
! if (mem != NULL) {
buf[0] = XPRG_CMD_SET_PARAM;
buf[1] = XPRG_PARAM_EEPPAGESIZE;
buf[2] = eepagesize >> 8;
--- 3770,3776 ----
return -1;
}
! if (eepmem != NULL) {
buf[0] = XPRG_CMD_SET_PARAM;
buf[1] = XPRG_PARAM_EEPPAGESIZE;
buf[2] = eepagesize >> 8;
***************
*** 3806,3811 ****
--- 3781,3797 ----
return -1;
}
}
+ if (flashmem != NULL) {
+ buf[0] = XPRG_CMD_SET_PARAM;
+ buf[1] = 5; /* this should be defined in stk500v2_private.h as XPRG_PARAM_FLASHPAGESIZE */
+ buf[2] = flashpagesize >> 8;
+ buf[3] = flashpagesize;
+ if (stk600_xprog_command(pgm, buf, 4, 2) < 0) {
+ avrdude_message(MSG_INFO, "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_FLASHPAGESIZE) failed\n",
+ progname);
+ return -1;
+ }
+ }
}
return 0;
***************
*** 4071,4076 ****
--- 4056,4062 ----
size_t writesize;
unsigned long use_ext_addr = 0;
unsigned char writemode;
+ int need_erase = 0;
/*
* The XPROG read command supports at most 256 bytes in one
***************
*** 4115,4120 ****
--- 4101,4112 ----
} else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
memtype = XPRG_MEM_TYPE_FUSE;
writemode = (1 << XPRG_MEM_WRITE_WRITE);
+ if (p->flags & AVRPART_HAS_TPI)
+ /*
+ * TPI devices need a mystic erase prior to writing their
+ * fuses.
+ */
+ need_erase = 1;
} else if (strncmp(mem->desc, "lock", strlen("lock")) == 0) {
memtype = XPRG_MEM_TYPE_LOCKBITS;
writemode = (1 << XPRG_MEM_WRITE_WRITE);
***************
*** 4143,4148 ****
--- 4135,4153 ----
return -1;
}
+ if (need_erase) {
+ b[0] = XPRG_CMD_ERASE;
+ b[1] = XPRG_ERASE_CONFIG;
+ b[2] = mem->offset >> 24;
+ b[3] = mem->offset >> 16;
+ b[4] = mem->offset >> 8;
+ b[5] = mem->offset + 1;
+ if (stk600_xprog_command(pgm, b, 6, 2) < 0) {
+ avrdude_message(MSG_INFO, "%s: stk600_xprog_chip_erase(): XPRG_CMD_ERASE(XPRG_ERASE_CONFIG) failed\n",
+ progname);
+ return -1;
+ }
+ }
while (n_bytes != 0) {
if (dynamic_memtype)
avrdude はいろいろな版がいろいろな形で配布されているため、ここに示したパッチは参考程度です。あなたがお持ちのavrdude のソースコードに
patch コマンドを動かして自動的に適用できるわけではなく、stk500v2.c というファイルの該当する箇所を見ながらあなたの手でパッチを当てる必要があるはずです。
(2021/8/16 追記: こちら に mariusgreuel さんの avrdude v6.3.1.1 を fork してパッチを当てたものを用意しました。Windows 用のバイナリも Releases に置いてあります。)
(2025/2/4 追記: avrdude が GitHub に移り、頻繁にアップデートされるようになりました。こちらに公式 avrdudes さんのを fork してパッチ を当てたもの を用意しました。)
パッチの第1の部分(1254,1263) は PGMTYPE_STK500
でも XPROG (TPI と PDI)を呼び出すようにします。
第2の部分 (3712,3719) と第3の部分 (3724,3736) では flash や eeprom の容量を計算し、第4の部分 (3795,3801) と第5の部分 (3806,3811) は計算した容量を STK500改造基板に申告するための変更です。
パッチの残りの部分は TPI のヒューズをプログラムする際に “書き込み前の神秘的な消去” が必要なための変更です。
STK500 改造基板を TPI/PDI プログラマとして使う — その接続
パッチ済みのavrdudeが用意できたので TPI/PDI のマイクロコントローラがプログラムできるようになりました。
TPI のマイクロコントローラをプログラムするには 510 オームの抵抗が外付けで2個必要です。次の回路図のように接続してください:
5V、MOSI、MISO、SCK、GND は J200 ISP6 コネクタにあります。VTARGET は基板上で “VTG” と印刷されているどのピンにも出ています (“VTARGET” ジャンパはセットしてください)。RESET5V は “PROG DATA” の5ピン、RESET12V は “ISP6PIN” または “ISP10PIN” に出ています。リセット無効化ヒューズがプログラムされていない時(リセットが有効の時)は、上の回路図で TPI と記されたコネクタの信号を使ってください。 リセット無効化ヒューズがプログラムされている時(リセットが無効の時)は、高電圧TPIはターゲットの電源電圧を制御する必要がありますので、上の回路図でTPI HV と記されたコネクタの信号を使ってください。
PDI のマイクロコントローラをプログラムするには、510オームの抵抗が外付けで2個必要なだけでなく、4回路入りの5V入力トレラントなトライステートバッファ 74LVX125 が1個必要になります。 次の回路図で示す接続を使ってください:
3V3 は “VADJ” または “EXPAND0” コネクタの13ピンに出ています (“AREF” ジャンパはセットしてください)。MOSI、 MISO、SCK、 GND は J200 または “ISP6PIN” または “ISP10PIN” に出ています。MOSI_GATE は “ISP6PIN” や “ISP10PIN” の RESET ピンに出ています。
付記: PDI プログラミングは 3.3Vロジックです。STK500 は 5V ロジックですので、何らかのロジックレベル変換が不可避です。自動レベル変換のチップが世の中にいろいろありますが、筆者がMAX3002、GTL2003、TXB0104、FXMA108 を実際に使ってみたところ、このうちの一つたりともまともに動きませんでした。74LVX125のようなトライステートバッファを使わざるを得ないのは残念なことです。まったく、 Atmel の PDI ってなんてナイーブで馬鹿げたプロトコルなんだろうか!!
この稿を終わるにあたり、avrdude の起動時の引数の例をいくつか挙げておきます:
avrdude -c stk500v2 -p t10 -P /dev/tty.usbXXXXX -vvvv # 詳細な通信ログと tiny10 のシグニチャを表示する
avrdude -c stk500v2 -p x128a1 -P /dev/tty.usbXXXXX -U flash:w:hehehe.hex:i # hehehe.hex を xmega128a1 の flash メモリに書き込む
ただし、例で tty.usbXXXXX は STK500 改造基板が繋がっているシリアルポートを表しています。
楽しんでね!