プログラムを動かそう

前回で開発環境をそろえましたので、実際にプログラムを作ってボードで動かしてみましょう。LEDをチカチカさせるためのGPIOの制御方法や、メモリ配置の設定、JTAG-ICEを使ってボードで動作するところまで説明します。

ボードを用意しよう

プログラムを作る前にボードを用意します。コンピューテックス製のCEV-RZ/A1L(以降CEVと表記します)を使用します。

CEV-RZ/A1L

このボードにプログラムを載せていくわけですが、まずはボードの仕様を把握するために、マニュアルをダウンロードしましょう。CEVのハードウェアマニュアルは下記のURLからダウンロードできます。

https://www.computex.co.jp/products/pdf/manual/cev/cev-rz_a1l_hardware_manual.pdf

このマニュアルによると、幸い(?)にもポートにつながったLEDが2つあります。ハードウェアマニュアルを引用すると、「モニタ用としてCPU のP7_8 にLED1(赤)が、P7_9 にLED2(赤)が接続されています。」となっています。

このLED、光っていないときは地味で分かりにくいのですが、通電するとまぶしい光を放ちます。これを使ってLチカを実現しましょう。

RZ/A1LのGPIO

CEVで使用しているP7_8、P7_9というのは汎用入出力ポートのことで、一般にGPIOと呼ばれているやつです。GPIOは普通、他の機能と兼用ピンになっていますので、

  • このピンを汎用ポートとして使用する
  • 入出力の方向

の2つを設定すれば、大体の場合OKです(だと思います...)。

先にダウンロードしたRZ/A1Lのユーザーズマニュアルを開いて、汎用入出力ポートを見てみると、兼用モードを設定するポートモード制御レジスタ(PMCn)と、ポートの入出力を決めるポートモードレジスタ(PMn)がありますので、これらを初期化します。

●ポートモード制御レジスタ(PMCn)
PMCn
15
PMCn
14
PMCn
13
PMCn
12
PMCn
11
PMCn
10
PMCn
9
PMCn
8
PMCn
7
PMCn
6
PMCn
5
PMCn
4
PMCn
3
PMCn
2
PMCn
1
PMCn
0
0:ポートモード
1:兼用モード
●ポートモードレジスタ(PMn)
PMn
15
PMn
14
PMn
13
PMn
12
PMn
11
PMn
10
PMn
9
PMn
8
PMn
7
PMn
6
PMn
5
PMn
4
PMn
3
PMn
2
PMn
1
PMn
0
0:出力モード
1:入力モード

PMCやPMについているnはポートグループを表しています。P7_8というのはグループ7の8ビット目ということになります。つまり、PMC7の8ビット目を0にすればポートモードになり、PM7の8ビット目を0にすれば出力モードになります。

実際のデータを出力するのはポートレジスタ(Pn)ですので、このレジスタ(P7の8ビット目)に書き込めばLEDがチカチカしてくれるはずです。

P7_8とP7_9へ書き込むための設定をまとめますと、以下のようになります。

  • PMC7の8と9ビット目を0にする。
  • PM7の8と9ビット目を0にする。
  • P7の8ビット目に1を書き込めばLED1が点灯し、0を書き込めば消灯。
  • P7の9ビット目に1を書き込めばLED2が点灯し、0を書き込めば消灯。

コードを追加しよう

e2 studioを閉じている場合は、もう一度起動してください。先ほどのワークスペースからtest.cを開いてコードを追加します。

まず、iodefine.hをインクルードします。先頭に「#include “iodefine.h”」を追加します。ついでに「#ifdef CPPAPP」で囲まれたところは、今回使わないので削除しておきます。

次はmain関数の先頭でGPIOの初期化を行います。GPIOのPMC7とPM7のビット8と9に0を書き込みます。

このエディタの機能として「GPIO.」と打ち込むと、後続するメンバ名を補完してくれるはずです。やってみましょう。

メンバ名を補完

あれ?補完されませんね。
test.cを保存してからもう一度CTRL+Spaceを押してみましょう。

CTRL+Spaceを押してみましょう

今度はちゃんと表示されました。これは、「#include “iodefine.h”」を追加した後で、ファイルを保存していなかったために、iodefine.hが解析されなかったためのようです。

では、引き続きPMC7を選択します。代入する値として、使わないビットに一応マスクをかけておきましょう。16ビットのビット8と9ですから0x0300ですね。これをビット反転してマスクをかけて代入します。つまり「&= ~0x0300;」となります。PM7も同様に追加します。

  GPIO.PMC7 &= ~0x0300;
  GPIO.PM7  &= ~0x0300;

GPIOの初期化コードを追加したソースコードは以下のようになります。

GPIOの初期化コードを追加

さあ、いよいよLEDの制御を追加します。
先ほどのポートと同じ要領でP7のビット8と9を書き換えます。まずはLED1をONにします。ORで代入してビット8だけを1にセットします。

  GPIO.P7 |= 0x0100;

次はLED1をOFFにします。セットしたビットを0にします。

  GPIO.P7 &= ~0x0100;

同様にLED2にも同じことを行います。

  GPIO.P7 |= 0x0200;
  GPIO.P7 &= ~0x0200;

最終的にソースコードはこのようになりました。

ソースコード

ここでは生真面目にポートをビット操作しましたが、ほかにポートを使っているわけではないので、以下のようにしても動作します。

  GPIO.P7 = 0x0100;    // LED1のONとLED2のOFF
  GPIO.P7 = 0x0200;    // LED2のONとLED1のOFF

では、ビルドしてみましょう。

ビルドしてみましょう

無事ビルドが通りましたので、これをCEVボードにダウンロードして実行します。

ここでCPUの初期化はどうなっているのか、疑問に感じられる方もおられるでしょう。実はプロジェクト作成時にreset_program.asmというソースファイルが作られて、最小限の初期化が行われるようになっています。

また、このプログラムは何番地で動作するのかメモリマップも気になるところだと思います。プログラムの配置アドレスはリンカによって決められますので、リンカの設定をのぞいてみましょう。

リンカのセクションを確認しよう

コンパイラやリンカのオプションを表示するには、プロジェクト・エクスプローラーのルート「test [HardwareDebug]」を右クリックし、[Renesas Tool Settings]を選択します。プロジェクト・エクスプローラーのルートを右クリックしないと、リンカの設定が表示されませんので注意してください。
ここで[Linker][セクション]をクリックすると、セクションの表示に切り替わります。

リンカのセクションを確認

この表示を見ると、4つのセクションでアドレスが設定されています。

.fvectors (0x20020000)
.text (0x20020100)
.data (0x20060100)
.stack (0x20061100)

0x20020000番地はRZ/A1Lの内蔵RAMを指しています。したがって、このプログラムはすべて内蔵RAMで動作するということになります。RZ/A1Lの内蔵RAMは3MBありますので、余裕でプログラムを走らせることができます。

JTAG-ICEを接続しよう

それでは、実際にプログラムをCEVボードにダウンロードしてみます。使用するJTAG-ICEはもちろんPALMiCE3です。CEVボードとの接続は20ピンのハーフピッチのJTAGコネクタです。ボードへの電源はパソコンからのUSBで供給します。

接続するとこんな感じになります。

JTAG-ICEを接続

CSIDEを起動する

PALMiCE3が接続できたら、デバッガCSIDEを起動します。ここからはCSIDEがインストールされている前提で話を進めますのでご了承ください。詳しくはPALMiCE3 ARMのマニュアルをご覧ください。

CSIDEを起動し、[設定]メニューの[ターゲットシステムの設定]を選択すると、CPUの選択画面が表示されます。ここで、メーカ名は[Renesas]、CPUは[RZ/A1]を選択し、[起動する]ボタンを押します。

CSIDEを起動する

次にターゲットシステムの設定ウィンドウが表示されますので、[更新]ボタンを押してください

ターゲットシステムの設定ウィンドウ

これで起動完了です。

オブジェクトファイルのダウンロード

さて、次はビルドしたオブジェクトファイルをダウンロードします。ファイルロードのボタンを押して、ファイルを選択します。[ファイル名]の項目に「*.x」を入力して、HardwareDebugのフォルダに移動します。

オブジェクトファイルをダウンロード

そうすると、オブジェクトファイル「test.x」が表示されますので、このファイルを選んで[追加]ボタンを押します。以下の画面のように登録されます。

ファイルを選んで追加

ここで[ダウンロード]ボタンを押せば、ダウンロードが開始されます。

ダウンロード

上記のロードアドレスを見ると0x20020000 - 0x20023DCFとなっていますので、内蔵RAM空間であることが分かります。

ダウンロードができたら、コードウィンドウを開いてみましょう。

コードウィンドウを開いてみましょう

ちゃんとダウンロードできたようですが、まだ安心してはいけません。
ここでミックス表示に切り替えて、アセンブラソースと逆アセンブラの対応が一致するかどうか確認します。

アセンブラソースと逆アセンブラ

はい、ちゃんと一致しているようですね。プログラムが正しくメモリに書き込まれて、デバッグ情報と一致しているかどうかを確認しておくと、後々トラブルを起こさなくて済みます。

プログラムの実行

では、ソースモードに戻して、main関数まで実行します。CTRL+Uを押して、「main」と入力すればmain関数まで実行して停止します。

プログラムの実行

うまく行ったようです。mainまでの初期化でトラブることはよくありますので、すんなりいく方が珍しいと思います。
では、恐る恐るステップ実行して動作確認してみましょう。まずはGPIOの初期化の2行をステップ実行します。

GPIOの初期化

無事通過しました。
次に27行目をステップ実行してLED1を点灯してみます。

LED点灯

うまく行きました。さらにステップ実行すると、LED1の消灯 ⇒ LED2の点灯 ⇒ LED2の消灯もOKでした。
では、実行してチカチカさせてみましょう。F5キーを押します。

両方点灯

チカチカが速すぎて、両方点灯しているように見えます(これは想定内です、、)。
ONとOFFの間にディレイを入れてチカチカの速度を調整します。本当なら、タイマーを使うところですが、早くチカチカが見たいのでソフトウェアタイマーを入れます。

  void sleep(int n)
  {
	volatile int i;
	for (i = 0; i < n*10000; i++);
  }

まあ、こんな関数でいいのではないかと思います。変数iをvolatile宣言している理由は、最適化によりループがなくなってしまうのを防ぐためです。

この関数をmain関数の前に配置し、LED1のONとOFFの間、LED2のONとOFFの間で呼び出します。同じタイミングでチカチカさせても芸がないので、sleepの引数を調整してタイミングをずらしてみます。

タイミングをずらしてみます

LED1でsleep(50)とし、LED2はその倍のsleep(100)で点灯するようにしました。
ビルド後、ICEで再ロードして実行すると、今度はうまく、LEDがチカチカしました。いいタイミングで点滅を繰り返していて、見ていると癒されます。

LEDがチカチカ

CSIDEのプロジェクトを保存する

ここで一度、CSIDEを終了して設定をプロジェクトファイルに保存しておきましょう。[ファイル]メニューの[名前をつけて保存][プロジェクト]で保存します。

この時、e2 studioのワークスペースフォルダ内に保存しておくと、e2 studioのプロジェクト・エクスプローラーからcside.cpfをダブルクリックすることで起動できますので便利です。

CSIDEのプロジェクトを保存する

次回はシリアルフラッシュメモリへ書き込んで、パワーオンでLチカを実現させます。