[Atmel-ICE on Linux] Debianからavrdudeを使ってブレッドボード上でAtmega328pのプログラムを書き込む


2021/03/09

前回は新品のAtmega328pマイコンにArduinoIDEからブートローダーを書き込んで、更にArduinoの基板に載せ替えて使うことでArduino用のプログラムを書き込みました。

Arduinoでマイコン開発に慣れてきたら、やはりブートローダーを毎回書き込んでから、さらにArduino用のプログラムを書き込む...という手順は面倒になりますし、製品の量産には向きません。

また簡単にチェックするためだけで、毎度毎度マイコンを剥がしていてはいつかボード表面をピンセットで滑っちゃって大切な部品を損傷させる危険性もあります。

ということで今回は新品のAtmega328pを題材に、Debian Linux & Atmel-ICEでavrdudeを使ったプログラムをブレッドボード上で書き込みする手順を特集します。


準備 ~ ハード編

まずは今回の作業でつかう材料に関してメモをしておきます。

Atmega328p(AVRマイコン)のプログラム書き込みに必要なもの

まず今回の作業ではMicrochip(旧Atmel)製品でAVRマイコンのライターが最低でも必要になります。

どのようなAVRマイコンでも安定して書き込めるように、また何かあったらヒューズビットも書き込みできるように、以下のように
ISP MkIIのような製品を少し高価でも一つ持っておくと良いと思います。

著者の場合はAVRだけでなくSAMも使いたいので、正規品のAtmel-ICEを使っていますが、ロイヤリティもありこちらはかなり高めです。セールスで出ているのを狙って買うか、以下のようなサードパーティ製の互換品を購入することもできます。

ちなみに付属品のJTAGケーブルのアクセサリーは失くすと、色んなプログラミングモードでピンの番号の対応を確認しなくてはならないという地味に辛い作業をしなくてはならないので、大切にしまっておきましょう。

次に今回プログラムの書き込み使う素材ですが、

            + ATMEGA328Pマイコン(※未使用もしくは初期化された状態のもの)
+ ブレッドボード
+ 5V供給用のUSBアダプター
+ 抵抗 10kΩ
        
となっています。

書き込み前のピン配線

次に書き込み前の準備の中で、もっとも重要な項目である、Atmel-ICEとマイコンとの配線接続に関して話です。

Atmega328pをSPI(ISP)モードでAtmel-ICE上のavrdudeから使うためには以下のような配線の模式図になります。

合同会社タコスキングダム|蛸壺の中の工作室

ここでの注意点として、JTAGの10ピンケーブルの向きを良く観察すると、このケーブルがストレートですので、両端のピンヘッダのアサインメントが異なります。

合同会社タコスキングダム|蛸壺の中の工作室

参考先:RoHS2(改正RoHS) 2×5(10P)両端コネクタ付IDCリボンケーブル(フラットケーブル ハーフピッチ).pdf)

つまり、同じような見た目でも、Atmel-ICE側に付けるヘッダ(上の図では右側)と、マイコン側に付けるヘッダ(上の図では左側)には区別があります。

ケーブル逆に取り付けた場合には正しく動作しませんので、取付方向は良く確認しましょう。


準備 ~ ソフト編

次にソフトウェア周りの内容を説明していきます。

Linux(Debian)にavrdudeをインストール

LinuxでAtmel-ICEなどの専用デバッガーからマイコンに書き込みを行う際には、avrdudeというプログラムを使います。ちなみにこれはArduino IDEのコアプログラムにも採用されている実績のあるアプリケーションです。

            $ sudo apt-get install binutils-avr gcc-avr avr-libc avrdude
        
現在ではLinuxの主要なパッケージマネージャからインストールすることができるようになっています。Debianだと、aptで簡単にインストールできるようになっています。

USBドライバをインストール

LinuxでAtmel-ICEを使うためにもっとも苦労するのが、LinuxカーネルにUSBデバイスマネージャを正しく設定する作業です。

USBドライバのインストールはLinuxの各ディストリビューションごとに作法が違いますので、ここではDebian系OSのドライバ構築手順のみを説明させていただきます。

まずは追加のUSBドライバのライブラリの
libusb-devlibusb-1.0-0-devを以下のようにインストールしてみます。

            $ sudo apt-get install libusb-dev
#👇ドライバ・ライブラリが追加されていることを確認
$ dpkg -L libusb-dev | grep /usr/include
/usr/include
/usr/include/usb.h

$ sudo apt-get install libusb-1.0-0-dev
#👇ドライバ・ライブラリが追加されていることを確認
$ dpkg -L libusb-1.0-0-dev | grep /usr/include
/usr/include
/usr/include/libusb-1.0
/usr/include/libusb-1.0/libusb.h
        
なお、この辺に言及されていますが、Windows/Mac/Linuxの各OSごとにUSBドライバのインストール方法が違います。

            Windows:
    Atmel-ICEをUSB接続すると自動でUSBドライバがロードされる
Mac:
    インストールは不要
Linux:
    99-platformio-udev.rulesというudevルールを設定する必要あり。
    もし過去に入れている場合には、最新のドライバにするためにアップデート推薦
        
WindowsやMacOSで試す分には、USBドライバのことをさほどシビアに考慮する必要も無いのですが、LinuxだけはUSBドライバをインストールしないと、Atmel-ICE側を正しく認識してくれない仕様になっています。

なお、udevルールの解説はここでは省きますが、詳しく知りたい方は
udevルールに関する技術記事などを参照ください。

Atmel-ICEはCMSIS-DAP準拠デバッグアダプタですので、たとえば
こちらの導入手順に書いてあるようなudevルールをシステムに追加します。

            $ curl -fsSL https://raw.githubusercontent.com/platformio/platformio-core/master/scripts/99-platformio-udev.rules \
    | sudo tee /etc/udev/rules.d/99-platformio-udev.rules
$ ls /etc/udev/rules.d/
#👇ルールが追加されている
... 99-platformio-udev.rules ...
$ sudo service udev restart
        
もしくはこちらのarduino用のudev詰め合わせプロジェクトでは、バージョン11以降においてCMSIS-DAPも追加されているようなので、以下のコマンドでドライバ定義を導入することも可能です。

            $ curl -L -O https://raw.githubusercontent.com/artynet/arduino-linux-setup/master/arduino-linux-setup-12.sh

$ chmod +x arduino-linux-setup-12.sh
$ ./arduino-linux-setup-12.sh <your_username>
        

ターゲットデバイス名&書き込み装置名の確認

それでは、パソコンとAtmel-ICEを接続して、avrdudeの動作確認を行います。

まずはAVRマイコンを設定するときに割り当てる名前を探します。

            $ avrdude -p ?

Valid parts are:
  uc3a0512 = AT32UC3A0512
  c128     = AT90CAN128
  c32      = AT90CAN32
#...
  m328p    = ATmega328P
#...
  x8e5     = ATxmega8E5
  ucr2     = deprecated, use 'uc3a0512'
        
これでATmega328Pマイコンはm328pという表記で利用できることが分かります。

また書き込み装置も同じように探せます。

            $ avrdude -c ?

Valid programmers are:
  2232HIO          = FT2232H based generic programmer
#...
  atmelice         = Atmel-ICE (ARM/AVR) in JTAG mode
  atmelice_dw      = Atmel-ICE (ARM/AVR) in debugWIRE mode
  atmelice_isp     = Atmel-ICE (ARM/AVR) in ISP mode
  atmelice_pdi     = Atmel-ICE (ARM/AVR) in PDI mode
  atmelice_updi    = Atmel-ICE (ARM/AVR) in UPDI mode
#...
  xplainedpro_updi = Atmel AVR XplainedPro in UPDI mode
        
Atmel-ICE用の書き込みモードがいくつかありますが、ここではatmelice_ispモードを使って書き込みを行います。

SPI(ISP)設定のピン配置

上記の配線図では説明をスキップしていましたが、SPIモードによるAVRマイコンへの書き込みでは、以下のようなピンアサインメントが対応しています。

Atmel ICEのマニュアルのTable3-6にも記述してありますが、

AVR用 10ピンヘッダ(Atmel-ICE側)

マイコンへの接続先

Pin 1 (TCK)

SCK

Pin 2 (GND)

GND

Pin 3 (TDO)

MISO

Pin 4 (VTG)

VTG

Pin 6 (nSRST)

/RESET

Pin 9 (TDI)

MOSI

となっていますので、書き込み前には配線をもう一度確認しましょう。

マイコンへの接続テスト

とりあえずAtmel-ICEが正しくマイコン側へ繋がっているかをテストするためにメモリ情報を出力します。

            $ sudo avrdude -c atmelice_isp -P usb -p m328p -v
avrdude: Version 6.3-20171130
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/etc/avrdude.conf"
         User configuration file is "/root/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : usb
         Using Programmer              : atmelice_isp
avrdude: Found CMSIS-DAP compliant device, using EDBG protocol
         AVR Part                      : ATmega328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : JTAG3_ISP
         Description     : Atmel-ICE (ARM/AVR) in ISP mode
         Vtarget         : 5.0 V
         SCK period      : 8.00 us

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: safemode: lfuse reads as 62
avrdude: safemode: hfuse reads as D9
avrdude: safemode: efuse reads as FF

avrdude: safemode: lfuse reads as 62
avrdude: safemode: hfuse reads as D9
avrdude: safemode: efuse reads as FF
avrdude: safemode: Fuses OK (E:FF, H:D9, L:62)

avrdude done.  Thank you.
        
はじめての接続ではなにやらズラズラと設定値が出てきますが、通信が成功しているということのようです。

またもし、Atmel Iceのボード上に青いLEDが点灯せずに通信エラーなどが出ていたらJTAGケーブルなどのピン配線に間違いがないかを確認しましょう。

特に注意が必要なのは、一度利用履歴のあるAtmega328pは既にROMにブートローダーが書き込まれているので、そのままではAtmel-ICEを使った通信が以下のようなエラーを吐いて上手くいきません。

            $ sudo avrdude -c atmelice_isp -P usb -p m328p -v

avrdude: Version 6.3-20171130
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/etc/avrdude.conf"
         User configuration file is "/root/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : usb
         Using Programmer              : atmelice_isp
avrdude: usbhid_open(): No response from device
avrdude: usbdev_open(): Found Atmel-ICE CMSIS-DAP, serno: J41800091527
avrdude: Found CMSIS-DAP compliant device, using EDBG protocol
avrdude: jtag3_edbg_prepare(): failed to read from serial port (-1)
avrdude: failed to sync with the JTAGICE3 in ISP mode

avrdude done. Thank you.
        
つまりは元Arduino Unoだったマイコンには既にブートローダーなどが仕込まれているため、再度書き込みたい場合には一度マイコンの初期化を行う必要があることも注意が必要です。

Atmel-ICEとマイコンの通信が正常に構築されているようであれば、いよいよ以降でプログラムの書き込み作業に進みます。


簡単なプログラムの書き込み

まずはこちらで紹介してある簡単なソースコードを参考にプログラムを作成します。

以下はAtmega328PのPORTBのピン全部を一斉にチカチカさせるコードになります。

            #ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz clock speed
#endif

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    DDRB = 0xFF; //Makes PORTB an Output.
    while(1) {
        PORTB = 0xFF; //Turns ON All LEDs
        _delay_ms(1000); //1 second delay
        PORTB= 0x00; //Turns OFF All LEDs
        _delay_ms(1000); //1 second delay
    }
}
        
このソースコードをsample_program.cとしてプロジェクトの保存しておきます。その保存したフォルダで以下のようにコンパイルしてみます。

            #👇コンパイル
$ avr-gcc -Wall -g -Os -mmcu=atmega328p ./sample_program.c -o ./sample_program.out
$ ls
sample_program.c  sample_program.out

#👇実行ファイルのサイズをチェック
$ avr-size -C ./sample_program.out
AVR Memory Usage
----------------
Device: Unknown

Program:     178 bytes
(.text + .data + .bootloader)

Data:          0 bytes
(.data + .bss + .noinit)

#👇hexファイルに書き込み形式を変更
$ avr-objcopy -j .text -j .data -O ihex ./sample_program.out ./sample_program.hex
$ ls
sample_program.c  sample_program.hex  sample_program.out
        
これで書き込み用のhexが作成できました。

ではこれを早速書き込んでみましょう。

            $ sudo avrdude -c atmelice_isp -P usb -p m328p -U flash:w:sample_program.hex:i
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "sample_program.hex"
avrdude: writing flash (178 bytes):

Writing | ################################################## | 100% 0.05s

avrdude: 178 bytes of flash written
avrdude: verifying flash memory against sample_program.hex:
avrdude: load data flash data from input file sample_program.hex:
avrdude: input file sample_program.hex contains 178 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.07s

avrdude: verifying ...
avrdude: 178 bytes of flash verified

avrdude: safemode: Fuses OK (E:FF, H:D9, L:62)

avrdude done.  Thank you.
        
とすると、PORTBのどのポートからでも1秒感覚でチカチカさせるプログラムが作成できました。

余談 ~ avrdudeのフューズの書き換え方

debugWIREモードによる書き込み時には、デフォルトのSPIモードからヒューズ値を変更する必要があります。

debugWIREでの書き込み方法はこの記事では詳しくは解説しませんが、RESETとVTGとGNDの3線だけで書き込みが出来るシンプルな配線構成でプログラムが書き込めるのがdebugWIREのメリットです。

まずはSPIモードに戻せるように現在のフューズ値を控えておきます。

            Ext:0xFF
High:0xD9
Low:0x62
        
debugWIREモードにするフューズの組み合わせは、マイコンの取説を読み込む必要があります。なおヒューズビットの計算を算出してくれるツールを公開されている方もいますので、ヒューズ値をカスタマイズする必要がある場合には参考になります。

今回はAtmega328pに限ると、最低限DWENを1に設定する必要があるので、例えば元の
0xD9からでは0x99にhfuseを変えたい場合のコマンドは、

            $ sudo avrdude -c atmelice_dw -P usb -p m328p -U hfuse:w:0x99:m -v
        
というようにします。

書き込みたいフューズ値を間違えて、一度SPIモードに戻したいときには、

            $ sudo avrdude -c atmelice_isp -P usb -p m328p -U hfuse:w:0xd9:m -U lfuse:w:0x62:m -U efuse:w:0xff:m -v
        
などとすると良いでしょう。

なおdebugWIREを使う際の注意点としては、間違ったフューズビットを送ってしまった場合、設定を間違ったマイコンと通信が不能になってしまう恐れがあります。

もしメーカー純正のHVPPに対応したデバッガーではない自作の書き込み装置でこのフューズビットを元の状態にレスキューする場合には、色々と策を絞る必要があります。

参考: Fuse BytesをミスったATmegaの救出劇

参考: AVRのヒューズをリセットしよう!(ATMegaxx8専用)

debugWIREは配線がシンプルで便利な分、それ相応のリスクがあるのを覚悟の上で利用してください。

...君子危うきに近寄らず、純正ライターを持っていないのなら、debugWIREは使わないのが賢明と言えるでしょう。


Lチカで動作確認

では正常にプログラムが書き込めいるかを、適当なPORTBのポートのどこかにLEDを使って確認してみます。

確認方法とは言っても、LEDを適当に配線したら、5V電源をマイコン側に供給するだけです。

合同会社タコスキングダム|蛸壺の中の工作室

書き込みが成功していると上の画像のようにLチカしていることが見て取れます。Windowsではだいたい上手く行くのですが、Linuxからでもavrdudeが機能して、プログラムが書き込めているなんて!感動もひとしおでした😋


まとめ

以上、今回はAtmel-ICEを利用したLinuxからのAVRマイコンにプログラムを書き込む手順を丁寧に解説したつもりです。

Linuxで専用の書き込み装置をつかってプログラムをマイコンに転送する最大のポイントとしては、
USBドライバを正常にインストールすることに尽きると思います。

もし書き込みに失敗している場合には、まずLinuxカーネルのUSBデバイスの設定をきちんと見直すなど、それなりに手探りで不足しているライブラリなどを探したり、干渉しているドライバ周りのファイルを良く読み込んでみたりなどしてみてください。


参考サイト

FT232RL USBシリアル変換モジュールで書き込み|ATMEGA328PをArduinoとして使う

簡単なソースコードサンプル集|tasmanianfox/compilation_of_c_program.sh