パワーオン起動に挑戦

前回は内蔵RAMにダウンロードしてプログラムを動作させましたが、今回はパワーオンでLEDをチカチカさせることに挑戦します。パワーオンで動作させるためにJTAG-ICEを使って、シリアルフラッシュメモリへプログラムを書き込みます。

パワーオンでLチカしたい

ここまでは内蔵RAMでプログラムを動かしていましたが、実際の組込み機器のようにパワーオンでLEDをチカチカさせたくなるものです。

そこで、CEVボードのハードウェアマニュアルを見ますと、ブートはRZ/A1Lのブートモード1を使用していると書かれています。つまり、シリアルフラッシュメモリから起動するようになっています。

ブートモード1のブートシーケンスをRZ/A1Lのマニュアルで確認すると、パワーオンリセット解除後、0xFFFF0000の内蔵ROMが実行されると書かれています。その後、なんやかんや処理して0x18000000に分岐する、となっています。

つまり、0x18000000番地から動作するようにプログラムを書けばいいということです。CEVボードのメモリマップを確認しますと、以下のようになっています。

アドレス空間 サイズ メモリ
0x0C000000 – 0x0FFFFFFF 32MB SDRAM
0x18000000 – 0x1FFFFFFF 2MB シリアルフラッシュメモリ
0x20000000 – 0x202FFFFF 3MB 内蔵RAM

0x18000000番地からシリアルフラッシュメモリがマッピングされていますので、RZ/A1Lの仕様と合致しています。CEVボードのシリアルフラッシュメモリには、出荷時にU-Bootが書かれています。今回はこれを上書きしますが、復元もできますので安心してください。

セクションアドレスの変更

では、シリアルフラッシュメモリに合わせて、コードのアドレスを0x18000000番地に変更します。

e2 studioを起動してワークスペースを開きます。
プロジェクト・エクスプローラーのルート「test [HardwareDebug]」を右クリックし、[Renesas Tool Settings]を選択します。
[Linker][セクション]をクリックします。

セクションの変更

このセクションの中で実際にシリアルフラッシュメモリに配置するのは、.fvectorsから.torsまでとなります。データ領域はそのまま内蔵RAMに配置しておきましょう。つまり、.fvectorsと.textのアドレスを変えればOKです。

ところで、.fvectorsってなんでしょう?
普通にベクタだと思っていたのですが、コードを調べてみるとvector_table.cに以下のように宣言されていました。

#define FVECT_SECT __attribute__ ((section (".fvectors")))

const void *HardwareVectors[] FVECT_SECT  = {
  _PowerON_Reset,
  INT_Excep_UndefinedInst,
       :(以下省略)

関数へのポインタが配列として宣言されていますが、Armのベクタには直接分岐命令を書く必要がありますので、仕様に合っていません。何かの意図があるのかもしれませんが、今回はこれを使用しないことにします。

よって、.fvectorsは削除して、.textを先頭の0x18000000に配置します。

セクションの変更

しかしまだ、これで終わりではありません。この段階では0x18000000番地に配置されるプログラムが不定なのです。.textセクションはCソースとreset_program.asmのコードが割り当てられますので、リンクの順番によっては意図しないコードが先頭になる場合があります。

リセット処理のソース変更

ソースコードを眺めてみれば、reset_program.asmの「_PowerON_Reset」から実行すればOKのようですので、新たなセクションを作成してリンカに設定します。

e2 studioでreset_program.asmを開いて、「.section .text」を「.section .resetprg」に書き換えます。これで、このソースは.resetprgセクションとなります。

セクション追加

先頭のコードを見ますと、_PowerON_Resetまでに何らかの固定データが存在します。このままだと、このデータをプログラムだと思って実行してしまいますので、先頭から_PowerON_Resetへ分岐する命令を書きます。

Armの分岐命令は「B 分岐アドレス」です。「b _PowerON_Reset」と追加します。

「b _PowerON_Reset」と追加

再びセクションの設定

新たなセクションを追加しましたので、再びリンカの設定からセクションを変更します。もうおなじみとなりましたが、セクションのウィンドウを開きます。

.textセクションの上で右クリックすると、メニューが表示されますので、ここで[式の追加]を選択します。ツリーを展開すると「.expression」が追加されています。これをクリックすると内容の変更ができますので、式の名前を「.resetprg」に変更します。

式の名前を「.resetprg」に変更

次は追加したセクションを.textの上に配置します。[上へ移動]ボタン(下の画面の赤枠のところ)を押すと上に移動します。

上に移動

これでメモリ配置はOKです。ビルドしてCEVボードへダウンロードしましょう。

シリアルフラッシュメモリへの書き込み

ダウンロードしましょうといいましたが、実際にはシリアルフラッシュメモリへ書き込む必要がありますので、そのままではダウンロードできません。

PALMiCE3にはNORフラッシュ以外にも、SPIで接続されたシリアルフラッシュメモリへ書き込む機能が用意されていますので、それを使います。

CSIDEをプロジェクトファイルから起動し、[ファイル]メニューから[ユーザ・カスタマイズ・モニタ・マップ]を選択します。

ユーザ・カスタマイズ・モニタ・マップ

[モニタ登録]ボタンを押して、さらに[追加]ボタンを押します。

モニタ登録

シリアルフラッシュに書き込むにはモニタプログラムが必要ですので、[参照]ボタンを押して指定します。モニタプログラムはCSIDEのインストールフォルダのEtc にあります。デフォルトのフォルダにインストールすると下記のファイルとなります。

C:\Program Files (x86)\CSIDE\Etc\PALMiCE3 ARM\UCM\RZ_A1L\CEV-RZ_A1L\project\gcc\Monitor.elf

[OK]を押して、[閉じる]ボタンを押すと以下のメッセージが表示されますので、[はい]を押してください。

メッセージ

無事登録されました。

登録完了

次にファイルロードに対して、登録したモニタを適用するように指定します。
ツールバーの[ファイルロードボタン]を押して、[変更]ボタン、[詳細設定]ボタンと押していきます。最終的にモニタ選択で[ユーザー・カスタマイズ・モニタ1(UCM1)を使用する]を選択します。

ユーザー・カスタマイズ・モニタ1(UCM1)を使用する

これで設定は終わりです。[OK]ボタン、[変更]ボタンを押して[ダウンロード]ボタンを押します

ダウンロード

モニタ経由で書いているので、内蔵RAMのダウンロード速度と比べると、じわっと遅いです。
このようにCSIDEはダウンロードファイルに対して、どのモニタを使用するかを指定できます。これを使えばシリアルフラッシュ以外のデバイスにもダウンロードできそうです。

シリアルフラッシュメモリでの動作確認

コードウィンドウを開いて書けたかどうか確認してみましょう。ミックス表示でコードを見ると、あれ?書けていませんね、すべてのコードが0になっています。

コードウィンドウ

これはRZ/A1Lの仕様で、内蔵ROMの初期化ルーチンが実行されないと、0x18000000番地が見えないようになっています。それならCSIDEで[ハードウェアの初期化](つまりリセット処理)を行って、0x18000000番地まで実行すればOKのはずです。

[システム]メニューの[ハードウェアの初期化]を行って、CTRL+Uを押してから「18000000」と入力します。

「18000000」と入力

おおっ、ちゃんとメモリの内容が表示されましたね。これで動いたのも同じです。
F5キーを押して実行します。

LED1は点灯しましたが、なぜかチカチカしません。しばらく放置しているとLED2が点灯しました。

なるほど、内蔵RAMに比べて実行速度が遅いんですね。
RZ/A1LではシリアルフラッシュメモリをCPUのメモリ空間にマッピングして、直接実行できる仕組みを持っていますが、SPI ⇒ アドレス変換のロジックが動作するので、その分遅くなるのでしょう。 これをもっと本気で使うためには、キャッシュを有効にすればいいのかもしれません。

でも、アドレスバスがつながっていないメモリを直接実行できるって、なかなか面白いと思いませんか。

キャッシュを操作して試す

というわけで、キャッシュのフラグビットをICEで操作して試してみましょう。Armには1次キャッシュを有効にするフラグがCP15という制御レジスタに用意されており、CSIDEで変更することができます。

一旦プログラムをブレークして、レジスタウィンドウを開き、右クリックメニューで[CP15]を選択します。「C1.I」がコードキャッシュのビットになります。0でキャッシュ無効、1でキャッシュ有効になりますので1に設定してみましょう。

レジスタウィンドウ

そのまま再実行してみますと、いい感じでLEDがチカチカしました。やはり、キャッシュを使用すればシリアルフラッシュでのプログラム実行は使えそうです。

再びパワーオンでLチカしたい

キャッシュはとりあえず置いといて、まずはパワーオンでLチカを実現することを考えます。といっても、とりあえず遅いだけですのでディレイの時間を短くしてその場をしのぎます。

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

とりあえず10000を100に変更しました。

これでビルドしてダウンロード、実行すると…
LEDがチカチカするようになりました。体感的には内蔵RAMと同じくらいの間隔のような気がしますので、シリアルフラッシュでの実行は、内蔵RAMの100倍ぐらいの実行時間差があるんでしょうか。今後、要調査です。

さて、いよいよパワーオンでLチカするか試してみましょう。正確を期すためにPALMiCE3もUSB電源も一度すべて外して試します。そして再びUSB電源を接続しますと、ご覧のようにLEDがチカチカしました。

LEDがチカチカ

次回は、今まで見ないふりをしていたCPUの初期化ルーチンに手を入れ、割り込みを使った本格的な(?)タイマーでLチカを行います(まだLチカは続く…)。