Renesas RX621 Timer割り込み
Timer割り込みとは、メインのプログラム実行から周期的(タイマー的)に割り込みプログラムを実行する機能です。
このため、プログラムを周期的に行いたい時や何かイベントが発生した時に実行したい時に割り込みは使用されます。
今回は周期的にプログラムを実行するTimer割り込みについて説明していきます。
(イベント: AD変換完了、通信においてデータ受信or送信、インプットキャプチャ(状態変化)等があげられます。)
それでは、CMT(コンペアマッチタイマー)機能を用いて、Timer割り込みの設定をしていきたいと思います。
まず、e2 stduio左側プロジェクトエクスプローラのプロジェクトフォルダ内のsrcフォルダを右クリックし,
新規→ソース・ファイルからCMT.c
新規→ヘッダ・ファイルからCMT.h
を作成します。
ソースコードの追加はプロジェクトファイルのsrcフォルダに直接作成することでも可能です。
つぎに、hardware_setup.cにてCMT.hをインクルードし、HardwareSetup関数でCMT.cのCMT0_initialize関数とCMT1_initialize関数を呼びます。
CMT.h
#ifndef CMT_H_ #define CMT_H_ void CMT0_initialize(void); void CMT1_initialize(void); #endif /* CMT_H_ */
CMT.c
#include "iodefine.h" #include "machine.h" #include "vect.h" #include "CMT.h" #pragma interrupt (timer0(vect=VECT(CMT0, CMI0))) #pragma interrupt (timer1(vect=VECT(CMT1, CMI1))) void CMT0_initialize(void); void CMT1_initialize(void); void timer0(void){ static unsigned char timer0cnt; if(timer0cnt == 10){ PORTA.DR.BIT.B2 ^= 1; timer0cnt = 0; } timer0cnt++; } void timer1(void){ static unsigned char timer1cnt; if(timer1cnt == 10){ PORTA.DR.BIT.B3 ^= 1; timer1cnt = 0; } timer1cnt++; } void CMT0_initialize(void) { // CMT0 5ms MSTP(CMT0) = 0; // Wake up CMT0 CMT0.CMCR.BIT.CMIE = 1; // Enable interrupt CMT0.CMCR.BIT.CKS = 0; // PCLK/8 CMT0.CMCOR = 29999; // Time interval 5ms IPR(CMT0, CMI0) = 3; // Interrupt level 3 IEN(CMT0, CMI0) = 1; // Enable CMT0 interrupt CMT.CMSTR0.BIT.STR0 = 1; // CMT0 counter start } void CMT1_initialize(void) { // CMT1 10ms MSTP(CMT1) = 0; // Wake up CMT1 CMT1.CMCR.BIT.CMIE = 1; // Enable interrupt CMT1.CMCR.BIT.CKS = 0; // PCLK/8 CMT1.CMCOR = 59999; // Time interval 10ms IPR(CMT1, CMI1) = 4; // Interrupt level 4 IEN(CMT1, CMI1) = 1; // Enable CMT1 interrupt CMT.CMSTR0.BIT.STR1 = 1; // Counter start }
つぎに、vect.hの
// CMT0 CMI0 #pragma interrupt (Excep_CMT0_CMI0(vect=28)) void Excep_CMT0_CMI0(void); // CMT1 CMI1 #pragma interrupt (Excep_CMT1_CMI1(vect=29)) void Excep_CMT1_CMI1(void);
をすべてコメントアウトします。
この状態でビルドを行い、LEDが点滅すれば成功です。
それではCMTの設定を見ていきます。今回はCMT0,CMT1の設定の違いはタイマークリア値のみなので、CMT0について説明していきます。
- モジュールスタート(消費電力低減機能の解除)
- ピンの設定
- CMTの設定
- ユーザ関数の定義
1.モジュールスタート(消費電力低減機能の解除)
MSTP(CMT1) = 0; // Wake up CMT1
消費電力低減機能を解除します。RX631のようにアクセスロックはないので、そのまま解除します。
MSTPCTRレジスタがiodefine.hでMSTP(****)というようにデファインされているのでこれを使用します。
2.ピンの設定
今回CMTと連動するピンはないので設定はありません。
3.CMT0の設定
データシートp.1133の図22.3とその説明を参考にします。
CMT0.CMCR.BIT.CMIE = 1; // Enable interrupt CMT0.CMCR.BIT.CKS = 0; // PCLK/8 CMT0.CMCOR = 29999; // Time interval 5ms IPR(CMT0, CMI0) = 3; // Interrupt level 3 IEN(CMT0, CMI0) = 1; // Enable CMT0 interrupt CMT.CMSTR0.BIT.STR0 = 1; // CMT0 counter start
CMT0のTimer割り込みの設定は
CMCRレジスタの
CMIE: 1→割り込みを許可
CKS: 0→タイマカウント周期をPCLK/8
CMT0レジスタの
CMCOR: 29999→タイマクリアカウントを29999に設定し、5ms周期でタイマカウントがクリアされるようにする
CMTSTR0レジスタの
STR0: 1→CMT0のカウントをスタートする。
となり、割り込みの設定は
IPR(CMT0, CMI0) = 3; // Interrupt level 3 IEN(CMT0, CMI0) = 1; // Enable CMT0 interrupt
とします。RX621はICUにより、すべての割り込みが管理されています。
ICUのIENレジスタに各割り込みに対しての、許可ビットが存在し、IPRレジスタに各割り込みに対しての、割り込み優先度を設定するビットが存在します。
そしてこのIENレジスタとIPRレジスタは各割り込み毎にIPR(割り込み名)、IEN(割り込み名)というようにiodefine.hでマクロされていますのでこれを使用します。
これで割り込みを含め、Timer割り込みの設定が完了しました。
4.ユーザ関数の定義
#include "vect.h" #pragma interrupt (timer0(vect=VECT(CMT0, CMI0))) #pragma interrupt (timer1(vect=VECT(CMT1, CMI1)))
各割り込みで呼ばれる割り込み関数はvect.hですべて定義されています。
そのため、vect.hのCMT0とCMT1のコンペアマッチで発生する割り込み(コンペアマッチ割り込み)の該当部分をコメントアウトし、CMT.hでTimer割り込みすべてを完結できるようにします。
ここで
#pragma interrupt ((割り込み関数名)(vect=(割り込みベクタ番号)))
というように定義することで、ベクタ番号とベクタ番号に対応し割り込み発生時に呼ばれる関数を定義することができます。
ベクタ番号とは各割り込みに対して呼ばれる関数にすで番号が振られており、それをベクタ番号といい、VECT(割り込み名)でiodefine.hでマクロされているのでこれを使用します。
今回はCMT0のコンペアマッチ割り込みの関数としてtimer0を、CMT1のコンペアマッチ割り込みの関数としてtimer1を作成しました。
ここでtimer0関数は5ms毎に呼ばれ10回目でLEDを点滅させるので50msおきにLEDを点滅させます。
同様にtimer1関数は10ms毎に呼ばれ10回目でLEDを点滅させるので100msおきにLEDを点滅させます。
Timer割り込みの設定はこれで完了です。多重割り込み等は
embedded-blog.ccwo.net
を参照して下さい。
20160822の記事