原理
タイマー割込処理の動作原理はシンプルです。
CPUのクロックをカウントしていき、
設定した目標値と
比較して一致した(コンペアしてマッチしたら)ら割り込みが発生します。
割り込みが発生した時にカウンタをリセット再スタートすれば再度カウントが始まります。
これで
1クロックの時間×設定値毎に割り込みが発生することになります。
クロックのカウントは
メインプログラムとは独立して動作するためメイン処理で何をさせても
割込が発生する周期が変化する事は無く安定しています。
※RX220向けの情報は
こちら
SH7125の設定
設定する内容を大まかに分けると3つ
CMTの初期化関数1.CPUのクロックが
n回動作したら
カウンターを1アップする機能設定
2.カウンターの
目標値設定
3.カウンターが目標値に到達したら
カウンタをリセット再スタートする機能設定
タイマ割込は
マイコン内部で完結する処理なので、マイコンの
端子の特殊機能設定はありません。
1.CPUのクロックがn回動作したらカウンターを1アップする機能設定
<設定>void init_CMT0(int T)
//ミリ秒単位で割り込みを設定する{
long int LN;
//目標値 // CMT0の割り込みレベル(優先順位)を設定 INTC.IPRJ.BIT._CMT0 = 0xA;
// ※(0x0:最低~0xF:最高) STB.CR4.BIT._CMT=0;
// CMTモジュールのスタンバイ解除 //設定中なのでカウンター一時停止
CMT.CMSTR.BIT.STR0=0;
// 0:カウント停止, 1:カウント開始 CMT0.CMCSR.BIT.CMIE=1;
// コンペアマッチ割り込み許可 ※1で割り込みを行う CMT0.CMCSR.BIT.CKS=2;
// クロックセレクト[1,0] 10=>2:Pφ/128<用語>
INTC:割り込みコントローラ。
STB:スタンバイレジスタ
AD変換やPWMの設定の際に使用したものと同じです。
CMT:コンペアマッチタイマ
タイマー割り込み用カウンターの機能名です。
2系統のカウンタ
CMT0と
CMT1があります。
CMSTR:コンペアマッチスタートレジスタ。カウントの停止or実行を指定します。0で停止、1で実行。
STR0:スタートレジスタ0。CMT0の停止実行を指示します。
STR1:スタートレジスタ1。CMT1の停止実行を指示します。
CMCSR:コンペアマッチタイマ コントロールステータスレジスタ。割り込み許可やクロックなどの設定を行います。
CMIE:コンペアマッチ割り込みイネーブル。割り込みを動作させるかの設定をします。
CKS:クロックセレクト。クロックをカウントする周期を設定します。
<解説>この関数に入力した時間(ミリ秒単位)でタイマ割り込みが発生するように設定します。
また、入力した時間をカウントの目標値へ変換するため、変数を用意しておきます。
クロックカウントの周期は今回
Pφ/128としました。
クロックカウントの周期を小さいまま使用すると、より細かい時間設定を行えるようになります。しかし、内部でクロックをカウントするための変数のカウント上限があるため設定したい時間をカウントできなくなる可能性もあります。
マイコンボードの25MHzクロックを使用した場合の分解能と最大設定時間は以下となります。
設定値 / 周期 /分解能 /最大設定時間
0b00(0) / Pφ/8 / 0.32μ秒 / 21m秒
0b01(1) / Pφ/32 / 1.28μ秒 / 84m秒
0b10(2) / Pφ/128 / 5.12μ秒 / 335m秒
0b11(3) / Pφ/512 / 20.58μ秒 / 1342m秒
2.カウンターの目標値設定
//CMCORの値を算出 Tミリ秒→LNカウント LN = 195312 * T/1000;
// 25MHz/128=195312Hz(1カウント5.12μs) if(LN < 1) LN = 1;
else if(LN > 0xffff) LN = 0xffff;
//335msに相当 CMT0.CMCNT = 0;
// カウンタリセット CMT0.CMCOR = (int)LN;
// カウント目標値セット CMT.CMSTR.BIT.STR0=1;
// CMT0カウント開始}
<用語>CMCNT :カウント値
CMCOR :目標値
<解説>カウンタの目標値を設定します
まずカウンタの目標値を計算しておきます。
CMT0.CMCSR.BIT.CKS にてクロックの1//128の周期でカウントする設定にしたため1カウントの周期は5.12μ秒、195312カウントで1秒となります。
カウント値が1以下と計算された場合の保護のため1以下の場合は1に設定しています。
また、最大値は0xFFFFなので335msに相当します。
これでタイマ割り込みCMI_0が動作するようになりました。
タイマ割り込みの初期化はここまでです。
3.割り込み動作の有効化
PWMの時と同様に初期状態では割り込みを受け付けないように設定されているので、割り込みを有効化しておきます。
resetprg.cの36行目付近
#define SR_Init 0x000000
F0
を
#define SR_Init 0x000000
00
へ変更します。
4.タイマ割り込み関数
SH7125では設定を行った
割り込み条件を満たしたときに、その割り込み条件に対して
特定の場所に記載された関数が実行されるように設定されています。
ハードウェアマニュアルの
割り込み例外処理ベクタテーブルの項によると
CMT0のコンペアマッチによる割り込みCMI_0は
ベクタ番号184にて実行されます。
CMI_1は
ベクタ番号188にて実行されます。
これに相当する設定がSH7125のプロジェクトを作成した際に自動生成されている
vecttbl.cに記載されています。
CMI_0割り込みが発生すると184番目の
INT_CMT0_CMI0が実行されます。
この関数はvect.hで宣言され、実体は
intprg.cに記載されています。
intprg.cで
INT_CMT0_CMI0を検索すると関数の実体が見つかりますが、
// 184 CMT0 CMI0void
INT_CMT0_CMI0(void){
/* sleep(); */}
となっており、関数の中身は
コメントしかないので結局
何も実行されません。
そこで、関数
INT_CMT0_CMI0の中に
実行したい内容を記述しておけば目的の動作となります。
しかし、intprg.cに各割り込みにて
実行したい内容を片っ端から書いていくと、
行数が増えに増えて非常に読みづらくなります。
そこで、
実行したい内容をまとめて記述した関数を作成し、INT_CMT0_CMI0の中にはその
1つの関数を実行するという1行だけ記述します。
これでintprg.cの中身は最小限に抑えられます。また、実行したい内容を割り込みの初期化処理等を記載した場所に並べて書くことができます。
割り込み関数の中身
INT_CMT0_CMI0内で実行される関数として
CMT0_INT_CMIを作成します。
関数名は何でも構いません。<設定>unsigned long _systimer=0;
//システム時刻void CMT0_INT_CMI(void)
{
CMT0.CMCSR.BIT.CMF=0;
// CMT0リスタート _systimer++;
//システム時刻増加}
システムタイマー取得関数
中身はカウンタをリスタートし、自前で用意した変数_systimerを1つ増やすだけにしています。
動作確認用としてLEDの点滅設定を作成しておきます。
システム時刻の取得関数
unsigned long getsystime(void){
return _systimer;
}
この関数を実行すればシステム時刻を取得できます。
ソースファイル、ヘッダファイルの作成
CMTに関する設定が出揃ったところで、CMTの使いまわしができるようにこれらの設定を独立したファイルとして作成します。
ソースファイルの中身:関数の実体、グローバル変数の宣言
ヘッダファイルの中身:define、関数のプロトタイプ宣言
詳細は以下のファイルを確認してください。
ダウンロード:ソースファイル
ダウンロード:ヘッダファイル
割り込み関数の登録
CMT0の設定はintprg.cの379行目付近
void INT_CMT0_CMI0(
void){
/* sleep(); */}
を
void INT_CMT0_CMI0(
void){
CMT0_INT_CMI();}
に修正します。
CMT1の設定は387行目付近
void INT_CMT1_CMI1(
void){
/* sleep(); */}
を修正します。
これでタイマー割込を使用する準備ができました。
次回はプログラムを実行してみます。
関連:
当ブログで扱うSH7125の特殊機能一覧