ATmega32U4について学んだこと
この記事はAtmel(現Microchip Technology)が販売するATmega32U4(以下m32u4)というMCU(Micro Control Unit)について最近学んだこと、遭遇した問題と、見つけたのであれば解決方法を、箇条書き的に記します。
m32u4は自作キーボードにおいて利用されることの多いPro MicroのMCUとしても知られています。自分がm32u4を取り扱うようになったのはまさにそれで、薄さや実装スペースへの欲求からPro Microではなくm32u4を直接使ってキーボードの回路を設計しようと思い立ったところから詳細を知ることになりました。
設計自体は比較的簡単
KiCadを少し齧ったことがあれば、以下のガイドに従うことで比較的容易にm32u4をMCUに使ったキーボードを設計できます。
自分はこのガイドを参考に疑似Pro Microともいうべき回路を設計し、それをブレッドボード上で組み立て、過去にデザインした自作キーボード実際に接続することで期待通りに機能することを確認できました。
QFP44のソケットに注意: 爪欠け
設計したものをいきなりPCBで組み立てるのはリスクがありますからブレッドボード上で組み立てたわけですが、その際にはm32u4のパッケージであるTQFP44(もしくはQFP44)はハンダ付けせずに使えたら助かります。ということで以下のQFP44のソケットと変換基板を利用しました。
自分が購入したソケットは受け取り時に4本中2本の爪が割れてしまってカバー(?)が止められない状態でした。ただこのソケットのカバーはチップの固定のためではなく、固定を解除するためのものだったので利用に支障はありませんでした。しかしやはり気持ち悪いのと不安定ではあったのでエポキシ接着剤を用いて折れた爪を修復するのと同時に無事な爪も補強しました。
QFP44のソケットに注意: ピン配列の違い
ブレッドボードを用いて疑似Pro Microを構成したり、ArduinoでISP(In System Programmer: 後述)を作ってブートローダを書き込んだりしているうちに、もう1台QFPソケット及び変換基板が欲しくなり、変換基板は前出のものをソケットは爪が折れなさそうな次の新商品を買いました。
しかしこの商品には前のソケットとはピン配列が違うという問題があり、購入した変換基板は使えませんでした。またこのソケットに対応した変換基板も販売されていないようでした。
そこで自分で変換基板のPCBをデザインし、発注しました。
この変換基板のPCBのデータはオープンソースとして公開しています。使ってみたい人は以下を参照してください。
出荷時にブートローダーが書き込まれていないことがある
型番ATmega32U4-AUとされるm32u4はデータシートによれば出荷時点でDFU機能のあるブートローダーが書き込み済みであるとされています。(33.2 ATmega32U4参照)
このブートローダーがあることでPro MicroをUSBケーブルにつないでリセットボタンを押すだけでファームウェアの書き換えができます。このお手軽さがm32u4が自作キーボードに採用された大きな理由のうちの1つだと考えられます。
話は変わって自分が最初に購入したATmega32U4-AUとされるm32u4はAliExpressからでした。それをブレッドボードで組み立てた疑似Pro Microに利用したところ、リセットボタンを押して(ショートさせて)もウンともスンとも言いませんでした。その時点では設計した回路や組み立てた回路に問題がある可能性もあり途方にくれたのです。以下はその時の作業の動画で途方に暮れ始めるあたりからです。
YouTubeのvideoIDが不正です
その後どこかで「AliExpressで購入したATmega32U4-AUにはブートローダーが書き込まれていないことがある」と読んだ記憶を思い出し、では「まず間違いなく書き込まれているだろうモノを売ってるところで買おう」と秋月電子でATmega32U4-AUを買ってきました。
秋月電子で購入したm32u4を疑似Pro Microに組み込んだところあっさりとDFUが認識され、自設計・自作キーボードのファームウェアも書き込みに成功し、実際のハードウェアに接続して正しく動作することの確認が取れました。
なおAliExperssで購入したm32u4は後にISP(In System Programmer: 後述)を用いてブートローダーを書き込むことができ、同じように正しく動作することが確認できました。ただデータシートに書かれていないような状態の製品が出荷されているのはどう解釈したら良いのかはわかりません。非正規品・デッドコピー品ではないことを祈るばかりです。
In System Programmer (ISP)とは
m32u4に限らずAVRマイコンについて調べていると遅かれ早かれIn System Programmer (以下ISP)と呼ばれる装置・仕組みに行き当たります。m32u4はファームウェアを書き込むのにUSBを利用できますが、それ以外の方法でも書き込めます。それこそがISPで、特にターゲットとなるデバイス=m32u4の間に6本の配線を接続するだけでいろいろな操作が可能になります。正確にはターゲット側には水晶発振子など多少の周辺回路が要るようなのですが、まだちゃんと調べていないので最低限何が必要なのかは理解していません。
ISPとして使える製品は市販されていますが、実はArduinoを使えば簡単にISPが作れます。自分はArduino Leonardを買ってきて、Arduino Examples内の11.ArduinoISPスケッチをビルド&インストールしてISPとしました。(のちにLeonardをPro Microで置き換えました)
これを使って前出のAliExpressで購入したm32u4にブートローダーやファームウェアを書き込みました。ISPとしての接続方法は特に以下のサイトを参考にしました。
avrdudeの古い(?)情報の罠
こうして作ったArduinoISPはavrdudeというプログラムを用いてPCから利用することになります。自分はQMK Firmwareをセットアップする際にインストールされたmingw64版のavrdude 6.3を使いました。
ArduinoISPとavrdudeの使い方については以下のページがとても参考になります。
しかし6-3-3. -cオプション の次の記述が大きな罠となりました。
ArduinoISPは、AVR ISP互換ですので、
-c avrispと指定しなければいけない
実際に指定すべきだったのは-c arduinoでした。avrdudeのアップデートに伴いISPの種類としてarduinoが増えたようです。
結果的にまず最初に実行すべきコマンドはこうなりました。なおCOM11は各自の環境で異なってきます。
$ avrdude -c arduino -P COM11 -b 19200 -p atmega32u4 -U lock:r:-:h
その実行結果はたとえば次のようなります。
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.01s
avrdude.exe: Device signature = 0x1e9587 (probably m32u4)
avrdude.exe: reading lock memory:
Reading | ################################################## | 100% 0.01s
avrdude.exe: writing output file "<stdout>"
0x3f
avrdude.exe: safemode: Fuses OK (E:FB, H:D8, L:FF)
avrdude.exe done. Thank you.
この結果ではm32u8が持つ1バイトのロックビットと3バイトのフューズ(いずれも後述)の情報が得られています。
デフォルトブートローダーの書き込み
ISPを使うことでまっさらなm32u4にもブートローダーを書き込めるようになりました。m32u4のデフォルトブートローダーは次のページのDocumentsタブの最下部にあるmegaAVR DFU USB Bootloadersからダウンロードできます。
https://www.microchip.com/wwwproducts/en/ATmega32U4 m32u4の各種資料
ダウンロードしたZIP書庫ファイル内のATMega32U4-usbdevice_dfu-1_0_0.hexが目的のm32u4のデフォルトブートローダーです。これを次のようにavrdudeを使ってArduinio ISPでm32u4に書き込みます。なお同じ方法でPro Microなどすでにブートローダーやファームが書かれたm32u4のブートローダーをDFUに更新することもできます。
$ avrdude -c arduino -P COM11 -b 19200 -p atmega32u4 -U flash:w:ATMega32U4-usbdevice_dfu-1_0_0.hex:i
# 出荷時のフューズバイトを設定
$ avrdude -c arduino -P COM11 -b 19200 -p atmega32u4 -U lfuse:w:0x5e:m -U hfuse:w:0x99:m -U efuse:w:0xf3:m
各種ブートローダーとその設定のコツ
DFUブートローダーについては前述しましたが、その他にもキーボード(≒Pro Micro)用途で利用されるブートローダーが複数あります。その中でも自分が動作確認をできた3つのブートローダーについて以下に示します。
DFUブートローダー
通常のm32u4出荷時に書き込まれているブートローダーです。QMKのBOOTLOADERに設定すべき値はatmel-dfuになります。リセットボタンを1回押すだけでファームウェア書き込みモードになります。
出荷時のフューズバイトはE:F3, H:99, L:5Eで、avrdudeのオプションでは-U lfuse:w:0x5e:m -U hfuse:w:0x99:m -U efuse:w:0xf3:mです。しかし16MHzで駆動させキーボード用に利用する際はE:F3, H:D9, L:FFくらいが好ましく、こちらはavrdudeのオプションでは-U lfuse:w:0xff:m -U hfuse:w:0xd9:m -U efuse:w:0xf3:mです。
入手にはhttps://www.microchip.com/wwwproducts/en/ATmega32U4よりDocumentsタブの最下にあるmegaAVR DFU USB BootloadersからZIPファイルをダウンロードし中のATMega32U4-usbdevice_dfu-1_0_0.hexを解凍します。
書き込み手順の想定コマンドは以下の通りです。ポートはCOM11になっているので適宜書き換えてください。フューズビットは出荷時のものではなく自分がキーボードのファームウェアで利用している設定です。
$ avrdude -c arduino -P COM11 -p atmega32u4 -U flash:w:ATMega32U4-usbdevice_dfu-1_0_0.hex:i
$ avrdude -c arduino -P COM11 -p atmega32u4 -U lfuse:w:0xff:m -U hfuse:w:0xd9:m -U efuse:w:0xf3:m
$ avrdude -c arduino -P COM11 -p atmega32u4 -U lock:r:-:h
Sparkfun製Caterinaブートローダー
Sparkfun純正のPro Micro (5V/16MHz)に書かれているブートローダーです。QMKのBOOTLOADERに設定すべき値はcaterinaです。ファームウェア書き込みモードにするためにはリセットボタンを素早く2回押す必要があります。
出荷時のフューズバイトはE:FB, H:D8, L:FFで、avrdudeのオプションでは-U lfuse:w:0xff:m -U hfuse:w:0xd8:m -U efuse:w:0xfb:mです。
入手はhttps://github.com/sparkfun/Arduino_Boards/tree/master/sparkfun/avr/bootloaders/caterinaよりCaterina-promicro16.hexをダウンロードしてください。
書き込み手順の想定コマンドは以下の通りです。ポートはCOM11になっているので適宜書き換えてください。
$ avrdude -c arduino -P COM11 -p atmega32u4 -U flash:w:Caterina-promicro16.hex:i
$ avrdude -c arduino -P COM11 -p atmega32u4 -U lfuse:w:0xff:m -U hfuse:w:0xd8:m -U efuse:w:0xfb:m
$ avrdude -c arduino -P COM11 -p atmega32u4 -U lock:r:-:h
Arduino Leonardo用Caterinaブートローダー
中華製Pro Micro互換機に書かれていることの多いブートローダーです。QMKのBOOTLOADERに設定すべき値はcaterinaです。リセットボタンを1回押すだけでファームウェア書き込みモードになります。
出荷時のフューズバイトはE:FB, H:D8, L:FFで、avrdudeのオプションでは-U lfuse:w:0xff:m -U hfuse:w:0xd8:m -U efuse:w:0xfb:mです。
入手はhttps://github.com/arduino/ArduinoCore-avr/tree/master/bootloaders/caterinaよりCaterina-Leonardo.hexをダウンロードしてください。-32u4のFlash全体である32KBのサイズのイメージなので、ほかのブートローダーに比べて書き込みに時間がかかります。
書き込み手順の想定コマンドは以下の通りです。ポートはCOM11になっているので適宜書き換えてください。
$ avrdude -c arduino -P COM11 -p atmega32u4 -U flash:w:Caterina-Leonardo.hex:i
$ avrdude -c arduino -P COM11 -p atmega32u4 -U lfuse:w:0xff:m -U hfuse:w:0xd8:m -U efuse:w:0xfb:m
$ avrdude -c arduino -P COM11 -p atmega32u4 -U lock:r:-:h
avrdudeの-Uオプション
avrdudeの-Uオプションはm32u4などターゲットデバイスのメモリ=記憶領域全般を操作するためのもので、少々特殊です。このオプションに指定する文字列には次のようなフォーマットが適用されます。
-U {対象メモリ}:{操作}:{パラメーター}:{フォーマット}
つまり「対象メモリを操作する。その際のパラメーターは指定されたフォーマットで解釈する」となります。
対象メモリはm32u4ではeeprom, flash, lfuse, hfuse, efuse, lock, calibration, signatureのいずれかです。
操作は書き込みのw、読み込みのr、検証のvのいずれかです。
パラメーターは入出力するファイルだったり、一部の対象メモリについては16進数のリテラル文字列であったりできます。またネット上でよく見かけるサンプルでは-U lock:r:con:hのようになっていますがこのconはWindowsのコンソールを指定する特殊ファイルCONのことで、より一般的には-を用いて標準入出力を指定して-U lock:r:-:hとするほうが良いでしょう。
フォーマットにはi, s, r, e, m, a, d, h, o, bなどが利用できますが、.hexファイルを読み書きする際のi (Intel Hexフォーマット)、フューズなどの値を読む時のh(16進数), o(8進数), b(2進数)、それにフューズなどに書き込む時のm(即値)くらいを覚えておくとよいでしょう。
以上がわかれば本文章に登場している-Uの利用例もその意味が読み解けます。以下には幾つかに解説を添えて示しています。
-
-U lock:r:-:h
ロックビット(lock)を読み込み(r)標準出力(-)に16進数で出力(i)=表示する -
-U flash:w:ATMega32U4-usbdevice_dfu-1_0_0.hex:i
Flashメモリ(flash)にIntel Hexフォーマット(i)のファイルATMega32U4-usbdevice_dfu-1_0_0.hexを書き込む(w)
-Uは複数記述できるため例えば以下のよう複数のフューズとFlashメモリを一度に書いたりもできます。
$ avrdude -c arduino -P COM11 -b 19200 -p atmega32u4 \
-U lfuse:w:0xFF:m \
-U hfuse:w:0xD8:m \
-U efuse:w:0xFB:m \
-Uflash:w:ATMega32U4-usbdevice_dfu-1_0_0.hex:i
avrdudeのその他の主要オプション
これまで特に説明しないまま使ってきた主要なオプション: -c, -P, -b, -pを説明します。
-cにはISPの種類を指定します。本文章で使ってるArduino ISPではarduinoです。使っているISPの種類で変わるほか、avrdudeのバージョンによっても変わったことがあるようです。
-PにはISPと通信するためのシリアルポートを指定します。WindowsであればCOM11のようにCOM{番号}を、Linuxやmacであれば/dev/ディレクトリ下のシリアルデバイスを指定することになります。ただ目的のシリアルポートがどのような番号、名前になるかは完全に環境依存です。接続するたびに確認するようにしてください。
-bにはISPとの通信速度を指定します。指定しなくてもRS-232接続のデフォルトの通信速度で動くようで、おそらく安全…もしくは速度のために19200を指定していると推測されます。
-pにはターゲットとなるデバイスの種類を指定します。本記事はm32u4だけを対象にしていますからatmega32u4固定です。
efuseに指定した値が書き込めないことがある
ここまでのフューズバイトの書き換えにおいて指定した通りの値が書き込めない場合があります。具体的にいうとbit5およびbit4が常に0になるケースがありました。もっと即物的に言うと0xffを書き込もうとした際には0xcfになってしまいます。そのため書き換え後のverifyフェーズにおいて指定とは異なった値が読み取られ、そこでプロンプトが表示されて処理が中断されました。
m32u4のデータシートによればbit5およびbit4には現在は機能が割り当てられてないため特に動作に支障はありませんが、どうにも気持ち悪いために調べてみたところavrdudeの設定が原因でした。
avrdudeの設定はavrdude.confファイルに記載され、デフォルトでは実行ファイルと同じディレクトリに配置されています。MSYS2においては{MSYS2のインストールディレクトリ}/mingw64/bin/avrdude.confになります。このファイルのATmega32u4のpartセクション内のmemory "efuse"サブセクションをみると以下の記述が見つかりました。
write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0",
"x x x x x x x x x x x x i i i i";
この2行目の最後の2つのxをiに書き換えて以下のように変更することで、この問題は解消され指定した通りのefuseが書き込めるようになりました。
write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0",
"x x x x x x x x x x i i i i i i";
この設定はefuseの書き換え時にISPがm32u4どんなビット列を送信するかを指定していると考えられます。iはユーザーが入力したデータを示します。一方でxは無視することを示していますが、実際には0を送信しているのでしょう。m32u4はbit5およびbit4に指定された値で動作を変えることはないはずですが、なぜか値としては記憶するらしくverifyのために呼び出すとxで書いた0がそのまま出てくると考えられます。
参考資料:
終わりに
以上、散文的でしたがATmega32U4を取り扱う際に気が付いたことを記述しました。あまりまとまっていないので公開するべきか考えてるうちに、実際に公開するまでにかなり間が開いています。しかし自分の興味がRP2040に移ったこともあり、これ以上増えることもないだろうというのと「公開しないのももったいないよね」ということで公開に至りました。
どなかのお役にたてば幸いです。
Discussion