MTU2の使い方(その1)
MTU2の使い方 1
MTU2とは
MTU2とはMultifunction Timer-pulse Unit 2の略であり、タイマ動作やパルス出力、PWM制御などの機能を備えた、多機能モジュールである。
以前に学習したCMTは、MTU2のごく一部分の機能で代替えすることが可能である。
MTU2はCH0~CH5の6チャネルで構成されており、各チャネルは16ビットカウンタと各種レジスタ、入出力端子などから構成されている。
CMTのようなクロックカウントによるコンペアマッチの他に
- 外部クロックをカウント可能
- コンペアマッチによる波形出力
- A/D変換器の変換スタート
- DMA/DTCの起動
- PWM出力
- 複数のチャネルを組み合わせての複雑な動作
など多機能である。
このテキストでは代表的と思われる使用方法2つ(周期タイマ、A/D変換器の起動)について説明している。より詳しく知りたい場合はCPUのハードウェアマニュアルを参照してほしい。
モジュールスタンバイ
他の機能モジュールと同様に、MTU2も初期状態ではスタンバイモードになっている。SH7085では、使用しない機能モジュールへのクロック供給を断つことにより、消費電力を低減している。
MTU2を使用可能にするには、モジュールのスタンバイモードを解除する必要がある。スタンバイコントロールレジスタ4(STB.CR4)のビット6を0にすることにより、MTU2モジュールへのクロックが供給されて、使用可能状態になる。
図1:STBCR4レジスタ
図1は、ハードウェアマニュアルに記載されている名称である。HEWにおいてiodefine.hを使う場合は、次のような構造体と共用体を使用する。
struct st_stb { union { unsigned char BYTE; struct { unsigned char STBY:1; } BIT; } CR1; ~中略~ union { /* STBCR4 */ unsigned char BYTE; /* Byte access */ struct { /* Bit access */ unsigned char _MTU2S :1; /* MTU2S */ unsigned char _MTU2 :1; /* MTU2 */ unsigned char _CMT :1; /* CMT */ unsigned char :2; unsigned char _AD2 :1; /* A/D 2 */ unsigned char _AD1 :1; /* A/D 1 */ unsigned char _AD0 :1; /* A/D 0 */ } BIT; } CR4; ~中略~ };
#define STB (*(volatile struct st_stb*)0xFFFFE802) /* STB Address */
MTU2のモジュールスタンバイを操作するには、下記のようなプログラムになる。
STB.CR4.BIT._MTU2 = 0; // モジュールスタンバイ解除 STB.CR4.BYTE &= 0xbf; // モジュールスタンバイ解除
MTU2の構成
ハードウェアマニュアルを参照すると、MTU2を構成するレジスタの数は1チャネルあたり10以上ある。しかし全てのレジスタを操作しなくとも、必要なレジスタだけを設定することで動かすことができる。
ここでは基本的な動きのみを解説し、各々の動作に必要なレジスタについては、その都度解説することとする。
① MTU2は内部のクロック(Pφ)を分周したクロックをカウントすることができる。また、外部端子からクロックを与えて、それをカウントすることも可能である。
カウントクロックの選択はタイマコントロールレジスタ(MTU2x.TCR : xはチャネル番号)のビット2~0で行う。
② 選択したクロックによりTCNTはカウントアップをするが、ジェネラルレジスタTGRxのうちの一つの設定値と一致したときに0クリアするように設定することができる。この設定により0, 1, 2, …, 0, 1, 2とカウントが一周する周期を決めることができる。
③ ジェネラルレジスタに設定した値は、TCNTのクリア条件に使われたり、A/D変換器のトリガ条件として使われたりする。
④ カウントのスタート/ストップはタイマスタートレジスタ(MTU2.TSTR)で行う。このレジスタはMTU2のチャネル0~チャネル4で共用である。各チャネルに該当するビットを0にするとカウント停止、1にするとカウント開始する。
MTU2のチャネル5は、独立したスタートレジスタMTU2.TSTR_5を持っているが、説明は省略する。
このビットを操作することにより、TCNTの値が0にクリアされることはない。よって、TCNTの値が0以外の時にカウントを停止し、TCNTを0クリアせずにカウントを再開した場合、周期が狂うことになるので、注意が必要である。
⑤ タイマステータスレジスタ(MTU2x.TSR)のビット0~ビット3で、カウンタ(TCNT)とTGRxレジスタとの一致を検出することができる。
これらのフラグは、一致で1にセットされ、1を読んだ後に0を上書きすることによりクリアすることができる。
周期タイマとして使う
MTU2を周期タイマとして使用する場合は、上で説明したような手順で行う。
例として1[ms]毎にコンペアマッチをする設定を考えてみる。なお周辺クロックPφ=20.0[MHz]である。
① クロック選択はPφ/1とする。Pφ/64(312.5[kHz])と設定することも可能であるが、その場合カウントアップが3.2[us](=1/312.5kHz)単位となるので精度が下がってしまう。
MTU20.TCRは次のように定義されている。
struct st_mtu20 { union { unsigned char BYTE; struct { unsigned char CCLR:3; unsigned char CKEG:2; unsigned char TPSC:3; } BIT; } TCR; ~中略~ };
#define MTU20 (*(volatile struct st_mtu20 *)0xFFFFC300)
TPSCビットは次のように操作する。
MTU20.TCR.BIT.TPSC = 0; // Pφ/1を選択 MTU20.TCR.BIT.TPSC = 1; // Pφ/4を選択
② 次にカウンタ(TCNT)のクリア条件を設定する。
MTU2のチャネル0の場合、TGRA~TGRDのうち一つとコンペアマッチが発生した時にTCNTをクリアするように設定できる。
ここではTGRAとのコンペアマッチでクリアするように設定する。
MTU20.TCR.BIT.CCLR = 1; // TGRAのコンペアマッチでTCNTクリア
③この例では、 カウントクロックは20.0[MHz]なので、カウントする数をN、Nカウントするまでの時間をtとすると、次の式が成り立つ。
Nについて解くと
となる。カウントクロックはTCRレジスタのTPSCビットで変更可能であるから(手順①)、必要に応じて上の式を変形して使用する。テキストのCMTのページが参考になる。
計算したNをTGRAに設定するのだが、CMTの時に説明したように、設定値はN-1としなければならない。カウンタは0からスタートするために、設定値は-1するのである。
TGRAは次のように定義されている。
struct st_mtu20 { ~中略~ unsigned short TCNT; unsigned short TGRA; unsigned short TGRB; unsigned short TGRC; unsigned short TGRD; ~中略~ };
#define MTU20 (*(volatile struct st_mtu20 *)0xFFFFC300)
よって、TGRAへの書き込みは次のように記述する。
MTU20.TGRA = 20000 – 1;
④ ここまでで必要な設定は終わっているので、チャネル0の動作を開始する。
MTU2のスタートはTSTRレジスタで行い、”iodefine.h”では次のように定義されている。
struct st_mtu2 { ~中略~ union { unsigned char BYTE; struct { unsigned char CST4:1; unsigned char CST3:1; unsigned char :3; unsigned char CST2:1 unsigned char CST1:1; unsigned char CST0:1; } BIT; } TSTR; ~中略~ }; };
#define MTU2 (*(volatile struct st_mtu2 *)0xFFFFC20A)
MTU2のスタートは次のように記述する。
MTU2.TSTR.BIT.CST0 = 1; // MTU2 チャネル0スタート MTU2.TSTR.WORD |= 0x0001; // MTU2 チャネル0スタート
⑤ コンペアマッチの発生を待つ。タイマステータスレジスタ(MTU20.TSR)のTGFAフラグは、TCNTとTGRAとのコンペアマッチ発生で1にセットされ、0の上書きでリセットすることができる。
TSRレジスタは次のように定義されている。
struct st_mtu20 { ~中略~ union { unsigned char BYTE; struct { unsigned char :3; unsigned char TCFV:1; unsigned char TGFD:1; unsigned char TGFC:1; unsigned char TGFB:1; unsigned char TGFA:1; } BIT; } TSR; ~中略~ };
#define MTU20 (*(volatile struct st_mtu20 *)0xFFFFC300)
コンペアマッチの発生は、下の例のように判断する。
if (MTU20.TSR.BIT.TGFA == 1) { // コンペアマッチ発生 ! : }
以上をまとめると、1[ms]ごとにコンペアマッチを発生するプログラムは、次のようになる。
void main() { STB.CR4.BIT._MTU2 = 0; // スタンバイ解除 MTU20.TCR.BIT.TPSC = 0; // カウントクロックは PΦ/1 = 20MHz MTU20.TCR.BIT.CCLR = 1; // TCNTはTGRAのコンペアマッチでクリア MTU20.TGRA = 20000 - 1; // 20MHzを20000カウント MTU2.TSTR.BIT.CST0 = 1; // カウント開始 while (1) { while (!MTU20.TSR.BIT.TGFA) ; // コンペアマッチしていない // コンペアマッチ発生(1ms経過した) MTU20.TSR.BIT.TGFA = 0; // フラグクリア(忘れがち) ~以降略~ } }
下記よりワークスペースをダウンロードし、演習を行うこと。
mtu2_1.zip
演習問題
1.Pφが20.0[MHz]のとき、クロック選択ビットの設定ごとのカウントできる最大値の表を完成させよ。
MTU20.TCR.BIT.TPSC | 分周比 | カウントクロック周期 | カウントできる最大値 |
0 | 1/1 | 0.05[us] | |
1 | |||
2 | |||
3 |
2.MTU2のチャネル0を使い、圧電スピーカーから1[kHz]の音を出力するプログラムを作成せよ。
3.MTU2のチャネル0を使い、プログラムスタートでLED6を点灯、1秒後に消灯するプログラムを作成せよ。<注意>演習1で計算したように、チャネル0はカウントできる最大値が1秒に届かない。よって、100[ms]を10回カウントするような構成にすること。
4.MTU2のチャネル0を使い、LED6が500msごとに点灯→消灯→点灯…を繰り返すプログラムを作成せよ。
5.MTU2のチャネル0を使い、100msごとにLCDの表示をカウントアップするプログラムを作成せよ。表示は0→1→2…のように増えるものとする。
6.上のプログラムを改造し、SW6でカウントアップ開始、SW5で停止、SW4で0になるような、簡易ストップウォッチを作成せよ。表示は0.0→0.1…のように小数点を付けた秒表示とする。