とりあえずRX220のページへ行って
https://www.renesas.com/ja-jp/products/microcontrollers-microprocessors/rx/rx200/rx220.html
「ドキュメント」を選択
「ユーザーズマニュアル:ハードウェア」にチェック
検索
出てきた「RX220グループ ユーザーズマニュアル ハードウェア編」をクリック
飛んだ先でもう一回「RX220グループ ユーザーズマニュアル ハードウェア編」をクリック
やっとダウンロードできました。
CMTの原理
コンペアマッチタイマの原理を理解しておきます。
タイマー動作で増えるカウント値と
設定値(上限値)を
比較(コンペア)し条件に
一致(マッチ)した時に何かする機能が
コンペアマッチタイマーです。
説明は
shのPWM設定の回とほぼ同じです。
CPUの
クロックをカウントしていき、
設定値になったらカウント値を
初期値にリセットします。
リセット直後から再びカウントを行い、再び上限値になったらカウント値をリセットします。
RX220の場合カウントが設定値に達したら自動的に0にリセットされるようです。
これがコンペアマッチタイマを使った繰り返し動作の例です。
繰り返しの周期は
クロックの周期×上限値となります。
クロックが一定であるため、
カウント値の増加は
時間の経過に比例し
タイマーにより自動的に増加していることと同じと考えることができます。
図では10カウント目でリセットをかけていますが、実際には数百カウントでリセットをかけます。また純粋なCPUのクロック周期では早すぎるため
CPUのクロックがn回動作したら
1カウントアップさせるといった方法をとります。
クロック2回で1カウントとすると見かけ上の
動作速度が2分の1になります。この設定を
2分周器と呼びます。
rx220では4種類のクロックが使用可能で、このクロックに対して分周器を設定して使います。
プログラム解説
準備が整ったのでプログラムを見ていきます。
ここから先だらだらと書くので非常にながったらしい説明になります。
RX220でCMTを扱ううえで必要なのは
・CPUクロックの設定
↓
・CMT機能の初期化
↓
・CMTを利用
の順で実行する必要があります。
サンプルプログラムでは
main関数内(49~68行目)でクロックの設定
timer関数内(31~33行目)でCMTの初期化
timer関数内(34~43行目)でCMTを利用しています
プログラム実行の流れに沿って
main関数→タイマー関数の順に動作をみていきます。
メイン関数部分void main(
void)
{
SYSTEM.
PRCR.WORD = 0xa50b;
//クロックソース選択の保護の解除 //SYSTEM.OPCCR.BIT.OPCM = 0x02; //動作モードの設定。低速/中速 //SYSTEM.SCKCR.LONG = 0x00001412; //マニュアル参照。 //SYSTEM.SCKCR.BIT.PCKD = 0x00; //マニュアル参照。 SYSTEM.
SCKCR.BIT.
PCKB = 0x01;
//マニュアル参照。 //SYSTEM.SCKCR.BIT.BCK = 0x00; //マニュアル参照。 SYSTEM.
SCKCR.BIT.
ICK = 0x00;
//マニュアル参照。 //SYSTEM.SCKCR.BIT.FCK = 0x00; //マニュアル参照。 /*クロックソースの選択*/ SYSTEM.
SCKCR3.WORD = 0x0200;
//大元のクロックにメインクロックを使用する。 //SYSTEM.SCKCR3.WORD = 0x0300; //大元のクロックにサブクロックを使用する。 /*クロックの元栓の設定*/ SYSTEM.
MOSCCR.BYTE = 0;
//メインクロック発振器動作 SYSTEM.
SOSCCR.BYTE = 0;
//サブクロック発振器動作 //SYSTEM.LOCOCR.BYTE = 1; //LOCO動作 //SYSTEM.HOCOCR.BYTE = 1; //HOCO動作 //SYSTEM.ILOCOCR.BYTE =1; //IWDT専用オシレータ停止 PORTH.PODR.BYTE=0x00;
PORTH.PDR.BYTE=0xff;
while(1)
{
PORTH.PODR.BIT.B0=1;
PORTH.PODR.BIT.B1=0;
timer(1000);
PORTH.PODR.BIT.B0=0;
PORTH.PODR.BIT.B1=1;
timer(1000); /
/timer(ミリ秒) }
}
<用語>
PRCR:プロテクトレジスタ
重要な機能には間違って変更してしまわないように保護がかかっており、
その保護機能を解除・設定します。
OPCCR:動作電力コントロールレジスタ
最大動作速度と消費電力の兼ね合いを設定します。
消費電力が大きいけど高速動作や速度を落として低消費電力などのおおよその設定を行います。
初期設定は中速動作モード1Aになっています。
SCKCR:システムクロックコントロールレジスタ
分周器の設定を行います。
PCKB:周辺モジュールクロックB(S12AD以外)の分周器設定
PCKD:周辺モジュールクロックD(S12AD用)の分周器設定
BCK:外部バスクロック(RX220未対応機能)の分周器設定ICK:メイン機能クロック(CPU、DMAC、DTC、ROM、RAM)の分周器設定
FCK:FlashIFクロック(ROM、E2 データフラッシュ)の分周期設定
設定値
0x00:1分周
0x01:2分周
0x02:4分周
0x03:8分周
0x04:16分周
0x05:32分周
0x06:64分周
SCKCR3:システムクロックコントロールレジスタ3
4つのクロックの大元となるクロックにどれを使用するか設定します。
・外付けメインクロック(20MHz)
・外付けサブクロック(32.768KHz:時計用)
・HOCO CPU内蔵高速クロック(32MHz/36.864MHz/40MHz/50MHz※HOCOCR2で切替)
・LOCO CPU内蔵低速クロック(125kHz:初期状態)
の何れかを選択します。
標準ではLOCOに設定されています。
MOSCCR:メインクロック発振器コントロールレジスタ
SOSCCR:サブクロック発振器コントロールレジスタ
LOCOCR:低速オンチップオシレータコントロールレジスタ
HOCOCR:高速オンチップオシレータコントロールレジスタ
ILOCOCR:IWDT (ウォッチドッグ)専用オンチップオシレータコントロールレジスタ
それぞれのクロックのON-OFFを設定します
<内容>
49行目クロック設定の保護解除
0xA50Bは 0xA500と0x000Bに分けれ考えます。
0xA50Bは
0xa500と
0x000Bに分けて考え、上2桁
0xA500は設定変更のためのパスワードの様なもの、下1桁
0x000Bがどの部分の保護機能を解除するかを表します。
0x0001:クロック発生回路関連レジスタへの書き込み許可
0x0002:動作モード、消費電力低減機能、ソフトウェアリセット関連レジスタへの書き込み許可
0x0008:LVD(電圧監視)関連レジスタへの書き込み許可
0x000Bだと全部保護解除になります。
今回の設定ではLVDを変更していないため
0xA503としても動作します。
50行目※コメント行
今回は設定不要です。
51~57行目分周器の設定をしています。
今回はメインとCMTで必要な周辺Bのみ設定しています。
メインを1分周器、周辺Bを2分周器に設定しています。
60行目大元のクロックをメインクロック(20MHz)に設定しています。
分周器を合わせて考えると
メインの実動作周波数は20Mhz、
周辺Bの実動作周波数は10MHzとなります。
64~68行目必要なメインとサブのクロックを動作開始させています。
今回の設定ではサブ(32.768KHz)を利用していないのでサブを動作させる必要はありません。
以降は
前回と同様なので割愛
タイマー関数部分void timer(
int msec){
//10MCLK int cnt = 0;
MSTP(CMT0)=0;
//Wakeup CMT0, CMT1 CMT0.
CMCOR = 1249;
//8msec ※実際は1ms CMT0.
CMCR.WORD = 0x0000;
CMT.
CMSTR0.BIT.
STR0 = 1;
while(1){
while(CMT0.
CMCNT != 0x00);
cnt++;
if(cnt == msec){
cnt = 0;
CMT.CMSTR0.BIT.STR0 = 0;
break;
}
while(CMT0.CMCNT == 0x00);
}
}
<用語>
MSTPこれはハードウェアマニュアルを探しても出てきません。
プロジェクト内を全検索するとiodefine.h内で見つかります。
MSTPはマクロで、iodefine.hの6542行目から6544行目に記載されています。
MSTP(CMT0)
を元に戻していくと
_MSTP(_CMT0)
__MSTP(_CMT0)
MSTP_CMT0
となります。
更にこれはiodefine.hの6486行目で
SYSTEM.
MSTPCRA.
BIT.
MSTPA15であることが分かります。
ここまで来ればハードウェアマニュアルに説明が出てきます。
MSTPCRA:モジュールストップコントロールレジスタA
様々な機能を停止しておくレジスタです。
起動直後はほとんどの機能が停止された状態なので、使う機能は自分で停止解除する必要があります。
MSTPA15:コンペアマッチタイマ(ユニット0)モジュールストップ設定ビット
要するにCMT0の停止を管理しています。
CMCOR:コンペアマッチタイマコンスタントレジスタ
CMTで使用する
比較対象(カウンタの上限値)です。
CMCR:コンペアマッチタイマコントロールレジスタ
CMTで使用するクロックの分周期器と割り込み機能を設定します。
CMSTR0:コンペアマッチタイマスタートレジスタ0
CMT0とCMT1のカウント開始・停止を制御します。
STR0:スタートレジスタ0
CMT0のカウント開始・停止を制御します。
<内容>
31行目~33行目CMTの初期化
MSTP(CMT0)=0;
CMT0機能を起動しています。
機能が起動しただけで、タイマーはまだスタートしていません。
CMT0.CMCOR = 1249;
タイマーの上限値を設定しています。
コメントでは8ミリ秒となっていますが、他の部分と合わせて実際には1ミリ秒になります。
解説は後程。
CMT0.CMCR.WORD = 0x0000;
この設定では分周器がPCLK/8(8分周器)となります。
PCLK(B)のクロックを8回カウントするとCMT0のカウンタが1増えます。
PCLKBが実動10MHzなのでPCLKBは1クロックで0.0001ms(0.0000001s)です。
8クロックで1カウントとなると1カウントは0.0008msとなります。
1msに到達するためには1/0.0008=1250カウント必要です。
真面目に確認していませんが処理の都合上1250から1引いた1249をタイマーの上限値に設定しています。
割込み機能は停止されています。
詳しくはハードウェアマニュアルの「CMCR」の項を参照してください。
34行目カウント開始
35行目~44行目条件を満たす(**ミリ秒経過)まで無限ループ
36行目条件を満たす(1ミリ秒経過)まで無限空ループ
CMCNTが0以外の間空ループします。
CMCNTが0になると空ループを抜けて次の行に行きます。
37行目~42行目ループするたびにcntを1増加させ、設定値msecと一致したらカウンタを停止させ無限ループを抜けます。
breakするとwhile(1)の無限ループから抜けます
43行目カウントが増えるまで無限空ループ
37行目から42行目の処理が速すぎてCMCNTのカウントが増える前にCMCNTが0の状態で何回もwhile(1)の無限ループの中を回ってしまうのを防ぐためにCMCNTのカウントが増えて0以外になってから次のサイクルに進みます。
気になる事
設定変更のために保護機能を解除していますが、変更後は再度保護をかけなおすのた正しい手順です。
関数を実行するたびに31行目から33行目の初期設定が実行されますが、本来1回だけ実行すれば良い内容なのでこの部分は別の初期化関数で実行させた方が良いと思う。
CMCNTはtimer関数を実行する度に初期化した方が良いと思う。
最初にwhile(1)に突入した時点では処理が速すぎて36行目に来た時点でCMCNTが0ですぐ無限空ループを抜けてしまいそう。
while(CMT0.CMCNT != 0x00); の前に while(CMT0.CMCNT == 0x00); を書いておいた方が良い気がする。