Skip to content

USB_ATML_DFU

askn37 edited this page Oct 31, 2026 · 2 revisions

Atmel USB DFU Bootloader

この項の記述は、以下の参考文献からの、USB協会 : DFU規約 Revision 1.1 との相違点を表す、ベンダー固有実装の例。策定されたのは DFU規約 1.0 の時代である。

Microccip (Atmel) : USB DFU Bootloader Datasheet (doc7618.pdf) / PDF

  • 決定的な相違として、"DFU_DNLOAD" は固有コマンド送信にも使用され、イメージ書き込み時は "Write Command" + (任意個の)"Memory Image" + "DFU Suffix" という制御パケット列で編成されることにある。
    • つまり DFU 1.1 付録B の記載("DFU Suffix" 送信禁止)とは矛盾する。しかしながらこれは "16バイトの将来用の予約情報" であるとも説明されており、実際には装置側で無視する(中身は確認せずCRC32も計算しない)ように実装される。実のところ ブートローダー格納領域に制約のある legacy/classicAVR 系統以前では、CRC32 計算器をソフトウェア的に格納する余地が少ない事情もある。
  • legacyAVR/classicAVR 系統に属する 8製品で採用されており、Flash 末尾に製造時書込された状態で出荷される。これら以外の(Xmega系列の)製品は "Atmel USB FLIP DFU" ブートローダー規約が適合する。

Run-Time Descriptor Set

使用しない。"Run-Time" 動作から "DFU Mode" 動作への遷移は、Hard Reset でのみ行われる。このためジャンパーピン操作や、Hard Reset 2度押しが利用される。

DFU Mode Descriptor Set

Atmel DFU Mode Device Descriptor

Ofs Size Field Value Description
0 1 bLength 0x12 記述子全体長
1 1 bDescriptorType 0x01 DEVICE descriptor type.
2 2 bcdUSB 0x0100 USB版番号(BCD)
4 1 bDeviceClass 0xFE Application Specific Class Code.
5 1 bDeviceSubClass 0x01 Device Firmware Upgrade Code.
6 1 bDeviceProtocol 0x00 This device does not use the base protocol.
7 1 bMaxPacketSize0 0x20 エンドポイントEP0 のパケット最大長(32固定)
8 2 idVendor 0x03EB Vendor ID is "ATML" specific.
10 2 idProduct 0x2F** The Product ID is unique to each product model.
12 2 bcdDevice 0x0000 Device release number in binary coded decimal.
14 1 iManufacturer 0x00 An index of unused String Descriptors.
15 1 iProduct 0x00 An index of unused String Descriptors.
16 1 iSerialNumber 0x00 An index of unused String Descriptors.
17 1 bNumConfigurations 0x01 構成定義数(必ず 1)
  • 複合デバイスを構成しないので、bDeviceClassと bDeviceSubClassは、この時点で DFUクラスであることを表明している。
  • bMaxPacketSize0 は 32(0x20)値で固定。
  • idVendor は(Microchip製品になって以後も)"MCHP" ではなく "ATML" を表明する IDが使われている。
  • iManufacturer 他の 文字列記述子指標番号は、すべて 0(未使用)が指定される。

idProduct

legacyAVR/classicAVR 系統に属する 8製品で使用されるのが明記されている。これらでのブートローダー領域とその先頭実行アドレスは、FUSEビットで指定された容量で、Flash の最後尾に配置する。

Production Product ID Version Bootloader Address Size
AT90USB1287 0x2FFB 1.0.1 $F000 (Word) 4KiB (Word)
AT90USB1286 ↑ ↑ ↑ ↑
AT90USB647 0x2FF9 1.0.1 $7800 (Word) 2KiB (Word)
AT90USB646 ↑ 1.0.1 ↑ ↑
AT90USB162 0x2FFA 1.0.0/1/5 $1800 (Word) ↑
AT90USB82 0x2FF7 ↑ $0800 (Word) ↑
ATmega32U4 0x2FF4 1.0.0 $3800 (Word) ↑
ATmega16U4 0x2FF3 ↑ $1800 (Word) ↑
  • AT90USB162 と AT90USB82 は、出荷時期によって マイナーバージョン(と支援される機能)が 3種類ある。
  • ATmega8/16/32U2 等は、この表に記載がないことに注意。原書発行後に発売開始され、かつ改訂・更新がされていない。

Atmel DFU Mode Configuration Descriptor

"DFU 1.0/1.1" と相違なし。bNumInterfaces は必ず 1 を指定する。

Atmel DFU Mode Interface Descriptor

Ofs Size Field Value Description
0 1 bLength 0x09 記述子全体長
1 1 bDescriptorType 0x04 INTERFACE descriptor type.
2 1 bInterfaceNumber 0x00 このIFを特定する指標番号(必ず 0x00)
3 1 bAlternateSetting 0x00 代替IF番号
4 1 bNumEndpoints 0x00 このIFで使用されるエンドポイント数(なし)
5 1 bInterfaceClass 0xFE Application Specific Class Code.
6 1 bInterfaceSubClass 0x01 Device Firmware Upgrade Code.
7 1 bInterfaceProtocol 0x00 The device does not use a class specific protocol on this interface.
8 1 iInterface 0x00 An index of unused String Descriptors.
  • bInterfaceProtocol には 2("DFU Protocol")ではなく、0(未定義)を指定する。
  • この インターフェースは、"DFU Mode" で使用される唯一の インターフェースである。従って bInterfaceNumber は常に 0x00 である。
  • しかしながら、以下の記述("DFU Mode"全体)では インターフェース指標番号を示すべき wIndex には(存在しないはずの)4 を常に指定するかのように読める記述がされている。
  • 要求内の wValue 項が示す wBlockNum についての説明はどこにも記載がなく、これも不明瞭である。一応 DFU規約1.x どおりに記述すれば良いだろう。

Atmel DFU Mode Functional Descriptor (Not specified)

使用されない。従って "Run-Time Mode" と、wDetachTimeOut、wTransferSize、bcdDFUVersion に関係する機能は使用できない。

応用アプリケーションがこれを独自に実装することは、自由。

Summary of Frames from Host

Atmel DFU は、"DFU_DNLOAD" を介して 6バイトの、これから実行すべき固有定義コマンドを装置に送る。

Request from Host

Class-Specific Request bmRequestType bRequest wValue wIndex wLength Data
DFU_DNLOAD 0 01 00001 0x01 wBlockNum Interface (4) Length Firmware

Summary of Frames from Host

Command ID data[0] data[1] data[2] data[3] data[4] Description
(Byte Offset) 0 1 2 3 4 5
Prog_Start 0x01 0x00 start_address (MSB) ← (LSB) end_address (MSB) ← (LSB) Init FLASH programming
↑ ↑ 0x01 ↑ ↑ ↑ ↑ Init EEPROM programming
Display_Data 0x03 0x00 ↑ ↑ ↑ ↑ Display FLASH Data
↑ ↑ 0x01 ↑ ↑ ↑ ↑ Blank Check
↑ ↑ 0x02 ↑ ↑ ↑ ↑ Display EEPROM Data
Write_Command 0x04 0x00 0xFF - - - Full chip Erase (bits at FFh)
↑ ↑ 0x03 0x00 - - - Hardware reset
↑ ↑ ↑ 0x01 program address (MSB) ← (LSB) - LJMP address
Read_Command 0x05 0x00 0x00 - - - Read Bootloader Version
↑ ↑ ↑ 0x01 - - - Read Device boot ID1
↑ ↑ ↑ 0x02 - - - Read Device boot ID2
↑ ↑ 0x01 0x30 - - - Read Manufacturer Code (Signature 0)
↑ ↑ ↑ 0x31 - - - Read Family Code (Signature 1)
↑ ↑ ↑ 0x60 - - - Read Product Name (Signature 2)
↑ ↑ ↑ 0x61 - - - Read Product Revision
Change_Base_Address 0x06 0x03 0x00 "PP" (0x00) (0x00) Select “PP” 64 KiB flash page number
  • (文書中では言及されていないが、その用途が自明な)Change_Base_Address は、Prog_Start で示されるメモリアドレスが 64KiB 境界を越える時、その直前に発行されるはずだ。示される "PP" は、0x00 か、そうでないかだろう。この情報はグローバル値として保存され、以後変更されるまで、あるいは別のメモリセグメントが指示されるまで、内部的に保持しなければならない。
  • Write_Command の LJMPアドレスは、ワード粒度で示される。このため Flash 最大量は 128 KiB に制限されるが、この DFUローダー対象製品は 128 KiB までしか製造されていないので、問題ではない。

Programming the Flash or EEPROM Data

Write Command Sequence

Firmware イメージは、不揮発メモリページサイズ(メモリセグメントによって異なる)に合わせて分割される。さらに EP0パケットサイズ(32バイト固定長)に分割し、コマンド(6バイト)、本体、DFU Suffix(16バイト)の順に送信される。

SETUP と OUT はホスト側からの要求/指令、IN は 装置側からの応答。

  • SETUP - DFU_DNLOAD (see wLength)
  • OUT - Prog_Start (6 bute) + Padding (26 byte)
  • OUT - X offset padding (0 to 31 byte) + Firmware Packet 1 (1 to 32 byte)
  • OUT - Firmware Packet 2 (32 byte) ...
  • OUT - Firmware Packet N (0 to 31 byte) + DFU Suffix (1 to 16 byte)
  • (OUT - Continuing with DFU Suffix (1 to 15 byte) )
  • (OUT - ZLP)
  • IN - ZLP
  • SETUP - DFU_GETSTATUS
  • IN - Status Answers(OK、errWRITE、errPROG、etc)
  • (SETUP - DFU_CLRSTATUS)
  • (IN - ZLP)
  1. ホストは最初に DFU_DNLOAD で 6バイトの Prog_Start コマンドを発行し、メモリセグメント種別、start_address と end_address を通知する。
  2. start_address が 64 KiB 境界を越える場合、このシーケンスに先立って Change_Base_Address コマンドシーケンスが送信される。装置は与えられた "PP"をグローバル値として保持しておき、オフセットページ番号として解釈して、次回からの address に加算しなければならない。
  3. EP0パケットサイズは 32バイト固定長であるので、その境界に合わせるために Prog_Start コマンドには 26バイトのパディングが後置される。換言すれば、装置は十分な量のバッファメモリを有しているならば、受信パケットを一列に格納することができる。装置はこのパディングを読み飛ばし、メモリに書き込んではならない。パディングは 0x00 の羅列であるべきだが、必ずしもそうであるとは限らない。
  4. 最初の Firmware Packet は、不揮発メモリページ境界と(自ずとパケット境界とも)一致しない start_address(バイト粒度)が示された場合、必要な分量のダミーバイトが前置される。装置はこれを読み飛ばし、決してメモリに書き込んではならない。パディングは 0x00 または 0xFF の羅列であるべきだが、必ずしもそうであるとは限らない。
  5. 最後の Firmware Packet には、end_address の位置から パディングなしで "DFU Suffix" が後置する。装置はこれを棄却しなければならず、メモリに書き込んではならない。換言すれば、装置は常に wLength と end_address を意識する必要がある。両者が一致した位置が "DFU Suffix" の開始点だ。なお "DFU Suffix" は途中で次の(真の最終)パケットに分断されうる。
  6. Flash 書き込みイメージは ワード粒度なので、かならず偶数倍の長さを持っているはずである。start_address は常に偶数であるし、end_address(最終書き込み番地+1)も偶数のはずである。そうでなければ余分なダミーバイトを 前または後の該当位置に補完しなければならない。これは既にメモリ上にある既知のバイト値を読み取って適用するか、0xFFを適用する。(不揮発メモリは NANDロジックなので、0xFFは既知のデータを上書きしても破壊されない)
  7. 最終パケットは 32バイトに満たないこともあれば、32バイトちょうどの場合もありうる。そのためホストは 転送完了を示すために、パケット長の端数がない場合は ZLP を送信するかもしれない。
  8. 装置は最終パケットまでの全ての転送パケットを受け取ったら(そこまでの総バイト数と wLength との比較で判断して)ZLP で応答する。しかしこれは実際の 不揮発メモリページ 書き込み操作結果が判明するまで、保留するのがよい。(自ずから、装置側周辺機能の AutoZLP 送信設定は有効にすべきではない)
  9. ホストは 装置から ZLP を受け取ると(直ちに。あるいは然るべき待機時間経過後に)DFU_GETSTATUS で、書き込み操作結果を要求するだろう。

Reading the Flash or EEPROM Data

Firmware イメージは、不揮発メモリページサイズ(メモリセグメントによって異なる)に合わせて分割される。さらに EP0パケットサイズ(32バイト固定長)に分割して順に送信される。

Read Command Sequence

  • SETUP - DFU_DNLOAD (wLength == 6)
  • OUT - Display_Data (6 byte)
  • IN - ZLP
  • SETUP - DFU_UPLOAD (see wLength)
  • IN - Firmware Packet 1
  • IN - Firmware Packet 2...
  • IN - Firmware Packet N
  • OUT - ZLP
  • SETUP - GET_STATUS
  • IN - Status Answers(OK、err_VENDOR、etc)
  1. ホストは最初に DFU_DNLOAD 指令で 6バイトの Display_Data コマンドを発行し、メモリセグメント種別、start_address と end_address を通知する。装置はこれに対して ZLP で応答する。
  2. start_address が 64 KiB 境界を越える場合、このシーケンスに先立って Change_Base_Address コマンドシーケンスが送信される。装置は与えられた "PP"をグローバル値として保持しておき、オフセットページ番号として解釈して、次回からの address に加算しなければならない。
  3. 続いてホストは DFU_UPLOAD 要求を装置に求める。
  4. プログラミング時(ダウンロード)と異なり、アップロードでの start_address(読出開始アドレス)と end_address(最終アドレス+1) はバイト粒度で、メモリページ境界は意識しない。よってホストに送信すべき イメージデータ量 wLength は、end_address - start_address に必ず一致する。これを 32バイトパケットに細分化してホストに送信する。最終パケットが端数であっても、パディング調整は行わない。(USB周辺機能がマルチパケットに対応している品種だと、細分化作業は考えなくて良い)
  5. 装置は "LOCK" されたメモリを読むことはできないので、その場合は wLength 全量を返す前に ZLP で転送を中断することができる。
  6. ホストは受信データ量が、要求した wLength で満たされると、装置に対して ZLP を通知し、転送状態を終了する。

Answers from the Device to a Blank Check Command

Blank Check Command Sequence

  • SETUP - DFU_DNLOAD (wLength == 6)
  • OUT - Display_Data #Blank Check (6 byte)
  • IN - ZLP
  • SETUP - GET_STATUS
  • IN - Status Answers(OK、errCHECK_ERASED、etc)
  1. DFU_DNLOAD 要求による 6バイトの Display_Data コマンドが "Blank Check" 種別である場合、装置は 指定メモリ範囲が全て 0xFF で満たされていることを確認する。このメモリスキャン操作が終わるまで ZLP 応答は遅滞させるのが良い。
  2. ホストは続けて GET_STATUS 要求で、装置の動作結果を求める。期待される値は "OK"(0xFFで満ちている)または "errCHECK_ERASED" である。そうであれば装置は dfuIDLE 状態 を維持する。さもなければ dfuERROR 状態に遷移する。

Reading Configuration Information or Manufacturer Information

ホストは 構成情報または製造元情報 の読み取りを要求することができ、装置は 1バイトの 構成情報または製造元情報 を返すことができる。

Information Command Sequence

  • SETUP - DFU_DNLOAD (wLength == 2)
  • OUT - Read_Command (2 byte)
  • IN - ZLP
  • SETUP - DFU_UPLOAD (wLength == 1)
  • IN - Byte value Answers(1 byte)
  • SETUP - GET_STATUS
  • IN - Status Answers(OK、err_VENDOR、etc)
  1. DFU_DNLOAD 要求による Read_Command コマンドの長さは、2バイトである。
  2. 装置は "LOCK" されたメモリを読むことはできないので、その場合は wLength 全量を返す前に ZLP で転送を中断することができる。

Erasing the Flash

ホストは Write_Command で、Flash 全領域の消去を 装置に求めることができる。

Erasing Command Sequence

  • SETUP - DFU_DNLOAD (wLength == 3)
  • OUT - Write_Command #Full chip Erase (3 byte)
  • IN - ZLP
  • SETUP - GET_STATUS
  • IN - Status Answers(OK、errWRITE、etc)
  1. ブートローダー領域は、ふつうは消去対象に含まれない。それ以外の Flash 領域が消去対象であり、それが 0xFF で満たされたなら、装置は "OK" 状況を報告してよい。さもなければ "errWRITE" 状況("errERASE"ではない)を報告する。
  2. USB をセルフホスティングしてブートローダーを走行させている構造の装置は、自分自身に ネイティブなチップ消去 を行えないので "EEPROM"、"FUSE" ビット、"LOCK"ビットをクリアすることはできず、ホストもまたそれを期待してはならない。ブートローダーが物理的に別の MCU で動いている場合は ネイティブなチップ消去 を試行できるため、"errERASE" を報告しうる。

Starting the Application

ホストは Write_Command で、ブートローダーから直接、応用アプリケーションの起動を試みることができる。

DFU_ABORT 指令についての言及はないが、目的はほぼ同じである。

Starting Application Command Sequence

  • SETUP - DFU_DNLOAD (wLength == 3 or 5)
  • OUT - Write_Command #Hardware reset (3 byte) or #LJMP address (5 byte)
  • IN - ZLP
  • SETUP - DFU_DNLOAD (wLength == 0)
  • IN - ...(USB Detach)
  1. 装置はまず最初の DFU_DNLOAD で続く実行内容を指示する。装置は 2個目の(Data が空の)DFU_DNLOAD を受信したら、指示内容の実行を図る。
  2. 装置は "LJMP address" を指示されると、自身が使用した周辺機能を停止・無効化し(USBバスからも切り離し)、汎用アドレスやスタックも可能な限り再初期化したした上で、指定された応用アプリケーション開始アドレス(しかし普通は 0x0000 だろう)への LJMP を実行する。
  3. 装置は "Hardware reset" を指示されると、通常は Watch Dog Timer of Timeout Reset を試みる。外部 MCU で動作している場合は、対象 MCU に 真の Hardware Reset を行い、自身は不活性状態になる。(USBバスのアクセス権も 対象 MCU に委譲される)
  4. 重要:legacyAVR/classicAVR では、ひとたび起動した WDT は、Hard Reset 後も継続動作しつづけるのが一般的である。実行先のアプリケーションがそれを確実に無効化しない場合、WDT Reset が無限に再発生するだろう。(ブートローダー自身もまたそうである)

"Hard Reset" 2度押しで "DFU Mode" に入れる実装(ATmega 系列等)は、EEPROM領域に切り替えフラグを記録して見分ける仕組みになっている。(そしてそれが可能なのはだいたい、USB FLIP DFU 規約動作である)

Manifestation Phase

言及なし。従って "dfuMANIFEST" 状況は実装されていないと判断される。

Security

USBブートローダー接続が開始されると、自動的に(MCU 固有の "LOCK" ビット設定とは無関係に)メモリの読み書きを制限されたセキュリティ動作に入るのが望ましい。この場合許可される DFU コマンドは「フルチップ消去」だけであり、それに成功しない限り 他のメモリ読み書きコマンドは 失敗を返されるのが望まれうる。

まとめ

なんかすごく分かりづらい。原書の前半は DFU規約1.0(?)の複写なので、実際の DFUローダー実装では機能していないような部分が多い。

関連リンク

  • dfu-programmer / Github
    • arguments.c
      • Atmel 対応製品の DFU対応 Product ID リストを記載している。以下の原書で言及がない製品も多く含まれる。

Microchip

USB協会

LINKS

multix.jp/てくにかるむ(休眠中)
Multix Zinnia Product SDK [*AVR]
AVR.JP(日本語訳)
AVR-LIBC(日本語訳)

Clone this wiki locally