ArduinoのATmega328pをVS CodeのPlatformIOでデバッグ実行する
Arduino UNO、Pro Mini、Nanoには、マイコンATmega328pが使われていますが、debugwireという規格に対応し、デバッグ実行が可能です。
debugwireを使用するには本来の高価な機器が必要になりますが、Digispark ATtiny85という1,000円以下で買えるマイコンボードをdebugwireとして使う、dwire-debugを使うことでATmega328pをデバッグすることが可能です。
こちらの記事を参考にしましたが、Arduinoへの理解が足りておらず、ハマった点が多かったので、デバッグ実行までの手順を紹介します。
ただし、Arduino UNO R3へのデバッグには私自身は成功しておりません。Arduino Pro Miniで成功しました。また、FUSEを書き換えることで、高電圧プログラマがないと書き換え不能な状態に陥ることもあります。リスクを考慮した上で取り組む必要があります。
Arduino UNOにおいては、以下の記事のように配線に加工を行う必要があるようです。
この記事での説明はすべてLinux(Ubuntu)で記載しますが、主にUSBポートの指定(/dev/ttyUSB0)を目的のOSのものに置き換えてください。
準備するもの
ハードウェア
- Digispark ATtiny85
- Arduino Pro Mini
ソフトウェア
以下のソフトウェアはインストール済みであるとします。
- VS Code
- VS Codeの拡張機能 "PlatformIO"
- PlatformIOでのArduino UNOの開発の準備
- avr-gdb
- avrdude
avr-gdbとavrdudeはUbuntuであれば以下でインストール可能です。
sudo apt install -y gdb-avr avrdude
Digispark ATtiny85に micronucleus bootloader を書き込む
Digispark ATtiny85にdwire-debugをプログラムするために、micronucleus bootloaderを書き込む必要があります。
bootloaderを書き込むにはISP(In System Programmer)が必要です。USBaspを購入することでISPとして使うことができますが、Arduino UNOがある場合、Arduino UNOをISPとして使うことが可能です。
まず、Arduino UNOをISPにするためには、Arduino IDEを開き、メニュー"File"->"Example"->"ArduinoISP"を開き、このスケッチをArduino UNOに Upload します。
Arduino UNO と Digispark ATtiny85 を以下の様につなぎます。
ICSP | Arduino UNO | Digispark ATtiny85 |
---|---|---|
RESET | 10 | P5 |
SPI MOSI | 11 | P0 |
SPI MISO | 12 | P1 |
SPI SCK | 13 | P2 |
5V | 5V | VCC |
GND | GND | GND |
avrdudeコマンドで、指定するprgrammerの名前(-c
で指定)はavrisp
になります。
まず、Digispark ATtiny85のFUSEがどのような設定になっているかを確認します。Digispark ATtiny85のFUSEの値が、FE DD C1
である必要があります(厳密にはSELFPRGEN
の値が1であること)。
avrdude -p attiny85 -c avrisp -P /dev/ttyUSB0 -b 19200
avrdude: safemode: Fuses OK (E:FE, H:DD, L:C1)
FUSEの設定には、avrdudeコマンドで設定可能な他、AVR8 burn-o-matというツールを使うと、GUIで設定が可能です。
ただしFUSEの設定を誤ると再起不能になる場合がありますので、注意ください。
avrdude -p attiny85 -c avrisp -P /dev/ttyUSB0 -b 19200-U lfuse:w:0xEF:m -U hfuse:w:0xDD:m -U efuse:w:0xC1:m
Digispartk ATtiny85用のmicronucleus bootloaderのイメージは以下からダウンロード可能です。
ここでダウンロードしたt85_default.hexを書き込むには以下のコマンドを実行します。
avrdude -p attiny85 -c avrisp -P /dev/ttyUSB0 -b 19200 -U ./t85_default.hex
これでISPの役割は終わりです。
次にこのmicronucleus bootloaderを使ってdwire-debugのイメージを書き込みます。
書き込みに必要なmicronucleusのcliツールは以下からダウンロードしてください。
dwire-debugのイメージは以下からダウンロードしてください。
そして、micronucleus bootloader経由で書き込むには以下のコマンドを実行します。
micronucleus --run main.hex
> Please plug in the device ...
と表示されたら、Digispark ATtiny85をPCに接続します(これがmicronucleusの書き込み方です)。
書き込みに成功した場合、差し込んだ直後は Bus 001 Device 007: ID 16d0:0753 MCS Digistump DigiSpark
と認識していますが、その6秒後 Bus 001 Device 031: ID 1781:0c9f Multiple Vendors USBtiny
に変われば成功です。Ubuntuでればlsusb
コマンドで確認することができます。
最後に、FUSEでRESETを無効化する設定(RSTDISBL=1)を行います。この設定を行うと、一般的なISPでは書き込めない状態になりますので、上記が成功していることを確認した上で実施してください。
avrdude -p attiny85 -c avrisp -P /dev/ttyUSB0 -b 19200-U lfuse:w:0xEF:m -U hfuse:w:0x5D:m -U efuse:w:0xC1:m
このDigispark ATtiny85はこれで、ISPのUSBtinyとしても使用可能になります。
dwire-debugのコマンドdwire-debugを準備する
MacOS、Windowsの場合、コマンドは以下からダウンロード可能です。
Ubuntuの場合は、別途ビルドする必要があります。
git clone https://github.com/DeqingSun/dwire-debug
cd dwire-debug
make
Arduino UNO,Pro MiniをDigispark ATtiny85接続する
以下のように配線します。
ICSP | Digispark ATtiny85 | Arduino UNO | Arduino Pro Mini |
---|---|---|---|
RESET | P5 | ICSP RST | RST |
SPI MOSI | P0 | ICSP MOSI | 11 |
SPI MISO | P1 | ICSP MISO | 12 |
SPI SCK | P2 | ICSP SCK | 13 |
Arduino UNOにおいては、ICSPは以下のようなピン配置になっています
|MISO|VCC|
|CLK|MOSI|
|RST|GND|
正しく接続されている場合、以下のコマンドで現在のFUSEの値を取得可能です。
avrdude -patmega328p -cusbtiny
FUSEでdebugwireを有効化する
FUSEでDWEN=1を設定し、debugwireを有効化します。Arduino UNOでは前に紹介した記事の通り、更に加工をしなければ、使用することはできません(筆者は、試しにFUSEを設定して、UNO 3個使えなくなりました)。
avrdude -patmega328p -cusbtiny -U lfuse:w:0xFF:m -U hfuse:w:0xDA:m -U efuse:w:0xFD:m
dwire-debugが動作するか確認する
dwdebugコマンドを実行し、ATmega328Pを認識することを確認します。
dwdebug device usbtiny1
Connected to ATmega328P on UsbTiny1 at 125000 baud.
確認後は一旦Ctrl-Cで中断します。
また、一度dwdebugを起動するとデバッグのモードで起動し、avrdudeコマンドやUploadが受け付けなくなりますが、その時は一度dwdebugでコマンドqiを実行してデバッグを終了させます。
dwdebug device usbtiny1
Connected to ATmega328P on UsbTiny1 at 125000 baud.
0040: 940c jmp $00000c > qi
PlatformIOでUSBTiny経由でプログラムを書き込む
PlatformIOのインストールと、プロジェクトの構築方法は省略します。
USBTinyで書き込むPlatformIOの設定は以下となります。
[env:uno]
platform = atmelavr
board = uno
framework = arduino
upload_protocol = usbtiny
build_type = debug
どうもPlatformIOのUploadボタンで機能しない場合があり、その場合、avrdudeコマンドで以下のように書き込んでいました。
avrdude -patmega328p -cusbtiny -U .pio/build/uno/firmware.hex
dwire-debugを動作させる
dwdebug コマンドで、gdbからの接続を受け入れる状態になるように、以下のコマンドを実行します。
dwdebug device usbtiny1, gdbserver, qr
Connected to ATmega328P on UsbTiny1 at 125000 baud.
Info : avrchip: hardware has something
Target ready, waiting for GDB connection.
Use 'target remote :4444'
PlatformIOでavr-gdbを用いてデバッグを開始する
PlatformIOの設定にdebugに関する設定を追加します。
[env:uno]
platform = atmelavr
board = uno
framework = arduino
upload_protocol = usbtiny
build_type = debug
debug_tool = custom
debug_server = /usr/bin/avr-gdb
debug_init_cmds =
set remoteaddresssize 32
target remote localhost:4444
ブレークポイントを設定し、停止すればデバッグ実行が可能です。
FUSEをもとに戻す
デバッグが終わった後は、FUSEをdebugwireが有効になっている状態から元にもとします。
avrdude -patmega328p -cusbtiny -U lfuse:w:0xEF:m -U hfuse:w:0xDD:m -U efuse:w:0xC1:m
確認できたこと
あまり、良いデバッグ体験は得られませんでした。
- ブレークポイントの設定は、一度プログラムを停止させてから行う必要がありました。
- ブレークポイントで停止した時、変数の値を参照することができました。
- ステップ実行(次の行に進む、関数の終わりまで実行する)は機能せず、それぞれブレークポイントを設定する必要がありました。
- 全体的にすごく動作が重くなり、元のような動作の上でステップ実行を可能にする感じではありませんでした。
所感
RaspberryPI PicoとESP32の法が開発体験が良い(デバッグ実行もできる)ので、私自身はあまり活用することはなさそうです。
Discussion