👨‍🏭

ArduinoのATmega328pをVS CodeのPlatformIOでデバッグ実行する

2021/09/23に公開

Arduino UNO、Pro Mini、Nanoには、マイコンATmega328pが使われていますが、debugwireという規格に対応し、デバッグ実行が可能です。
debugwireを使用するには本来の高価な機器が必要になりますが、Digispark ATtiny85という1,000円以下で買えるマイコンボードをdebugwireとして使う、dwire-debugを使うことでATmega328pをデバッグすることが可能です。

こちらの記事を参考にしましたが、Arduinoへの理解が足りておらず、ハマった点が多かったので、デバッグ実行までの手順を紹介します。
https://hackaday.io/project/162302-debugging-arduino-uno-in-vscode

ただし、Arduino UNO R3へのデバッグには私自身は成功しておりません。Arduino Pro Miniで成功しました。また、FUSEを書き換えることで、高電圧プログラマがないと書き換え不能な状態に陥ることもあります。リスクを考慮した上で取り組む必要があります。
Arduino UNOにおいては、以下の記事のように配線に加工を行う必要があるようです。
http://easylabo.com/2015/02/atmel/6924/

この記事での説明はすべて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の設定を誤ると再起不能になる場合がありますので、注意ください。

http://avr8-burn-o-mat.aaabbb.de/

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のイメージは以下からダウンロード可能です。

https://github.com/micronucleus/micronucleus/blob/master/firmware/releases/t85_default.hex

ここでダウンロードしたt85_default.hexを書き込むには以下のコマンドを実行します。

avrdude -p attiny85 -c avrisp -P /dev/ttyUSB0 -b 19200 -U ./t85_default.hex

これでISPの役割は終わりです。

次にこのmicronucleus bootloaderを使ってdwire-debugのイメージを書き込みます。

書き込みに必要なmicronucleusのcliツールは以下からダウンロードしてください。

https://github.com/micronucleus/micronucleus/releases/tag/master-LATEST

dwire-debugのイメージは以下からダウンロードしてください。

https://github.com/dcwbrown/dwire-debug/blob/master/usbtiny/main.hex

そして、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の場合、コマンドは以下からダウンロード可能です。

https://github.com/DeqingSun/dwire-debug/releases/

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の設定は以下となります。

platformio.ini
[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に関する設定を追加します。

platformio.ini
[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