H8マイコンで割り込みしよう2 デバックモニタ上で割り込みの実現をしてみる 後編 [RX&SH&H8]
ええっと、前回は何をしたんだっけ。ああそうか、デバックモニタ上でプログラムを実行する時のメモリイメージを描いたのですね。
では、実際にプロジェクトを作成してみます。
今回も新たにプロジェクトを生成します。ここでやった手順でプロジェクトを作成してください。
http://hamayan.blog.so-net.ne.jp/2009-06-07-1
最終的にはこの様にHEWが起動しています。
左のペインの中で表示されている幾つかのファイルの内、「mon_int_sample.c」はこのプロジェクトを生成した時のプロジェクト名がそのまま関数mainを含むファイルとしてウイザードが生成したものですが、更に自分で「vector.c」と「startup.c」と言うファイルを追加しています。
それではこれら2つのファイルの内容を以下に掲載します。
vector.c
startup.c
「vector.c」の中身はhttp://hamayan.blog.so-net.ne.jp/2009-06-12-1で紹介した「intprg.c」の中身に似ていますが、若干の違いが有ります。
例えば「intprg.c」の中でTimer A オーバーフロー割り込みは以下の様に記載されていました。
しかしこの「vector.c」では以下の様に記述しています。
__interruptと#pragma interruptは同じ意味で、後ろに続く関数を割り込み関数として認識させるものです。
ここでの大きな違いは(vect=19)の有り/無しです。これは前にも解説したように割り込みベクター番号19の位置に関数の先頭アドレスを埋め込む様に指示している宣言です。
なのでhttp://hamayan.blog.so-net.ne.jp/2009-06-12-1では特に割り込みベクターテーブルの記述を行っていません。
ではデバックモニタで割り込みを使用する時もHEWのウイザードが生成した「intprg.c」を使えばよいじゃないか!と思われるでしょうけれど、そうは行かないのです。
(vect=?)を使う方法はデバックモニタ上にプログラムをロードする上で問題が発生します。つまり埋め込み先はFLASH ROM領域であり、幾らデバックモニタ上にロードしてもFLASH ROMの内容までは書き換える事ができません。このプログラムを無理やり実行するとおそらくデバックモニタは不正な割り込みが発生した!とメッセージを出力し、そこで実行を停止するでしょう。
そこで今回の「vector.c」なのですが、この場合は関数が割り込み処理である事は宣言していますが、メモリ上のどの位置に割付すると言った情報は一切記載されていません。この割付に関してはビルド時にコンパイラの後の処理で実行されるリンカーに一任しています。コンパイラはいわゆるリロケータブルなオブジェクトファイルを生成します。
※これは、随分前に戻ってしまいますが、http://hamayan.blog.so-net.ne.jp/2009-06-03で紹介したワークフローの中でコンパイラからリロケータブルオブジェクトファイルを生成して、それが最適化リンケージエディタに読み込まれるまでの流れですね。
もう一つ、「startup.c」ですが、こちらは「resetprg.c」に相当するファイルです。「resetprg.c」を開いてみて下さい。あちこちコメントアウトしてあって実に読み難いファイルですが、ポイントは以下の宣言です。
__entry(vect=0) void PowerON_Reset(void);
__interruptの記述に似ていますが、__entry(または#pragma entry)はリセット時専用の宣言です。
この宣言で修飾された関数はリセット直後に実行される関数として認識され、関数の先頭に自動的にスタックポインタの初期化が挿入されます。
試しに「resetprg.c」のコンパイル時にアセンブラリスト出力を行うコンパイルオプションを設定して内容を見てみます。※実際の出力から無関係な記述は省略されています。
MOV.W #STARTOF S+SIZEOF S,R7
は、スタック領域として使用されるSセクションの先頭アドレスにスタックサイズを加算した値を、スタックポインタとして使用されるR7レジスタに代入しています。
もちろん「startup.c」でも関数「startup」で初っ端にスタックポインタの設定を行っています。この場合はBSTKと言うセクションを使用しており、BSTKの実体はこの「startup」の下に続く領域の宣言としてSTKセクションを宣言しています。
※H8のコンパイラではC言語でセクションを宣言した場合、自動的に頭に
P:プログラムコードの意味。
C:定数の意味。
D:初期化付き変数の意味。
B:0クリアのみの変数の意味。
が付加されます。
そして、
__entry(vect=0)
と記述されているところから判る様に、この宣言もまた絶対アドレスで0x0000を示しており、デバックモニタ上ではこの情報を正常にロードする事ができません。やはりスタートアッププログラムもリロケータブルである必要があります。
ちなみに、実はデバックモニタ上でユーザープログラムを実行する時は特にプログラムの初っ端でスタックポインタの設定をする必要がありません。実はです(笑)。
デバックモニタからユーザプログラムへCPUの実行が移る時、デバックモニタが適当なスタックポインタを設定してくれています。
だからスタックポインタの設定を一切行っていない”Hello World”プログラムが何の問題も無く動いたのです。
話が長くなって書いている本人が疲れたので、ここからは飛ばします。
ツールチェインのダイアログを開いて以下のポイントを変更します。
HTERMを起動し、デバックモニタが書かれているH8マイコンと接続し、今回作成したプログラムのロードを行うと画面の様になります。
黄色くハイライトされている行がPCの位置を表し、ステップ実行等を行えばこの黄色い帯も移動します。
※このプログラムは、ポートにLEDを接続しておくと、実行した時にLEDがチカチカします。
※実際のところ「vector.c」や「startup.c」は決まりきった記述、決まりきった処理なので、デバックモニタ上で動くプログラムを作成したくなったら、今回の手順でプロジェクトを生成し、上の「vector.c」と「startup.c」をコピーし、適当に編集して使うとよいと思います。
では、実際にプロジェクトを作成してみます。
今回も新たにプロジェクトを生成します。ここでやった手順でプロジェクトを作成してください。
http://hamayan.blog.so-net.ne.jp/2009-06-07-1
最終的にはこの様にHEWが起動しています。
左のペインの中で表示されている幾つかのファイルの内、「mon_int_sample.c」はこのプロジェクトを生成した時のプロジェクト名がそのまま関数mainを含むファイルとしてウイザードが生成したものですが、更に自分で「vector.c」と「startup.c」と言うファイルを追加しています。
それではこれら2つのファイルの内容を以下に掲載します。
vector.c
#include <machine.h> #include "iodefine.h" void startup( void ); /*BOOT処理*/ #pragma interrupt(abort) /*NMI*/ void abort( void ){} #pragma interrupt(TRAP0) /*トラップ命令#0*/ void TRAP0( void ){} #pragma interrupt(TRAP1) /*トラップ命令#1*/ void TRAP1( void ){} #pragma interrupt(TRAP2) /*トラップ命令#2*/ void TRAP2( void ){} #pragma interrupt(TRAP3) /*トラップ命令#3*/ void TRAP3( void ){} #pragma interrupt(ADRBRK) /*アドレスブレーク*/ void ADRBRK( void ){} #pragma interrupt(CPUSLEEP) /*スリープ命令実行による直接遷移*/ void CPUSLEEP( void ){} #pragma interrupt(IRQ0) /*外部割込み端子0*/ void IRQ0( void ){} #pragma interrupt(IRQ1) /*外部割込み端子1*/ void IRQ1( void ){} #pragma interrupt(IRQ2) /*外部割込み端子2*/ void IRQ2( void ){} #pragma interrupt(IRQ3) /*外部割込み端子3*/ void IRQ3( void ){} #pragma interrupt(WKP) /*外部割込み端子WKP*/ void WKP( void ){} #pragma interrupt(TAOVI) /*タイマーAオーバーフロー*/ void TAOVI( void ) { IRR1.BIT.IRRTA = 0; /*割込み条件のクリア*/ IO.PDR8.BIT.B0 ^= 1; /*LEDチカチカ*/ } #pragma interrupt(TIMERW) /*タイマーW*/ void TIMERW( void ){} #pragma interrupt(TIMERV) /*タイマーV*/ void TIMERV( void ){} #pragma interrupt(SCI_3) /*シリアル*/ void SCI_3( void ){} #pragma interrupt(IIC_2) /*I2C*/ void IIC_2( void ){} #pragma interrupt(ADI) /*A/D*/ void ADI( void ){} #pragma section VECT /* 仮想ベクタテーブル */ void (*const VEC_TBL[])(void) = { startup, /*Vector 0 Reset Vector*/ (void *)0, /*Vector 1*/ (void *)0, /*Vector 2*/ (void *)0, /*Vector 3*/ (void *)0, /*Vector 4*/ (void *)0, /*Vector 5*/ (void *)0, /*Vector 6*/ abort, /*Vector 7*/ TRAP0, /*Vector 8*/ TRAP1, /*Vector 9*/ TRAP2, /*Vector 10*/ TRAP3, /*Vector 11*/ ADRBRK, /*Vector 12*/ CPUSLEEP, /*Vector 13*/ IRQ0, /*Vector 14*/ IRQ1, /*Vector 15*/ IRQ2, /*Vector 16*/ IRQ3, /*Vector 17*/ WKP, /*Vector 18*/ TAOVI, /*Vector 19*/ (void *)0, /*Vector 20*/ TIMERW, /*Vector 21*/ TIMERV, /*Vector 22*/ SCI_3, /*Vector 23*/ IIC_2, /*Vector 24*/ ADI, /*Vector 25*/ };
startup.c
#include <machine.h> void main( void ); void startup( void ) { #pragma asm MOV.W #(STARTOF BSTK) + (SIZEOF BSTK),R7 #pragma endasm // set_imask_ccr(1); /*全体の割り込み禁止*/ _INITSCT(); main(); while(1) ; } /***********************************************************/ /* スタック領域として領域の確保を行う。 */ /***********************************************************/ #pragma section STK static char stack_area[256];
「vector.c」の中身はhttp://hamayan.blog.so-net.ne.jp/2009-06-12-1で紹介した「intprg.c」の中身に似ていますが、若干の違いが有ります。
例えば「intprg.c」の中でTimer A オーバーフロー割り込みは以下の様に記載されていました。
__interrupt(vect=19) void INT_TimerA(void) { IRR1.BIT.IRRTA = 0; /*割込み条件のクリア*/ IO.PDR8.BIT.B0 ^= 1; /*LEDチカチカ*/ }
しかしこの「vector.c」では以下の様に記述しています。
#pragma interrupt(TAOVI) /*タイマーAオーバーフロー*/ void TAOVI( void ) { IRR1.BIT.IRRTA = 0; /*割込み条件のクリア*/ IO.PDR8.BIT.B0 ^= 1; /*LEDチカチカ*/ }
__interruptと#pragma interruptは同じ意味で、後ろに続く関数を割り込み関数として認識させるものです。
ここでの大きな違いは(vect=19)の有り/無しです。これは前にも解説したように割り込みベクター番号19の位置に関数の先頭アドレスを埋め込む様に指示している宣言です。
なのでhttp://hamayan.blog.so-net.ne.jp/2009-06-12-1では特に割り込みベクターテーブルの記述を行っていません。
ではデバックモニタで割り込みを使用する時もHEWのウイザードが生成した「intprg.c」を使えばよいじゃないか!と思われるでしょうけれど、そうは行かないのです。
(vect=?)を使う方法はデバックモニタ上にプログラムをロードする上で問題が発生します。つまり埋め込み先はFLASH ROM領域であり、幾らデバックモニタ上にロードしてもFLASH ROMの内容までは書き換える事ができません。このプログラムを無理やり実行するとおそらくデバックモニタは不正な割り込みが発生した!とメッセージを出力し、そこで実行を停止するでしょう。
そこで今回の「vector.c」なのですが、この場合は関数が割り込み処理である事は宣言していますが、メモリ上のどの位置に割付すると言った情報は一切記載されていません。この割付に関してはビルド時にコンパイラの後の処理で実行されるリンカーに一任しています。コンパイラはいわゆるリロケータブルなオブジェクトファイルを生成します。
※これは、随分前に戻ってしまいますが、http://hamayan.blog.so-net.ne.jp/2009-06-03で紹介したワークフローの中でコンパイラからリロケータブルオブジェクトファイルを生成して、それが最適化リンケージエディタに読み込まれるまでの流れですね。
もう一つ、「startup.c」ですが、こちらは「resetprg.c」に相当するファイルです。「resetprg.c」を開いてみて下さい。あちこちコメントアウトしてあって実に読み難いファイルですが、ポイントは以下の宣言です。
__entry(vect=0) void PowerON_Reset(void);
__interruptの記述に似ていますが、__entry(または#pragma entry)はリセット時専用の宣言です。
この宣言で修飾された関数はリセット直後に実行される関数として認識され、関数の先頭に自動的にスタックポインタの初期化が挿入されます。
試しに「resetprg.c」のコンパイル時にアセンブラリスト出力を行うコンパイルオプションを設定して内容を見てみます。※実際の出力から無関係な記述は省略されています。
22: __entry(vect=0) void PowerON_Reset(void); 54: #pragma section ResetPRG 55: 56: __entry(vect=0) void PowerON_Reset(void) 0000 _PowerON_Reset: ; function: PowerON_Reset 0000 79070000 MOV.W #STARTOF S+SIZEOF S,R7 57: {
MOV.W #STARTOF S+SIZEOF S,R7
は、スタック領域として使用されるSセクションの先頭アドレスにスタックサイズを加算した値を、スタックポインタとして使用されるR7レジスタに代入しています。
もちろん「startup.c」でも関数「startup」で初っ端にスタックポインタの設定を行っています。この場合はBSTKと言うセクションを使用しており、BSTKの実体はこの「startup」の下に続く領域の宣言としてSTKセクションを宣言しています。
※H8のコンパイラではC言語でセクションを宣言した場合、自動的に頭に
P:プログラムコードの意味。
C:定数の意味。
D:初期化付き変数の意味。
B:0クリアのみの変数の意味。
が付加されます。
そして、
__entry(vect=0)
と記述されているところから判る様に、この宣言もまた絶対アドレスで0x0000を示しており、デバックモニタ上ではこの情報を正常にロードする事ができません。やはりスタートアッププログラムもリロケータブルである必要があります。
ちなみに、実はデバックモニタ上でユーザープログラムを実行する時は特にプログラムの初っ端でスタックポインタの設定をする必要がありません。実はです(笑)。
デバックモニタからユーザプログラムへCPUの実行が移る時、デバックモニタが適当なスタックポインタを設定してくれています。
だからスタックポインタの設定を一切行っていない”Hello World”プログラムが何の問題も無く動いたのです。
話が長くなって書いている本人が疲れたので、ここからは飛ばします。
ツールチェインのダイアログを開いて以下のポイントを変更します。
HTERMを起動し、デバックモニタが書かれているH8マイコンと接続し、今回作成したプログラムのロードを行うと画面の様になります。
黄色くハイライトされている行がPCの位置を表し、ステップ実行等を行えばこの黄色い帯も移動します。
※このプログラムは、ポートにLEDを接続しておくと、実行した時にLEDがチカチカします。
※実際のところ「vector.c」や「startup.c」は決まりきった記述、決まりきった処理なので、デバックモニタ上で動くプログラムを作成したくなったら、今回の手順でプロジェクトを生成し、上の「vector.c」と「startup.c」をコピーし、適当に編集して使うとよいと思います。
ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発
- 作者: 濱原 和明
- 出版社/メーカー: オーム社
- 発売日: 2005/04/25
- メディア: 単行本
2009-06-16 23:56
nice!(0)
コメント(0)
トラックバック(0)
コメント 0