インターフェイス2011年5月号の付録基板を使います。すでに6月号にSDカードを操作して、ファイルシステムを実装する記事がありますが、インターフェイス誌のサンプルソフトを元に、このURLで使ってきたモニタをまず移植します。パソコンと通信するRS232Cは、SCI0を使い、SPIポートは、RSPI1を使います。なので、JTAGポートは使えません。
SCI0で、送信と受信をテスト SCI0を使うモニタを移植
SDカードを接続してモニタで操作
RX用GCC開発環境を作成( ROM化できる ) 正確には、初期化付き変数を使う場合。
Hewでのデバッグは、SIO の方が転送が早い
RX62NのSDカードモニタをROM化する。GCC版は現在作成途中
GCCでROM化のテスト。とりあえずRAM上で、ROMに見立てたアドレスでリンカのテスト
ROM化の準備1、ベクタテーブルの配置
ROM化の準備2、アセンブラでしか書けない処理 2011.12.19 更新
割り込みのテストをしてみる 多重割り込でLED点滅 2012.1.18 更新
RX62Nなどで、FatFs を使ってみる。FatFs でのSDカードアクセス回数の調査 2012.2.22 更新
SH2A(SH7262)を使った例はこちら→SH2AのSPIでSDカードを操作、SH7262でのスピード評価 SH7262 は、クロックを同一に換算しても、LPC2388( ARM7 ) の1.5倍の速さ。
インターフェイス誌2011年6月号と、5月号付録基板にRS232Cポートを付けたもの。
LED点滅ソフトを改造してRS232Cをテスト。
あれもこれもつなぐには、若松通商のLCDキットを使うのが手っ取り早いのですが、ここでは適度に、ありあわせのICなどを使います。この写真では、SCI0に、簡易RS232C変換回路をつけて、RS232Cの動作テストをしたものです。プログラムは、LEDを点滅させるCQ出版からダウンロードできる Sample_Project.zip の、main.c を改造しています。
以下は、LEDを点滅させる main.c を改造したもの。SCI0と、SPIポートを初期化して、SCI0は、入出力、SPIは、出力のみ。
以下は、簡易RS232C変換回路です。トランジスタがOFFする時間が2μ秒ほど遅れる場合がある( DTC143 は約1μ秒と短い。)ので、ボーレートの誤差が大きい場合はエラーが起こりやすくなりますが、±1%ぐらいなら全く問題ありません。115200bpsで2μ秒は、2.3%の誤差となります。
上記のRS232Cテストで、動作確認したあと、モニタを移植します。LED点滅プログラムの、main.c をさらに改造しますが、他のソースや、プロジェクトの設定は一切変更しません。デバッグも、LED点滅のサンプルソフトを動かすのと全く同じです。
移植後の、main.c は以下のようになります。ここでは先頭部分のみ表示しています。
全体をテキストファイルにしたものは、こちら→ main.txt
パソコンのターミナルで操作したときのスクリーンショットです。0x400番地から256バイトをダンプしています。このモニタの仕様は、SH2用モニタとほとんど同じです。シフトJISの漢字を表示することができます。ascii のところで、2行に渡っている場合でも表示できます。ただし、以下のようなテラタームでは、端末(T)の設定で、漢字-受信(K)を、(default)UTF-8 から、SJIS に設定変更する必要があります。
以下は、HEWで、メモリを表示したスクリーンショットです。
SDカードを接続する回路。若松通商の拡張基板のSDカードとは、接続ポートが異なります。
|
SDカードの3.3V電源は、RX62Nから制御できるような回路を追加しています。SDカードを再挿入しなくても、SDカードにパワーONリセットをかけることができます。カード挿入検出とライトプロテクトはまだ接続していません。
表面。空きエリアには、イーサネットのPHYなどを追加する予定。その他、FPGA追加で、大容量DRAMも予定していますが、安価な評価基板が見当たらないので、以前に購入していた、Digilent の、ATLYS ( XC6LX45-CSG324C を搭載 )を接続予定。特殊電子回路のSpartan-6 FPGA評価ボードも、DDR2搭載なので使えるのですが、なにぶん4万円ほど出費になってしまう。また、ヒューマンデータの評価基板は、これも5〜6万円と高い。これだけ高いと、まだ手持ちに無いICなどが搭載された、別の評価基板を買ったほうがいい。
裏面。周囲のすずめっき線は、GND。基板の下の端、やや左に、小さな黒いのが載っていますが、この部分が簡易RS232C変換回路です。上の写真の下の端、CQ基板の右下に、4PINのチェックコネクタありますが、このうち3本が、RS232Cコネクタに接続されます。
操作プログラムは、LED点滅プログラムの、main.c をさらに改造し、以下の mainsd.txt を、main.c に名前を変更してに置き換えて、HEWで再コンパイルします。
SDカード操作プログラムの全体 → mainsd.txt このファイルを、main.c に変更して、置き換えます。
以下は、mainsd.txt の一部
こちらは、少し前のもの。バグあり → mainsd_110608.txt
こちらは、少し前のもの。バグあり → mainsd_110610.txt
SDカードを装着しておいて、上記プログラムを、HEWでRX62Nにロードし、リセット、実行で、ターミナルには、以下のようなオープニングメッセージが表示されるので、
Custom Monitor 2011.6.8
RX62N-Bug>
ここで、"Si" (Enter) とコマンド操作すると、SDカードを操作できる状態になります。以下はそのスクリーンショットです。
モニタの操作コマンドの仕様は、SH7144でSDカードを操作するモニタ と、ほとんど同じです。
以下がSDカード関連コマンドの使用方法です。ここで、SDカードの任意のアドレスは、SDHC では、セクタ番号、そうでない2GB以下では、アドレスとなります。例として、SDHCのセクタ1では、x = 1、 そうでない場合は、x = 200 と、物理アドレス、0x200の指定になります。z は、セクタ個数で、SDHCの区別はありません。
- SDカードを使える状態にするコマンド。 "Si"
- SDカードの任意のアドレスから、メモリの任意の番地へ、指定セクタを連続で読み出す。 "Sr x,y,z"
- SDカードの任意のアドレスから、メモリの任意の番地のデータを、指定セクタ連続で書く。 "Sw x,y,z"
- SDカードにCMDを出す。"cmd n"。n は、0,1,8,9,10,17,24,41,58 で、それぞれ、CMD0,CMD1,CMD8,CMD9,CMD10,CMD17,CMD24,ACMD41,CMD58 に対応します。ACMD41 の場合だけ、CMD55 が自動で先行で追加されます。
- CMD17 の場合は、SDのアドレス x と、読み出すCPUのアドレス y を、cmd 17,x,y と指定します。操作セクタ数は1個だけです
- CMD24 の場合は、SDのアドレス x と、書くデータのバッファーアドレス y を、cmd 24,x,y と指定します。操作セクタ数は1個だけです
RX62Nの内臓RAMが、64kBと小さいので、SDカードのデータの格納は、プログラムの空きエリアを指定します。モニタのサイズが、0番地から11kBほどなので、0x4000 --- 0xF000 ほど使えます。CQ付録基板のRX62Nは、R5F562N7BDFB で、Renesas のRX62NファミリURLによると、RAMが64kBとなっているので、0x0〜0xFFFFと思っていましたが、0x10000〜0x17FFFにもRAMが存在していて、どうも RAM1 のようです。このため、RAMとして、0x0〜0x17FFFまで、96kBが使えるようです。96kBあるのは、R5F562N8 ファミリーのはずです。
以下は、2GBのSDカードの、0x10600番地( セクタ番号では、0x83 に相当する )を0x10000番地のRAMに読み出して、メモリダンプした例です。
このSDカードの0x10600番地( セクタ番号では、0x83 に相当する )は、FAT16のブートセクタになっています。
ルネサス純正 IDE 評価版 Hew は期限付きなので、(と言っても128Kまでなら期限後でも可能)GCCで開発できるものを作ります。環境は、Cygwin上となります。Cygwin は、ここからインストールソフトをダウンロードしてからセットアップします。現時点(2011.6.15)の最新版では、1.7.9−1ですが、解説では、1.7.7を使っています。クロス開発環境のビルドは、大変時間がかかりますが、Corei5と、キャッシュの大きな高速のHDD上なら、1〜2時間で可能です。また、 configure のオプションを間違えると、エラーで止まってしまうこともありますが、何回かトライしてると、何がだめなのか、だんだんとわかってくるようになりますが、備忘録のためもあって、記録を残すことにしました。
用意するものは、binutils-2.2.1.tar.bz2 と gcc-4.6.0.tar.bz2 を、ftp.riken.jp か、ftp.jaist.ac.jp から、newlib-1.18.0.tar.gz を、sourceware.org/newlib/ の左の、Download からダウンロードします。
Cygwinのセットアップは、以下のように、Devel 、Libs、Math を、Install に変更して次に進みます。インストール後は、2.5GBほどになります。(V1.7.7の場合)
Libs と、Math をInstall しないと、configure の段階で、gmp, mpfr, mpc のヘッダ、ライブラリが無いため、エラーでストップします。↓
configure: error: Building GCC requires GMP 4.2+, MPFR 2.3.1+ and MPC 0.8.0+.
Cygwinのセットアップが済むと、binutils-2.2.1.tar.bz2 と gcc-4.6.0.tar.bz2 と、newlib-1.18.0.tar.gz を /usr/local フォルダにコピーします。このフォルダに、以下のようなテキストファイルを作っておいて、エディタで開いておき、Cygwin のコマンドラインにコピーアンドペーストします。
上記コマンドで作成したクロスコンパイラは動作確認済みです。ソースファイルの解凍に15分、binutils の configure & コンパイルに10分、gcc の configure & コンパイルに20分、newlib の configure & コンパイルに6分かかっています。(Corei5 660、WindowsXP SP2、Cygwin 1.7.7(0.230/5/3)、 HDD は WDのSATA 1TB、多分 5400rpm、キャッシュ64MB、マザーは、ASUSTeK P7Q57-M DO )
クロス開発ソフトは、/usr/local/rx-g460-elf/ 以下に作成され、約280MBあります。
圧縮したものはこちら。rx-g460-elf.tar.gz ← 初期化付き変数を使う場合、ROM化できないです。
ROM化できるものは、こちら → 圧縮したものはこちら。rx-g462-elf.tar.gz
こちらは、初期化付き変数を使う場合もROM化できます。gcc ( 4.6.2 ) binutils ( 2.21 ) newlib ( 1.19.0 ) です。
解凍は、cygwin/usr/local/ フォルダに置き、そこで rx-g462-elf フォルダを作り、
$ cd rx-g462-elf ( enter ) として、そのフォルダに移動して、
$ tar zxvf ../rx-g462-elf.tar.gz ./ >../tarrx.log 2>&1 ( enter ) とコマンドを与えると、解凍できます。tarrx.log はどこに何を解凍したかのログ。
$ export PATH=/usr/local/rx-g462-elf/bin:$PATH とすることで、パスが通ります。
パスを通さない場合は、makefile に、たとえば、e:/cygwin/usr/local/rx-g462-elf/bin/rx-g462-elf-gcc などと、直接指定すると使えます。
Hewでのデバッグでは、USB接続のものより、SIOの方が転送が早い
|
Hewを使ったシリアル接続のデバッガには、すぐに使えるUSBと、外部回路が必要な、SIO0、SIO1、SIO2のデバッグ用ファームウエアが用意されていて、どれでも同じようなデバッグ操作ができますが、SIOn にすると、プログラムのダウンロードなどが、かなり早くなります。理由は簡単で、USBシリアルでのボーレートが38400であるのに比べ、SIOの場合は、115200だからです。また、パソコンによっては、USBでのデバッグで、RUNさせた後STOPボタンが効かなくなるのがあります。USBを使っていながら、38400でしか使えないのも、残念です。
GCC では、リンカにバグがあるので、上記のCygwin 用ツール( rx-g460-elf.tar.gz )は未対応です。←解決策が見つかったので、ここに、rx-g462-elf.tar.gz を置きます。2011.12.8
GCCを使ってROM化する例は、近々に解説します。以下は、Hewを使ったROM化です。
デバッガを接続して動作確認できると、今度は、ROM化をしてみます。無論、ROM化すると、Hewを使ったシリアル接続のデバッガは使えなくなりますので、簡単なデバッグ機能を使えるようにしておきます。その機能としては、
- パソコンからRS232Cを介してデバッグ対象のプログラムをRAMにロードできる。
- 任意の番地から、実行できる。
- メモリの参照、変更ができる。
- デバッグ対象のプログラムを走らせているとき、ターミナルからの操作で、ストップできる。
- ブレークポイントを設定できる。
- ストップや、ブレークしたときのレジスタを確認できる。
これくらいですが、4,5,6、については、アセンブラをはじめ、RX62N用コンパイラの、スタックフレームまで調査する必要があり、すぐにはできそうにないので、1,2,3のみ実装します。また、レジスタを表示できても、C言語で開発したものを、アセンブラレベルのデータが表示できたところで、ほとんど役立ちません。1,2,3のみでも、デバッグ途中のソースに、printf ( コンパイラ組み込みを使うと膨大になるので、簡易 printf 「 cprintf 」 )で、変数の表示などをさせるだけで大抵用が足せます。1,2,3までなら、すでに、ここで紹介した、 mainsd.txt に実装していますが、若干追加したものを使います。→ mainsdrom.txt このモニタは、SIO0のRS232Cで操作します。
図では、全部見えませんが、設定値は以下です。
Address と、section 名
0x0000F800 SI,B_1,R_1,B_2,R_2,B,R ← 変更するのは、このアドレスのみ。0x00000000 ==> 0x0000F800
0xFFFA0000 C$VECT
0xFFFA0400 PResetPRG,PIntPRG,P,C_1,D_1,W_1,C_2,D_2,W_2,C,D,W,L,C$DSEC,C$BSEC
0xFFFFFF80 FIXEDVECT
さらに機能追加した main.c が、 mainsdrom2.txt ( このファイルを、main.c に名前を変更して置き換えます )、GCCでも使えるようにI/O設定など追加、分離したものがこちら。→ monitor_h.txt を monitor.h として、プロジェクトのソースに追加、さらに、 rx62n_h.txt を rx62n.h として、プロジェクトのソースに追加しておきます。 これらのヘッダーファイルは、main.c で参照しています。
これを、ROM化するわけですが、LED点滅サンプルプログラムのソースファイル群は、ROM化できるように作成されているので、そのまま使います。Hewのプロジェクトを、Debug から Release に変更し、Hewのビルド(B) プルダウンメニューの、RX Standard Toolchain... を選択して、「最適化リンカ」タブの、カテゴリ(Y) の「セクション」を表示して、設定を変えます。
この設定で作成したROM化プログラムは、こちら → RX62N_mot.txt これを ROMに書けば、ここで説明している回路で、パワーONでSDカードの操作プログラムが走ります。RS232Cは、115200ボーとなっています
このときの、Hewのスクリーンショットは、以下です。
モニタのコマンドにSDカードを操作するコマンドを追加して、単にSDカードの読み書きにとどまらず、いろいろなことができるようにしています。操作機能は、以下です。
- SDカードの初期化。コマンドは、Si(enter)--CMD0,CMD8, ... さらに、CSD を読み出して、SDHC か否かなどを調査する。
- SDカードを指定セクタから指定メモリに、指定セクタ数だけ読む。コマンド例。Sr2000,10000,1(enter)--0x2000 セクタから、0x10000 番地に、1 セクタ読み出す。
- 上記コマンドで、マルチセクタリード、CMD23 + CMD18 で実行。コマンド例。SR2000,10000,10,10(enter)--0x2000 セクタから、0x10000 番地に、10 セクタ読み出す。
- SDカードの指定セクタから指定メモリのデータを、指定セクタ数だけ書く。コマンド例。Sw5000,10000,10(enter)--5000(hex) セクタから、0x10000 番地からのデータを、0x10 セクタ書く。
- CRCチェックの有効、無効を指定する。encrc(enter)--有効、 dscrc(enter)--無効。
- SPIの転送クロックを指定する。ボーレート設定レジスタを変更してスピードを変える。clkspeed 0(enter)--付録基板での最速、24MHz になる。
- CRC7や、CRC16を計算する。crc7 8100,f(enter)--メモリの 0x8100 番地から、0xF バイトのCRC7を計算して表示する。
- CMDx をSPIで送って、レスポンスを表示する。CMD0,CMD1,CMD8,CMD9,CMD10,CMD17,CMD18,CMD23,CMD24,CMD58,CMD41(=ACMD41) など
- 各コマンドの実行時間を測定して、後で確かめる。最大約0.6秒まで。これは、RX62N 内臓カウンタが16ビットの制限による。T(enter)
GCCでROM化のテスト。とりあえずRAM上で、ROMに見立てたアドレスでリンカのテスト
|
ROM化可能なリンカに修正した環境で、 rx-g462-elf.tar.gz テストプログラムを作成して、リンカで設定されるSECTIONの確認をしてみます。
詳しくは、なひたふさんのブログ、なひたふJTAG日記 rx-elf-gccの問題点に解説があります。
全く同じソースを使って、リンカを修正していない場合と、修正した場合とで次のような違いがでてきます。
以下はアドレス指定を行う、リンカ用のスクリプトで、同じものを使っています。プログラムと固定データが0x2000〜、RAMを0x6000からにしています。
rx-g460-elf-objdump を使って、出来上がった .elf ファイルをダンプしてみると、
修正なしの場合の、rx-g460-elf-objdump -h test.elf > testdmp2.lst で作成した dmp ファイルは以下で、
gccのバージョンが、gcc-4.6.0 と、gcc-4.6.2 の違いがあるので、若干違いが出てますが、問題は、Sections: の D です。
(57行目の、 26 D 0000008c 00008948 00008948 00003948 2**2 に注目。VMA と、LMA が同じ )
修正後の場合の、rx-g462-elf-objdump -h test.elf > testdmp2.lst で作成した dmp ファイルは以下でです。
(57行目の、 26 D 0000008c 00008948 000044fb 00003948 2**2 に注目。VMA と、LMA が異なる )
両方とも、Sections: D の VMA は、0x00008948 ですが、LMA が違っています。0x00008948 は、RAMに指定したメモリ領域で、変数領域ですが、LMA はROMに指定した領域です。修正前のものでは、リンカスクリプトで異なる領域に指定しているにもかかわらず、LMA = VMA になっています。当然ながら、objcopy で、ヘキサファイルに出すと、LMA の領域はRAMのアドレスで出力され、ROMに書いて残すことができません。出力された test.mot の最後を見ると、
S310000044B44E207364617461322E00001C が、ROMの最終で、( 実際にはROMのアドレス、0xFFFFxxxx になる )その後、
S31500008948525836324E2D4275673E20746869732038 と、RAM領域に指定したデータがあります。0x8948 番地から、"RX62N ..." です。これは正に、
char prompt[]="RX62N-Bug> this is SECTION D. これは、char []=\"xxx\"。copy from ROM";
のデータです。
修正後のものでは、以下のようになっています。先ほどの、 26 D 0000008c 00008948 000044fb 00003948 2**2 の、000044fb が LMA で、
S315000044FB525836324E2D4275673E207468697320CA を見ると、アドレス、0x000044FB から始まっており、以下のソースで作成される、
char prompt[]="RX62N-Bug> this is SECTION D. これは、char []=\"xxx\"。copy from ROM";
の文字データとなっています。RAMは 0x6000 番地から指定しているので、ROM領域に出力されていることが判ります。
ここで使った、プログラム main の一部は以下です。いくつか、SECTION名の異なるデータを作り、どこに配置され、正しく初期化されるかを確かめるプログラムです。初期化が必要なのは、char hogehoge[]="hogehoge"; と、static char hogehoge[]="hogehoge"; です。その他は、ROM領域に配置されます。printf の書式などもROM領域になります。初期化の確認以外に、三角関数や、ベンチマーク( Dhrystone 2.1 ) も入れています。
以上の、プログラム一式を、こちらに置いています。RAM上でテストしているので、実行可能な、ヘキサファイル、test.mot は、0x2000 番地からロードして、0x2000 番地から実行できます。また、このプログラムでは、リセットスタートの初期設定は行っていません。それらは、すでに設定されているものとしており、以下のROM起動のプログラム、で設定されたものとしています。
Hewで作成した、ROM起動のプログラム をフラッシュに書いて、操作したスクリーンショットが以下です。
1、起動後、RX62N-Bug>l ( enter ) で、パソコンから送られる、test.mot を受信待ちにします。
2、パソコンのターミナルから、test.mot を送信します。
3、プログラム( test.mot)を受信すると、0x2000 から、合計 0x257D バイト、メモリにロードされたことが報告されます。
4、RX62N-Bug>g2000 ( enter ) で、0x2000 番地から実行します。
5、各セクションのデータなどを表示します。sin(1) を計算して表示したり、アセンブラを呼び出して、RX62N の一部のレジスタを表示したりします
6、その後、Dhrystone 2.1 のオープニングメッセージを表示して、回数入力待ちになります。(回数はここでは指定できません)
7、( enter ) のみ入力すると、10000回実行して結果を出します。
( enter ) を入力すると、以下の長い報告があって、Dhrystone を1秒間に実行できる回数を報告して、モニタに戻ってきます。
最後の、
ret = 0000148B3
は、Dhrystones per Second: の値のヘキサ値です。これは、g コマンドで戻ってきた場合、リターン値を表示する機能で表示した結果です。
この結果から、RX62N は、かなり早いマイコンで、インターフェイス付録基板の、SH2A ( SH7262 ) と、クロック換算で同じくらいの実行スピードであることが判りました。( SH7262=144MHz, RX62N = 96MHz ) から、RX62N = 1243 Dhrystones/1MHz, SH2A = 1297 Dhrystones/1MHz
SH7262 の Dhrystone 2.1 は、こちらを参照
初期化可能な変数の問題が解決したところで、もう少しROM化の準備をします。RX62Nが、リセットスタートするとき、ベクタテーブルから最初に実行するアドレスを読みますが、その場所が、0xFFFFFFFC 番地の32ビット値です。RX62Nでは、リセットのほか、予約を含めて12個のベクタテーブルがあり、0xFFFFFFD0〜0xFFFFFFFFに割付られ、これらは固定番地となっています。
RX62Nの固定ベクタテーブル
0xFFFFFFD0 |
特権命令例外 |
0xFFFFFFD4 |
予約 |
0xFFFFFFD8 |
予約 |
0xFFFFFFDC |
未定義命令例外 |
0xFFFFFFE0 |
予約 |
0xFFFFFFE4 |
浮動小数点例外 |
0xFFFFFFE8 |
予約 |
0xFFFFFFEC |
予約 |
0xFFFFFFF0 |
予約 |
0xFFFFFFF4 |
予約 |
0xFFFFFFF8 |
ノンマスカブル割り込み |
0xFFFFFFFC |
リセットスタート |
ROM化するには、これらを、ヘキサファイルに出力しないといけませんが、これが単純ではなく、ただ単にROM領域の .rodata SECTION などで指定しても、他のROM化データと一緒にまとめられてしまい、アドレスを特定することができません。
この解決方法は、2つあって、1つは、C言語のソースで書く方法、もうひとつは、アセンブラで記述する方法です。
C言語のソースで書く方法は、先ほどの、 SECTION名の異なるデータ のテストで使っている、
char testsdata2[] __attribute__ ((section (".sdata2"))) ="\r\nthis is SECTION sdata2.\0";
を、.sdata2 ではなく、新たな SECTION ( たとえば、.fixvectors )で宣言して、リンカスクリプトで配置させる方法です。
こんな感じで宣言します。リセットで実行するプログラムは、_start から始まるとして、
リンカスクリプトには、以下の項目を追加します。
こうすることで、12個のベクタテーブルが、0xFFFFFFD0〜0xFFFFFFFF のアドレス付きで、出力されます。
アセンブラの場合はこんな感じになります。リンカスクリプトは同じものを使います。
特殊なレジスタへのアクセスは、アセンブラでしか書けない( asm("") 関数を使えるものもある) ので、アセンブラで記述した、スタートアッププログラム start.s に用意します。RX62N では、リセットスタート直後何も設定しなくてもRAMを使えるので、スタックポインタを設定すれば、後はCの関数でほとんど用が足せるみたいです。スタックの設定だけ済めば main に飛ぶということもできるようですが、ここではいくつかアセンブラで初期設定をします。
まず、割り込みを使わないスタートアップ、start.s
と言っても、割り込みの準備はしておきます
ベクタテーブル、他のアセンブラサブルーチンを追加します。その他、特権命令違反などの、固定ベクタテーブルで示される処理も追加し、例外が起こった時点のレジスタの表示などを行えるようにします。これらを追加したスタートアップは以下のようになります。割り込み処理を含めたこのモニタのデバッグでは、Hewのようにはできないので、いきなり割り込み処理でなにかを行わせるのではなく、割り込みが発生したらモニタなどの処理を中断して、そのときのレジスタなどを表示させてみて、想定通りの結果か否かを先に確かめます。
上記のアセンブラプログラムの makefile 例です。RAM用、ROM用の区別を指示しています。
Cygwinでコンパイル可能な、ソース一式です。rxrommoni.lzh ← は随時変更、修正することがあります。
この中の、mainr.mot を、フラッシュメモリに書くと、このページで解説しているハードウエアで実行可能です。
リセットなどの固定ベクタ以外は、RAMで実行できるコードも作れます。main.mot これをRAMにロードして、g400 でRAMでの同じ処理になりますが、一般の割り込みでは、INTB(RAMでの実行では、0x0に設定しています)に従いますが、未定義命令などの、固定ベクタの例外が起こると、ROMモニタに戻ります。
例外処理に関する操作例を、ファイル説明.txt に書いています。割り込みを受け付けると、その時点のレジスタなどを表示できます。割り込み処理で暗黙に何かを行うというプログラムにはなっていません。
メモリマップ
項目 |
ROM用 mainr.mot アドレス |
RAM用 main.mot アドレス |
固定割り込みベクタ |
0xFFFA0000〜0xFFFA03FF |
0xFFFA0000〜0xFFFA03FF |
割り込みのレジスタ格納 |
0x17DB8〜0x17DFF |
0x17DB8〜0x17DFF |
特権命令違反例外のレジスタ格納 |
0x17E38〜0x17E7F |
0x17E38〜0x17E7F |
未定義命令例外のレジスタ格納 |
0x17EB8〜0x17EFF |
0x17EB8〜0x17EFF |
浮動小数点例外のレジスタ格納 |
0x17F38〜0x17F7F |
0x17F38〜0x17F7F |
ノンマスカブル例外のレジスタ格納 |
0x17FB8〜0x17FFF |
0x17FB8〜0x17FFF |
一般割り込みベクタ |
0xFFFA0000〜0xFFFA03FF |
0x00000000〜0x000003FF |
変数領域 |
0x6000〜0x6158 |
0x8000〜0x8158 |
プログラムのスタート番地 |
0xFFFA0400 |
0x00000400 |
ISP スタック領域 |
0x17D00より下 |
0x17700より下 |
USP スタック領域 |
0x17A00より下 設定されるが、guser で、USP=ISP |
0x17400より下 設定されるが、guser で、USP=ISP |
以下は、このモニタでいくつか操作したスクリーンショットです。
電源ONのプロンプト、RX62N interrupt test... の後、stat で、いくつかレジスタを表示し、
その後、l ( 英小文字の L ) コマンドで、ターミナルから、main.mot が送信されるのを待ちます。
ターミナルソフトから、main.mot の送信が終了すると、start loading .... と報告があるので、
g400 コマンドで、0x400番地から実行します。ROMと同じプログラムなので、プロンプトも同じです。
stat コマンドでレジスタを表示すると、PC ISP USP が異なっているのが判ります。
ここで、ユーザーモードへの移行コマンド、guser を実行すると、
USP = 176B0 と、USP を報告して、プロンプトに戻り、コマンド待ちになります。
ここで、再び、stat コマンドで、レジスタを表示すると、今度は、PSW がユーザーモードになっているのが確認できます。
ここで、さらに、guser コマンドを実行すると、今度は、
mode_1 = 000000D0, mode_2 = 0001766C, mode_3 = 00120001 と、表示されますが、
これは、特権命令違反の例外が発生したので、その報告です。
stat コマンドでレジスタを表示すると、PSW の、ユーザーモードフラグが消えているのが判ります。
そして、例外が発生した時の各レジスタを表示しています。
特権命令違反や、NMI、未定義命令などの例外が起こると、ロードして実行した RAMで動く main.mot から、ROMに戻ります
割り込みの発生を報告できるようになったので、モニタを使って実際に一般の割り込みを発生させてみます。このために、いくつかプログラムを追加します。rxrommoni.lzh では、モニタから PSW の割り込み許可ビットを1にできないからです。その他、割り込みプライオリティーレベルの設定をできるようにします。アセンブラに以下のようなサブルーチンを追加し、モニタから所定の値を引数にして呼び出します。
モニタのソース、main.c の 関数、int optioncmd(char *cp,union param32 *param,int mode_1) の中に追加。
このようにして作成したプログラムはこちらです。テキストですが、中身は .mot ファイルです→ RAM用 main.mot
そのまま RX62N-Bug>l ( enter ) でロードして、RX62N-Bug>g400 ( enter ) で実行可能です。
カウンタで割り込みを発生させてみる。
RX62N のカウンタ割り込み関連のレジスタは、解りにくいマニュアルによると、コンペアマッチタイマコントロールレジスタ、IERレジスタ、IPRレジスタなどの4個の設定になっています。(括弧内) は、Hewでのポート設定です。
1、コンペアマッチタイマコントロールレジスタ ( CMT1.CMCR.WORD = 0x0043; ) 0x88008 番地 ワードライトでビット6を1。例、0x0043
2、IERレジスタ ( IEN( CMT1, CMI1 )=1; ) 0x87203 番地 バイトライトでビット5を1。例、0x20
3、コンペアマッチタイマコントロールレジスタ ( IPR( CMT1, CMI1 )=1; ) 0x87305 番地 バイトライトで1以上0xF以下。例、0x01
4、コンペアマッチタイマスタートレジスタ0 ( CMT.CMSTR0.BIT.STR1=1; ) 0x88000 番地 バイトで0x3を書くと、タイマ1がスタート。
5、割り込み要求レジスタ29 ( ICU.IR[29].BIT.IR ) 0x8701D 番地 バイトで読むと、割り込み要求レジスタ29 IR029 が、割り込みを要求しているかを確認できる。
上記、4、5番目以外を設定しておき、RX62N-Bug>enint ( enter ) で割り込み許可にしておきます。stat で PSW を確かめます。
4番目で、タイマーをスタートさせると、1秒以内に割り込みが発生して、報告されます。
RX62N-Bug>stat ( enter ) で、PSW を読むと、0x100000x になっています。割り込み許可フラグが消え、割り込みプライオリティーレベルが1になっています。
RX62N-Bug>s8701d ( enter ) で、割り込み要求レジスタ29を読むと、再び割り込みが要求されているのが判ります。
RX62N-Bug>enint ( enter ) で、再び割り込み許可にします。しかし、今度は割り込みの報告がなされません。PSW の割り込みプライオリティーレベルが1になっているからです。
RX62N-Bug>sw87305,2 ( enter ) で、タイマー割り込みのプライオリティーレベルを2に上げます。すると、直ちに割り込みの報告が表示されます。
以下の図は、これらの操作のスクリーンショットです。
多重割り込みでLEDの点滅スピードを変化させてみる
|
割り込み対応の準備ができたところで、LEDを点滅させてみます。モニタはそのまま操作できる状態なので、点滅の停止と再開や、インターバルの変更ができるようにします。コマンドは、RX62N-Bug>blink 0 ( enter ) で停止。0以外で再開と同時にスピードを設定可能にします。
単なるLEDの点滅ではおもしろくないので、別のカウンタ割り込みを追加して点滅周期を変更してみます
しかも、点滅周期の変更は、LED点滅の割り込み処理中に、別のカウンタによる『多重割り込み』があった場合のみとします。
このような多重割り込み処理を可能にするには、LED点滅の割り込み処理中に、他の割り込みを受け付けるように、PSWの割り込み許可ビットを1にする必要があります。この処理にはアセンブラ関数が必要ですが、C言語のインラインアセンブラ、asm("..."); を使ってみます。また、LED点滅の割り込み処理中に他の割り込みが起こったか否かの判断には、フラグを使います。いわゆるセマフォーの一種です。割り込み処理は、言わば最も簡単なマルチタスクの形態なので、各タスク間の情報管理に使うと判断に誤りが起こりません。フラグの判定、変更は、割り込み禁止中に行います。でないと、排他的な処理にならず、信号の役目を果たせません。
以下の図は、LED点滅用カウンタ( CMT1 )割り込みと、別のカウンタ( CMT2 )割り込み処理で多重割り込みになる場合のタイミングです。また高速なカウントができる MTU0 ( PCLK プリスケーラ 1/1 )を、おおよその割り込み可能時間の測定に使っています。測定によると、TMU0 で、45〜48カウントになり、割り込み可能時間は、およそ1μ秒であることが判っています。CMT2 のプリスケーラを、PCLK 1/32 に設定すると、0.6666 μ秒単位で、割り込み時間間隔が設定されるので、LED点滅用カウンタ割り込み中に、いつかは割り込めることになります。”いつかは”と言うのはかなり適当な予想です。LED点滅用カウンタ割り込みの PCLK プリスケーラ 1/512 設定と、CMT2 の PCLK プリスケーラ 1/32 設定が、同じプリスケーラカウンタを元にしているので、2個の割り込みタイミングは、PCLK 単位で非同期ではなく、PCLK の32カウント単位の位置で同期することになります。同期しているので、LED点滅用カウンタ割り込みと、CMT2 での割り込みが同時だと、CMT2 が優先されるので、先に割り込み処理が終わってしまって、「LED点滅用カウンタ割り込み中」にはなりません。LEDの点滅処理中に CMT2 が割り込めるのは、LED点滅用カウンタ割り込みが発生して、32 PCLK 後にちょうど CMT2 の割り込みが発生した時です。しかし、ちょうどそのときに CMT2 カウンタがコンペアマッチで満了してくれるのか、否かは、CMT2 のコンペアマッチの設定に依存します。そこで、CMT2 のコンペアマッチ数をモニタで設定できるようにして、どのような設定のとき、多重割り込みを発生できるのかを調査できるようにしました。
CMT1と、CMT2の割り込み処理関数。
と、こんな感じになります。
Cygwin プログラムソース一式 旧 rxromintn.lzh ←SDカード操作にバグあり。
Cygwin プログラムソース一式 旧 rxromintn_120112.lzh ←CRC有効で、バグあり。2012.1.12
Cygwin プログラムソース一式 rxromintn_120118.lzh ←バグ修正。2012.1.18
この中の、main.mot をRAMにロードして、g400 で実行します。
操作のスクリーンショットは以下です。CMT2 のプリスケーラ、コンペアマッチ数を、それぞれ PCLK = 1/32 , コンペアマッチ数 = 101 とすると、約5秒間隔で、多重割り込みを発生できます。そのたびに、LEDの点滅スピードが、10回/1秒と、2.5回/1秒と、変化します。多重割り込みが発生した回数は、
RX62N-Bug>blink s ( enter ) コマンドで確認できます。下図の、multiint = 0x00000004 などが結果の報告です。
この図の中ほどに、00008144 = FEF1FED3 と表示されていますが、これは、TMU0 のカウントを、読んだ値です。LSB 0xFED3がLED割り込み直後、MSB 0xFEF1が、割り込み禁止直後の値です、差は0x2Eで46カウントです。48MHzで1カウントですから、約1μ秒であることがわかります。
工事中
ホーム に戻る