べーヤタさんからCDIプログラムのTMR2の動作について質問がありましたので、その解説。 

TMR2は8ビットタイマーです。
つまり本来256までしかカウント出来ません。 

ところがTMR2にはプリスケーラとポストスケーラが存在しています。
これを使えばなんちゃって16ビットタイマーになります。

これを頭から見ていきます。
TMR2は3つのブロックからなります。
無題

入力の「Fosc/4」というのは、動作クロックの1/4でカウントアップシグナルが入力されるという事です。 
まずこのカウントアップシグナルがポストスケーラに入ります。
ポストスケーラのシグナルは8ビットのT2CONレジスターの<1:0>ビットによって設定します。
この2ビットにはT2CKPS1、T2CKPS0の別名が付いています。

余談ですが、この辺の定義を一度はヘッダーファイルで見とくと分かりやすいと思います。
コンパイラにXC8を使っているなら、デフォルトインストール時に以下のフォルダが存在するはずです。
C:\Program Files\Microchip\xc8\v1.20\include
ここにpic12f683.hがあります。
HI-TECH CのVer9.83なら以下のフォルダがありました。
C:\Program Files\HI-TECH Software\PICC\9.83\include
これらのヘッダーのお陰でビット操作しなくても直接値を入れてしまう事が可能となっています。


さて話を戻しますと、プリスケーラの設定は1:1、1:4、1:16の三種類です。
例えば1:4に設定するには、T2CKPSに1を入れるか、T2CONの0ビット目を1、1ビット目を0にします。
するとカウントアップシグナルが4回来るごとにTMR2カウンタがカウントアップします。

TMR2は常にPR2レジスタと比較されています。
PR2は8ビットレジスタで、TMR2を動作させる前に予め設定値をいれておきます。
TMR2とPR2の値が等しくなると、ポストスケーラがカウントアップし、TMR2がリセットされます。

ポストスケーラはプリスケーラと同様に、T2CONレジスターの<6:3>ビットによって設定します。
設定可能な値は結構種類が多く、
1:1、1:2、1:3、1:4、1:5、1:6、1:7、1:8、1:9、1:10、1:11、1:12、1:13、1:14、1:15、1:16
が設定出来ます。
ポストスケーラに1:10を設定すると、TMR2が10回カウントアップする(PR2と等しくなる)と割り込みが発生します。
このとき、TMR2の値はリセットされ、TMR2IFビットがONになり、割り込みが発生します。
割り込みが発生すると、PIC12FのCPUはvoid interrupt ISR(void)関数へジャンプします。

トータルでTMR2は以下の式でタイムアップする事になります。
(プリスケーラ) * PR2 * (ポストスケーラ)

したがって最大値は 16 * 256 * 16 = 65536(16ビット最大値)

これがTMR2の仕組みです。
なんでこんなにヤヤコシイの?ってな感じですが、CDIでは使わないだけで、これはこれで本来色々と使い道があるのです。
たぶん。

つまり、TMR2を制御するには、プリスケーラ、ポストスケーラ、PR2、(これに加えてTMR2の初期値も一応設定可能)の3点を設定すれば使えるって訳です。


んではCDIのソースコードを見てみます。
PR2   = gtblPR2[gRPM][deg];
T2CON = gtblT2CON[gRPM][deg];
テーブルはその時の回転数と進角させたい角度から、TMR2の設定値PR2/T2CONが引っ張れる様になっています。

これ何をやっているのかって言うと、時間とメモリを節約する為に、こまごまスケーラやらPR2やらを設定せず、一気にテーブルからドカンと値を入れているんですね。
計算、特に割り算は時間がかかるんですよね。
デバッグモードでステップイン実行して見ると分かりますけど、割り算って単純に引き算を繰り返しているだけですから。
詳細はこの辺見てくださいな。
こんなものは事前にIntelCore i3でやっとけばええのです。


次にTMR2に設定すべき実際のタイマー値を調べます。
例えば1,000rpmで回るエンジンは、ピックアップコイルの間隔が60ms=60,000usとなります。
前回書いた通り、8Mhzで動作するPIC12FはFosc/4なので0.5us間隔で動作します。
60,000(us) / 0.5(us) = 120,000回カウントアップする事になります。
1周360度とすると、120,000 / 360(deg) = 333.333...
333.33回のカウントを数えると大体1度程クランクが回っているってことですね。
20度進む時は、333.33 * 20 =  6,666.666...となります。

無題


ヤマハのピックアップコイルは、ピストンの上死点から70度マイナスのところで負電圧のパルスを発生させます。
なので、例えばB.T.D.C30度でプラグにスパークさせたい場合は、マイナス70度の信号を拾って、クランクが40度進む時間を計算して点火します。

以上が基礎です。

しかし、このままではタイミングが合いません。
なぜなら、パスルを受け取り、TMR2を設定し、次の割り込みを発生させるには、CPUが動作する時間が必要だからです。
流石に1,000rpm程度ですとCPU時間もあまり気にしないで良いのですが、10,000rpmも回っていると、一周6msと、結構早い周期になっています。
PICの動作は十分に早いのですが、なんだかんだやっていると1ms程度はすぐに消費します。
特に割り算は、です。
1msも消費すると、進角で言えば6度ズレるって事ですから、馬鹿に出来ませんね。

なので、パルスの入力(CCP1割り込み)から、TMR2を仕掛けてサイリスタゲートをオン、つまりプラグに火花を飛ばす付近の処理は、可能な限り時間が掛かるコードを書かない様にします。
特に割り算は分母と分子の乖離が大きければ大きいほど処理時間が直線的に伸びますので、これも避けるか、 分母分子の割合があまり変化しない様に十分注意して、発火タイミングがさほどズレ無いように慎重に設計します。
もしビットシフトで済むのであれば、ビットシフトします。2の階乗で割るならビットシフトですね。
割る方、割られる方の型も注意します。
実際型が違っている場合、暗黙的型変換をコンパイラがやっちゃいますので、意外と時間が掛かっている事もあります。
とまぁここまで神経尖らせてやるならアセンブラ使えって話ですけど、、、。


こうして一度TMR2を設定してしまえば、後は割り込み処理となりますので、メインループでのんびりアナログ入力でもしておきます。

TMR2のタイマー値を設定する際に、このCCP1割り込みからTMR2を仕掛けるまでの時間はあらかじめさっぴきます。
最後に、このさっぴいたタイマー値に上手く合う様にTMR2の設定を行います。
別に変わった事はしてなく、単純にエクセルで算出した値になります。

TMR2の設定値 = (70度 - 進角したい角度) * (1度進む時間) - (CPUで使う時間)

CPUで使う時間は、実際にMPLAB IDEのシミュレータ機能を使って調べます。
今回書いたコードでは700程度のカウントを必要としていたので、これを固定値として入れてます。 


TMR2の設定値が決まったら、次の順番で3つの設定値を決めていきます。
1)まずプリスケーラの精度が粗いので、これを決定します。可能な限り小さい方が良いです。
2)次にポストスケーラの値を決定します。 
3)ここまで決まればPR2は決まります。

多少の誤差はありますが、検算したところ許容範囲内に収まっています。
詳細はエクセルの表に書いてます。
プリスケーラだけ手で調整して、後は全部自動で計算してます。


今回のPICプログラムで、なぜわざわざテーブルにしているかというと、単純にダイヤルで進角を調整したかったからです。
一発決まれば、このようなテーブルは不要かも知れませんが、、、点火時期はガソリンのオクタン価でも調整した方が良いですし、今時のFIエンジンならノッキングセンサーに応じて常に調整している部分でもあります。
もう少しメモリがあるPICにしたら、センサー付けて色々出来ると思いますので、アプローチ的には良いと思います。
点火時期の基本はノッキングする直前で、とありますが、2ストは高回転時に大きく遅角させます。
点火してから排気するまでの時間を短くして、熱対策をしているそうです。
確かに4ストと違って2ストは毎回爆発ですから、単純に倍の熱を発生させている事になりますね。
排気ポートが4ストと違ってかなり大きいですし、その他の要因もありますから単純比較は出来ないと思いますが。
レーサーだと良いオイルを使っているでしょうし、常に全開とは言え、走っている時間も短いですから、もう少し進めても良いかも知れません。