はじめに
Arduinoなどでよく使われているAVRマイコンにRaspberry PiのGPIOからプログラムを書き込む方法です。
AVRマイコンへの書き込みは専用の書き込み機を使用したり、Arduinoでライターをエミュレートしたりといった方法がありますが、Raspberry PiがあればGPIOから安価に書き込みを行うことが可能です。
書き込みソフトの準備
書き込みにはavrdudeを使用します。
Arduinoの開発環境でも使われているAVR開発ではメジャーなツールで、
パッケージでも配布されていますが、GPIOを使用するにはビルドが必要です。
環境
Raspberry Pi 3 model b+
Raspberry Pi 4 model bでも動作します。その他のSBCでも動作するかもしれません。
今回はdockerでubuntuコンテナをたてて作業しました。
avrdudeのビルド
avrdudeのビルドを行っていきます。
ほとんどのディストリビューションにgccなどの開発ツールがインストールされていますが、なければインストールしておきます。
# apt install build-essential autoconf wget
続いてflex bisonのインストール
# apt install flex bison
次にavrdudeのビルドですが、バージョンには注意が必要です。
現在最新のv6.3にはバグがあり、Raspberry PiでGPIOが利用できません。
ですので今回はv6.2を使用します。
公式リポジトリからダウンロードして展開
# wget http://download.savannah.gnu.org/releases/avrdude/avrdude-6.2.tar.gz
# tar -zxf avrdude-6.2.tar.gz
ビルドとインストール
configureに--lenable-linuxgpioオプションを渡すのを忘れずに
# cd avrdude-6.2
# ./configure --enable-linuxgpio
# make
# make install
avrdude.confにデバイスの定義を追加します。
以下のファイルを適当なエディタで編集します。
/usr/local/etc/avrdude.conf
エディタ上で"linuxgpio"を検索すると次のセクションが見つかるはずです。
#programmer
# id = "linuxgpio";
# desc = "Use the Linux sysfs interface to bitbang GPIO lines";
# type = "linuxgpio";
# reset = ?;
# sck = ?;
# mosi = ?;
# miso = ?;
#;
コメントアウトを外して適当なピンをアサインします。
programmer
id = "linuxgpio";
desc = "Use the Linux sysfs interface to bitbang GPIO lines";
type = "linuxgpio";
reset = 4;
sck = 16;
mosi = 20;
miso = 21;
;
avrdudeはGPIOで書き込みプロトコルをソフトウェアエミュレートで行います。いわゆるbit bangingです。
ですのでハードウェアリソースによらず空いてるピンなら何でも構いません。
次のコマンドでlinuxgpioが追加されていることを確認します。
# avrdude -c?
以上でavrdudeのセットアップは終了です。
書き込み
準備ができたらいよいよ書き込みを行っていきます。
プログラムを書き込むマイコンはatmega328pを想定していますが、ISP(SPI programming protocol)が使用できるAVRマイコンならほとんど対応しています。
ヒューズビット
atmega328pには豊富な動作モードが用意されており、ヒューズビットと呼ばれている特殊な領域に設定値を書き込むことでsystem clockなどの変更が行えます。
avrdudeはヒューズビットの書き込みにも対応しているのですが、設定を間違えるとISPでの書き込みが行えなくなったりするので、今回は初期値のままにしておきます。
書き込み回路
ヒューズビットが初期値の場合、clock sourceは内部RC発振8Mhzで分周が8なので1Mhz動作です。これは3.3vの給電でも動作に十分な電力を確保できますし、外部クリスタルも必要ないので先ほどアサインした各ピンをatmega328pのreset,clk,mosi,misoに接続して電源を接続するだけで動作します。
コンデンサを持っていればVCCとGNDの間にパスコンを挿したほうがいいかもしれません。
以下のコマンドで正常に接続できているか確認します。
# avrdude -c linuxgpio -p m328p
問題なければデバイスシグネチャとヒューズビットの値が取得できます。
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: safemode: Fuses OK (E:FF, H:D9, L:62)
avrdude done. Thank you.
以下のようなメッセージがでるようなら配線に間違いがあります。
電源を切り、配線を確認しましょう。
avrdude: AVR device not responding
avrdude: initialization failed, rc=-1
Double check connections and try again, or use -F to override
this check.
avrdude done. Thank you.
プログラムのビルド
ビルド作業とプログラムの詳説は省略します。
普通のLチカです。
Arduinoのプロジェクトをビルドするコマンドラインツールもあるようですが、私はavr-gccで直接コンパイルしています。
# apt install gcc-avr avr-libc
#define F_CPU 1000000
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
DDRB = DDRB | 0b00001111;
PORTB = PORTB | 0b00001111;
while(1) {
PORTB |= 0b00000001;
_delay_ms(1000);
PORTB &= 0b11111110;
_delay_ms(1000);
}
return 0;
}
# avr-gcc -Os -mmcu=atmega328p blink.c -o blink.out
# avr-objcopy -F ihex blink.out blink.hex
以下のhexファイルができます。
:100000000C9434000C943E000C943E000C943E0082
:100010000C943E000C943E000C943E000C943E0068
:100020000C943E000C943E000C943E000C943E0058
:100030000C943E000C943E000C943E000C943E0048
:100040000C943E000C943E000C943E000C943E0038
:100050000C943E000C943E000C943E000C943E0028
:100060000C943E000C943E0011241FBECFEFD8E04C
:10007000DEBFCDBF0E9440000C945B000C940000DA
:1000800084B18F6084B985B18F6085B9289A2FE3D8
:100090008DE093E0215080409040E1F700C00000E7
:1000A00028982FE38DE093E0215080409040E1F7C5
:0A00B00000C00000EBCFF894FFCF72
:00000001FF
アップロード
先ほどのhexファイルをavrdudeでatmega328pにアップロードします。
avrdudeはUオプションの後にメモリタイプ、操作、ファイル、フォーマットを:で区切って指定します。
フォーマットは指定しなくても自動で判別できます。
# avrdude -c linuxgpio -p m328p -U flash:w:blink.hex:i
特にエラーとかが出なければ書き込みは成功です。
以下のようにPB0からledを接続するとおよそ1秒おきに点滅するはずです。
以上でraspberry piからavrマイコンにファームをアップロードできるようになりました。
avr単体で使用する以外にもUSBのついてないarduino pro miniなどに書き込んだり、arduinoにブートローダーを書き込んだりも可能です。