第 2 回 開発環境

本日の内容


このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。

2-1. Arduino 開発環境

Arduino IDE

Arduino の標準的な開発環境は、公式サイトからダウンロードできる Arduino IDE です。 Windows 用はインストーラーをダウンロードしてインストールしてください。 Windowsストアからインストールすると、インストール結果でコマンドのパスなどが変わってしまいます。

サンプルプログラムの実行

  1. Arduino Uno を接続する
  2. Arduino IDE を起動する
  3. 「ファイル→スケッチ例→01 Basics→Blink」を選ぶと、 Blink という ウィンドウが開く
  4. 「ツール→ボード」で Arduino/Genuino Uno を選ぶ
  5. 「ツール→シリアルポート」で表示されている適切な表示(COM3 Arduino/Genuino Uno)を選ぶ
  6. 「→」ボタン(「マイコンボードに書き込む」という表示が出る)を押 す

Atmel Studio7

検証は(ver. 7.0.1931)で行っています。 ディレクトリパスの表示など、バージョンで異なるかもしれません。

Atmerl Studio では C 言語とアセンブリ言語開発ができます。 本講義ではC言語の開発は専らArduino IDEで行うので、 Atmel Studio はア センブリ言語の開発のみで使用します。

プログラムの作成

  1. Atmel Studio を起動し、New→project を選択し、Assembler を選択し、保 存フォルダとプロジェクト名を記入します。

  2. マイコンの名前を入力します。 atmega328p を選ぶか入力して下さい。
  3. 開発画面になります。
  4. プログラム入力エリアの上に2つの入力欄がある場合、
    1. 「Select the micro-controller application」とメッセージが出 る入力欄は Arduino.org を選びます(バージョンは一番新しいもの を)
    2. 「Select the micro-controller hardware/board」というメッセー ジが出る入力欄は Arduino/Genuino Uno を選びます。
  5. プログラムを入力します。 上記の選択が効くのか、デバイス宣言やインクルードファイルの指定は不要で、 C:Program Files (x86)\Atmel\Studio\7.0\packs\atmel\ATmega_DFP\1.2.209\avrasm\inc で定義されているマクロ、名前などが使用できるようです。
  6. プロジェクトを Build します。

プログラムの書き込み

  1. Arduino をコンピュータに接続します
  2. Windows ではデバイスマネージャー、MacOSX では ls /dev/tty.*などで、Arduino のデバイス識別子を調べます。
  3. Windows Power Shell, cmd.exe, Terminal など、コマンドの入力できる 画面で、プログラムを作成したフォルダに行き、さらに、Debug というフォ ルダに入ります。 「プロジェクト名.hex」というファイルがあることを確認します。
  4. 下記のprogram.batプログラムをフォルダに置きます。
  5. .\program.bat COM3 flashuno.hex./program.bat /dev/tty.usb1234 flashuno.hexなどとするとプログラムがArduino に書き込めます。

program.bat(Windows 用)

以下のプログラムを program.bat というテキストファイルに収めます。

SET dude="C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe"
set conf="C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf"
rem %dude%  -C %conf% -p atmega328p -cstk500v1 -P %1 -b 57600 -D -U flash:w:%2%:i
%dude%  -C %conf% -p m328p -c arduino -P %1  -D -U flash:w:"%2":i

flashuno


/*
 * flashuno.asm
 *
 *  Created: 2018/09/15 15:39:43
 *   Author: sakamoto
 */ 

.cseg
.org	0x0000
	rjmp	reset
.org	INT_VECTORS_SIZE
reset:
        ldi     r16,high(RAMEND)
        out     SPH,r16 
	ldi	r16,low(RAMEND)
	out	SPL,r16
	ldi	r16,1<<pb5
	out	ddrb, r16

.equ	time = 10
main:
	sbi	portb,pb5
	rcall	wait
	cbi	portb,pb5
	rcall	wait
	rjmp	main

.def	wreg0 = r20
.def	wreg1 = r21
.def	wreg2 = r22
wait:
	ldi	wreg0,time
wait0:
	ldi	wreg1,0
wait1:
	ldi	wreg2,0
wait2:
	nop
	dec	wreg2
	brne	wait2
	dec	wreg1
	brne	wait1
	dec	wreg0
	brne	wait0
	ret
.exit

2-2. Arduino のアーキテクチャ

Wiring システムは、マイコン開発を容易に行うために開発された教育用の 教材でした (Arduinoの語られざる歴史 by Hernando Barragán)。 Java で開発されたIDEはパソコンのOSを選ばずに使用できます。 また、マイコンのプログラムはC/C++言語で記述します。 プログラムのコンパイル、書き込みがワンアクションでできます。

Arduino のハードウェアは Creative Commons Attribution-ShareAlike  2.5 宣言されてます。 但し、派生製品に対して Arduino の名前を使うことを 禁じています。 ソフトウェアは GPL v2 宣言されていて、条件を守れば自由に改変などができます。

Arduino Uno のドキュメントは 公式サイト にあります。 また、 ピン配置 も図示されていますが、より見やすい図が色々デザインされていますの で、気に入ったドキュメントを探してください。

基板上でメインに使用するのは ATmega328Pというマイコンです。 このマイコンは内部クロックも利用できますが、外部クロックとして16MHz の水晶発振器が接続されています。 多くの I/O ポートがそのまま外部端子に繋がれています。 また、PortB5 には LED が接続されています。 Digital 0,1 が通信用ポートとして使用されます。

基板にはUSBポートが搭載され、USB通信を実現するために、もう一つ AVR のマイコン が載っています。 さらに、USBポートからの5V電源に対して、レギュレータ回路により 3.3Vの 電源も供給されています。

マイコンにはブートローダーというプログラムが書き込まれていて、これによ り、パソコンからのプログラムの書き込みと、プログラムの実行を行います。

C/C++言語で開発を行うとき、様々な関数、変数などが 定義されています

setup(), loop()
Arduino のプログラムは、はじめに setup() が一回だけ呼び出され、 その後loop 関数が常に繰り返される。 そのため、 setup には初期設定を書き、loop には毎回実行されることを 書く。 loop で状態を保持したい場合は、 static で宣言した変数を使う。 但し、loop 内で無限ループを作ったり、 setup で無限ループを作っても、 読みづらいだけで、特にトラブルにはならないはず。
pinMode() ,digitalRead(),digitalWrite(), LED_BUILTIN, HIGH, LOW
ディジタルピンに対して、 pinMode はピンの状態を設定する、 OUTPUT(出力)、INPUT(入力)、 INPUT_PULLUP(プルアップ付きの入力)の3状態あり、ピン番号で指定する。 なお、アナログポートとして指定されているピンも A0, A1 などが定義さ れているため、ディジタルピンとして使用できる。 LED_BUILTIN は内蔵LEDのピン番号を指す。 ピンへの出力は、 HIGH, LOW で指定するが、これは C++ の bool 型のよ うなので true, false でも指定できると思う。

pinmode(LED_BUILTIN,OUTPUT);
digitalWrite(LED_BUILTIN,HIGH);    
delay(), millis(), delayMicroseconds(), micros()
delay は待ち時間をmsで指定する。millis ミリ単位の時刻を取得する。 delayMicroseconds, micros はそのマイクロセコンド版
volatile
変数がプログラムの流れとは異なる条件で変化するなど、コンパイラが最 適化などで変数へのアクセスの仕方を変更することを防ぎたい場合がある。 このため、変数の取扱いにおいて最適化などをしないように指定するのが volatile 宣言である。 下記のプログラムにおいて、 volatile 宣言をしないと、コンパイラは for ループを無駄なループだと思い、削除してしまう。
void wait(void){
    volatile int i;
    for(i=0;i<35000;i++){
    }
}

2-3. ATmega 328Pのアーキテクチャ

ATmega 328P は Microchip 社のマイクロコントローラです(かつては Atmel 社の製品でしたが、会社が買収されました)。 データシートは Microchip 社から入手できますが、有志により日本語訳さ れたものも別サイトで公開されています。 本講義では、解説などには公式ドキュメントである英文を使用しますが、理解 の助けとして日本語訳を使用するのは問題ありません。 但し、日本語訳は公式ではありませんので、状況に応じて公式ドキュメントを 確認する必要があります。

ATmega 328Pの特徴はデータシートの表紙にまとめられています。 豊富な機能がありますが、本講義では基本的な機能しか使いません。 メモリーマップがシンプルで、スタックが実装されているため、 C 言語と 親和性が高いです。

ハーバードアーキテクチャ

我々が普段使っている Windows を使うパソコンでは、メモリは単一のもので、 プログラムとデータが共存しています。これを(フォン)ノイマン型コンピュー タと呼んでいます。 一方、ATmega328P では、データシートの p.13 Figure 4-1 にあるように、 Program Flash と SRAM に明確な区分があり、共存していません。これを ハーバードアーキテクチャと言います (由来のハーバードマークI は世界初の汎用(リレー式)計算機(1944))。 プログラムとデータの扱い方が違うので、プログラムをメモリ上で扱う OS や コンパイラなどの実装は難しいという欠点はあります。 しかし ATmega328P の用途から考えると OS やコンパイラを使うことは無さそうなの で、問題無さそうです。 さらにこのようなアーキテクチャでは、CPU がプログラムを読み込む仕組みを 単純化できるなど長所もあります。 また ATmega328P のようにプログラムの語長とデータの語長がそれぞれ 16bit と 8bit と異なるデザインも可能です。

プログラム領域

プログラム領域は データシートの Figure 12-1(p.36) にあるよ うに、0x0000 から 0x3fff まであります。 プログラムカウンタは 14bit あります。 アセンブリ言語では PC という記号で参照できます。 プログラム領域は 16 bit = 1 word でプログラムを記述しますが、一方で、 データも記述できます。 さらに本講義では扱いませんが、プログラム領域をプログラムによって書き換 えることもできます。

割り込み が発生した時は、発生した割り込みに応じて 0x0001 番地から 0x0032 番地の どれかが呼び出されます(割り込みベクタ pp. 84-85 Table 16-1)。 そのため、通常はこのベクタにはジャンプ命令のみ書いて、それぞれを処理する 番地に移行するようにします。 割り込みベクタ以降はどこにプログラムを書いても影響はありません。 但し、ジャンプ命令でどこへでも飛べるわけでは無いので、プログラムはなる べく近くに書きます。

プログラム領域にデータを書くには .db や .dw ディレクティヴを使用します。 ATmega328P のデータ処理単位は 8bit ですが、プログラム領域は 16bit 単位でアド レスが振られているので、プログラムからアドレスを指定してデータを読み出 す場合、(プログラム領域のアドレス*2)で最初のバイト、 (プログラム領域のアドレス*2+1)で次のバイトを読むことができます。 プログラム領域をアクセスするには lpm 命令を使いますが、アドレス指定は Z レジスタのみが使用できます。

メモリ構造

ATmega328P がデータをやりとりする場所は、プログラム領域の他、レジスタ、I/O、 SRAM領域、EEPROM があります。 このうち、レジスタ、I/O、SRAM は連続したアドレスが割り振られていて、 LD と ST 命令でやりとりできます(Figure 12-2 p.37)。 しかし、レジスタや I/O に関しては、より多くの専用の命令が用意されてい ます。

レジスタ

内部の数値論理ユニット(ALU)と接続して演算を行えるのはレジスタだけです。 したがって、機械語のプログラミングではレジスタの操作が重要になります。

ATmega328Pには 32 個のレジスタ(r0-r31)がありますが、 すべてのレジスタが同等ではありません(Figure 11-2 p.29)。 r27:r26=X, r29:r28=Y, r31:r30=Z と、3組のレジスタは 16bit のインデック スレジスタとしてメモリの番地指定に使用できます。 また、定数読み込み命令 ldi 掛け算命令 mul やビット操作命令は r16 から r31 までしか使えません。 さらに小数の掛け算命令 fmul, fmuls, fmulsu は r16 から r23 までしか使 えません。 なお、これらの掛け算命令による結果は r1:r0 に入ります。 従って、レジスタで一番命令の制限が無いのは r16 から r23 までなので、通 常のプログラミングではこのレジスタを主に使用します。 さらに、 r26 から r31 はインデックスレジスタとして利用します。

I/O

各入出力ポートの他、割り込みや外部との通信用に I/O があります。 I/O 用の命令として in, out があります。 さらに、 I/O 自体は 64バイト用意されているのですが、前半の 32 バイトに 対してはビット演算命令 cbi, sbi, sbic, sbis を使用できます。 なお、ld, ldd, st, std 命令を用いて、 I/O 番地に 0x20 を加えた メモリ空間としてもアクセスできます。

SRAM、スタック

SRAM は 0x0100(SRAM_START) 番地から 0x08FF番地(RAMEND) までの連続した領域として使 用できます。 ここへは ld, ldd, st, std 命令でアクセスします。

一方、ATmega328P では、この領域にスタックも置き、サブルーチン呼び出し rcall, ret などで使用します。 そのため、プログラムの開始時にスタックポインタを設定する必要があります(p.85)。


ldi r16,high(RAMEND)
out SPH,r16 
ldi r16,low(RAMEND)
out SPL,r16

スタックは rcall, ret, reti で戻り番地を記憶するために使われる他、8bit のデータを出し入れをする push, pop でも使用できます。

EEPROM

ゲームのデータや利用者の設定情報など、電源を切っても失いたくないデータ は EEPROM に書きます。 これの読み書きの仕組みは I/O にある EEPROM のアドレスレジスタとデータ レジスタを使用します。 アドレスレジスタにアドレスを書けば、データレジスタにデータを読み書きでき ます(データシート pp.38-45)。 なお、eseg と db ディレクティヴを使用すると、プログラマから書き込んで 初期化することもできます。

I/O Memory

I/O 領域は 64 Byte あり、さらに拡張 I/O 領域が160 Byte あります。 これは データシート p.427 の 35. Register Summary にまとめられてます。 この領域は基本的には LD, LDS, LDD, ST, STS, STD 命令で読み書きできます。 その時は、p.37 Figure 12-2 に示されるアドレスである 0x0020 から 0x00FF の 間のアドレスを使用します。 この I/O 領域には、各PORT の信号を制御したり、割り込みの制御をするなど、 様々な機能が埋め込まれています。

I/O領域に対する特別な入出力命令として IN , OUT 命令があります。 この場合、アドレスは 0x00 から 0x5F としてアクセスします。 さらに、前半のアドレス 0x00 から 0x1F の I/O 領域だけに有効な命令とし て、特定のビットを検査する SBI, CBI があります。

割り込み

電源を入れた時やリセットした時は 0 番地から実行が始まります。 一方割り込みが発生した時はそれぞれの割り込みに割り当てられた割り込みベ クタが呼び出されます。 (データシート pp.84-85 Table 16-1)。 割り込みとは次の条件が発生した時のことを言います。

  1. Reset, 電源On, 電圧低下によるリセット(Brown-out Reset), Watch dog Reset
  2. 外部割り込み0
  3. 外部割り込み1
  4. ピン変更割り込み0
  5. ピン変更割り込み1
  6. ピン変更割り込み2
  7. ウォッチドッグタイマータイムアウト
  8. タイマー/カウンター2 A と一致
  9. タイマー/カウンター2 B と一致
  10. タイマー/カウンター2 オーバーフロー
  11. タイマー/カウンター1イベント発生
  12. タイマー/カウンター1 A と一致
  13. タイマー/カウンター1 B と一致
  14. タイマー/カウンター1 オーバーフロー
  15. タイマー/カウンター0イベント発生
  16. タイマー/カウンター0 A と一致
  17. タイマー/カウンター0 B と一致
  18. タイマー/カウンター0 オーバーフロー
  19. SPI 送信完了
  20. USART0 Rx完了
  21. USART0 データレジスタ空
  22. USART0 Tx完了
  23. ADC完了
  24. EEPROM準備完了
  25. アナログコンパレータ
  26. I2C 2線インターフェース
  27. Store program memory 準備完了

これらの条件にマイコンが反応すると、それぞれの割り込みに対して、定めら れた割り込みベクタの番地のプログラムを実行します。

割り込みを許可/不許可するための値やレジスタのことを割り込みマス クと言います。 これには、個別の割り込みを ON/OFF するものの他に、全体の割り込みを ON/OFF する全体割り込み許可フラグが Status Register の Bit7 I にありま す(データシート pp.28-29)。 割り込みを使用する際は、個別の割り込みの設定をしたのち、この全体割り込 み許可を行います。 一方、割り込みが発生した時は、割り込みベクタが呼び出されますが、この際、 戻り番地がスタックに入る他に、この全体割り込み許可フラグがクリアされま す。 割り込み処理を終えた後、割り込み許可フラグをセットすると同時に割り込み 発生した番地に戻らなければなりませんが、これを1命令で行う RETI 命令が用意されています。 このような他の要因に影響されずにひとまとまりに操作することを アトミック と言います。

ヒューズビット

ATmega328P のチップにおいて、クロックの入力方法や、ピンの使用方法など、起動以 前に設定しなければならない項目があります。 これらは、プログラムなどと一緒に設定情報として書き込む必要があります。 この設定情報はヒューズビットと呼ばれています。 これは 3 Byte あり、データシートpp.346-348 に記載されています。

ヒューズビットで設定可能なのは、プログラムや EEPROM の読み書きの設定、 Broun-out 割り込みにおける電圧設定の他に、外部リセット端子の無効化、ク ロックの内部外部切り替え、内部クロックの速度の設定などです。 本講義では、これらはすべてデフォルトで使用しますが、高速に動作させたい など、デフォルト以外の動作をさせる場合は、精読して活用する必要がありま す。


坂本直志 <sakamoto@c.dendai.ac.jp>
東京電機大学工学部情報通信工学科