忍者ブログ

Fグループ電子工作講座

秋月電子SH7125ボードで始めるマイコン開発

タイマー割込(CMT)の設定

タイマ割込とは

マイコンの処理では待機処理を行わず高速で無限ループします。
従って何か処理を行うと即座処理が反映されます。

しかし、入力が加わって一定時間後に次の処理を行いたい場合もあります。(遅延処理)
遅延処理に関してはループ部分の繰り返し回数をカウントし、一定数カウントしたら処理を行う事である程度対応することができます。
しかし、ループ内の処理は様々な条件分岐を行うことになるため条件次第ではループ一回に要する時間が大きく変化します。より正確な時間で遅延処理を行いたい場合はこの方法は使用できません。

また、速度系の処理を行う場合はループの周期自体を安定させる必要があります。
この場合は一定時間ごとにループを実行するように設定する必要があります。
for文等を使って待機させることも出来ますが、待機中は処理を行う事ができません
また、ループ周期は「待機時間1ループの処理時間」となるため、やはりループ内の分岐によっては処理時間が変化するためループ周期を十分安定させる事はできません。
そこでタイマー割込Compare Match Timer)を使用します。

原理

タイマー割込処理の動作原理はシンプルです。
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系統のカウンタCMT0CMT1があります。

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    0x000000F0

#define SR_Init    0x00000000
へ変更します。

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 CMI0
void 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の特殊機能一覧
PR

コメント

プロフィール

HN:
ぼんどF博士
性別:
男性

最新コメント