PTM

Programmable Timer Module (MC6840)は16 bitのカウンタ・タイマを3回路内蔵したデバイスで、周期的割り込み発生器やACIAのビットレートジェネレータ、時間測定などに使える素子です。

MC6840
1979年製のプラスチックパッケージ、28ピンDIPです。

Z80 CTCと同じような目的のLSIですが、MC6840の方が確か後発で、その分だけ機能が練られています。まず、カウンタの数はZ80 CTCの4チャネルから3チャネルに減っていますが、そのカウンタのビット幅が8 bitから16 bitとなっているため、実用上はZ80 CTCより便利になっています。なにしろ、Z80 CTCではカウントできる数の上限が256と少ないため、ふたつのチャネルを組み合わせて16 bitカウンタとして使用することも多かったのですから、16 bitカウンタひとつと8 bitカウンタふたつが必要となるアプリケーションではZ80 CTCとMC6840が互角で、独立した16 bitカウンタふたつが必要となればZ80 CTCでは残りがありませんがPTMならあと1チャネル使えます。
さらに、カウンタ・タイマの動作モードとして8モードを設定できます。Z80 CTCでは2モードで、少々複雑なことを行おうとすると割り込みを併用してソフトウェアでサポートする必要がありました。指定周波数の方形波を出力し続けることもできますし、CPUの書き込みや外部回路からの信号を基準にして一定時間だけのパルスを出力することもできます。あらかじめ設定しておいた時間と外部パルスの幅を比べ、外部パルス幅が狭い場合、あるいは広い場合に割り込みを発生させるようなこともできます。
また、各カウンタにクロック入力、ゲート入力、タイマ出力の端子が用意されていて、外部回路との相互作用を行いやすくなっています。

レジスタ選択端子が3本あり、CPUからは8個のレジスタに直接アクセスできます。ただし、内蔵されているレジスタは各チャネルごとにコントロールレジスタ、カウンタ上位バイト、カウンタ下位バイトをアクセスする必要があるでしょうから、9個のレジスタとなります。そこで、チャネル1, 2, 3のコントロールレジスタのうちチャネル1とチャネル3のものを同じアドレスに割り当て、チャネル2のコントロールレジスタのビット0でどちらに書き込むか決めるなど、少々ややこしくなっています。さらに書き込みと読み出しでは異なるレジスタが見えたり(書き込み時はコントロールレジスタだが読み出し時はステータスレジスタとか)、16 bitのカウンタ値にアクセスする際は上位か下位のどちらかを先に読み取ってからカウンタ値が変化してしまうとおかしなことになるため、読み書きそれぞれにバッファレジスタがあって、CPUから連続したアクセスによって16 bit分まとめて読み書きできるような工夫がされているため、結構レジスタアクセス方法がややこしくなっています。
レジスタ選択端子(RS2, RS1, RS0)とR/W*信号によって内蔵レジスタに対してどのような動作が行われるのか次の表に示します。

RS2 RS1 RS0 R/W* = 0 R/W* = 1
0 0 0 CR20 = 0: Write Control Register 3
CR20 = 1: Write Control Register 1
No Operation
0 0 1 Write Control Register 2 Read Status Register
0 1 0 Write MSB Buffer Register Read Timer 1 Counter
0 1 1 Write Timer 1 Latch Read LSB Buffer Register
1 0 0 Write MSB Buffer Register Read Timer 2 Counter
1 0 1 Write Timer 2 Latch Read LSB Buffer Register
1 1 0 Write MSB Buffer Register Read Timer 3 Counter
1 1 1 Write Timer 3 Latch Read LSB Buffer Register

各チャネルごとに存在するコントロールレジスタの意味を次の表にまとめました。なお、チャネルn用のコントロールレジスタのビットbをCRnbと表記します。つまり、チャネル2のコントロールレジスタのビット0ならCR20と書きます。これは上の表でも使われています。また、どのチャネルでも同じ意味のビットについては、CRXbというような表記を用いています。たとえばコントロールレジスタのMSBは常にそのチャネルのタイマ出力端子のイネーブルビットになっていますから、まとめてCRX7の意味はタイマ出力イネーブルビットなどとしています。

CRX7 Timer X counter output enable
CRX6 Timer X interrupt enable
CRX5
CRX4
CRX3
Timer X counter mode and interrupt control
CRX2 Timer X counting mode control
CRX1 Timer X clock source
CR10 Internal reset bit
CR20 Control register address bit
CR30 Timer 3 clock control

CRX7はタイマ出力端子を有効無効を決めるビットです。各カウンタには、タイマ出力(O1, O2, O3)、ゲート入力(G1*, G2*, G3*)、クロック入力(C1*, C2*, C3*)の各3本の入出力信号があります。そのうちのOXの動作を決めるのがこのビットの意味です。CRX7が0ならOXは常にLレベルを出力し、CRX7が1ならタイマの動作モードによって決まるタイミングで信号を出力します。
CRX6は割り込みイネーブルで、0でマスク、1で割り込み有効となります。どのようなタイミングで割り込みが発生するかについては、タイマの動作モードによって決まります。
CRX5, CRX4, CRX3は3 bit分まとめてタイマの動作モードを指定するのに使われます。詳細は後述します。
CRX2はカウンタモードの切り替えビットで、16 bitカウンタとして扱うか、ふたつの8 bitプログラマブルカウンタが直列に接続されたものとして扱うか、決定します。CRX2が0のとき、カウンタに16 bitの定数Nをロードすることができます。有効なクロックがN + 1回入力されるとカウンタが0になり、なんらかの動作が行われます。CRX2が1のときには、ふたつの8 bit定数LとMをカウンタにロードしたものとして扱われます。そうして、有効なクロックが(L + 1)*(M + 1)回入力されるとカウンタ全体が0になり、なんらかの動作が行われます。つまりL + 1回で8 bitカウンタがタイムアウトすると、そのイベントがもうひとつのM + 1回カウントするカウンタのクロックとして使用されます。使い方によっては、おもしろい応用ができるでしょう。あらかじめマイクロプロセッサで乗算をしてから16 bit定数をロードすれば同じことですが、MC6800などの初期8 bitマイクロプロセッサは乗算に手間がかかりましたから。
CRX1はクロック信号の選択ビットで、0ならクロック入力端子(C1*, C2*, C3*)に与えられる信号によってカウンタをデクリメントしていきます。1ならシステムバスクロックのE信号をクロックとして使用します。なおクロック入力端子は内部でEに同期されるため、C3*でプリスケーラを使用する場合を除き、Eクロック周波数の半分よりも充分に低い周波数でなくてはいけません。C3*には8分周を行えるプリスケーラが備えられていて、CR30によってプリスケーラを有効にできますが、やはり分周後にEと同期する必要がありますから、MC68B40で2 MHzクロックをEに与えてもせいぜい8 MHz弱の信号までです。また、80系のバスのRD*信号とWR*信号を細工して疑似E信号を作成してMC6800系のデバイスにインターフェースする技法がありましたが、そのようにしてMC6840を80系のプロセッサから使用しようとすれば不具合が生じる可能性があります。つまり80系のバスではRD*信号やWR*信号は不定期に出力されます。マイクロプロセッサ内部での命令実行時間が長い命令が実行されたりすると、何usもの間、バスへのアクセスが生じない可能性だってあります。すると、クロック入力端子からの周期的信号でカウンタを働かせていても、Eクロックと同期がとれないためにカウントミスを引き起こす可能性があります。たとえばHD64180にはEクロック信号出力があり、MC6800系のデバイスを簡単にインターフェースできることになっていますが、この信号は内部的にRD*やWR*信号から作成されているために非周期的になっていて、MC6840を接続してもトラブルの原因になることがあります。MC6800系のデバイスではE信号を読み書きのタイミングだけでなく周期的であることを利用したものがありますから、多種類のバスにインターフェースする際には注意しなくてはなりません。よく使われるMC6821ですら、ハンドシェークラインのパルス出力モードでのパルス幅はEクロックで決められているので、HD64180なんかに接続した場合にはそのパルス幅の時間が一定でななくなってしまいますし。まぁ、それでトラブルが生じることはないでしょうけど、MC6840の場合には結構危ないですから。
あ、寄り道しすぎました。コントロールレジスタの最下位ビットはチャネルごとに異なる意味を与えられています。
CR10に1を書き込むと内部リセット状態になります。カウンタ動作は禁止されます。ただし、カウンタラッチの内容やコントロールレジスタの別のビットを書き換えることは自由にできます。0を書き込めば、通常動作となります。なお、外部リセット信号RESET*が与えられた場合には、CR10以外のコントロールレジスタの全ビットがクリアされるという点が異なります。
CR20はRS0 .. RS2が0のときに書き込めるコントロールレジスタがチャネル1用のものかチャネル3用のものかを決定するビットです。0でコントロールレジスタ3に、1でコントロールレジスタ1に書き込めます。ハードウェアリセット後にはCR20も0にクリアされていますので、コントロールレジスタにはチャネル3, 2, 1の順でアクセスすれば最短手順で初期設定ができるとMotorolaの資料にあったりしますけど、どうでしょう。今となってはたいした手間とバイト数でないですから、リセット後の状態に影響されにくい初期化コードの方がよさそうですし、NMI*なんかで強制再初期設定なんかを行わせたい場合に、リセット時の初期化サブルーチンを流用しやすくするためにも、きちんと毎回CR20を操作した方がよさそうです。
CR30はチャネル3にだけ付属の8分周プリスケーラを有効にするためのビットです。1で有効、0で無効です。

さて、カウンタの動作モードですが、これはCRX5, CRX4, CRX3によって次の表のように決まります。

CRX5 CRX4 CRX3 動作モード
0 0 0 連続動作モード
GX*ネガティブエッジかラッチ書き込みかリセットでカウンタ初期化発生
0 0 1 周波数比較モード
GX*ネガティブエッジ間の時間がカウンタタイムアウトより短ければ割り込み
0 1 0 連続動作モード
GX*ネガティブエッジかリセットでカウンタ初期化発生
0 1 1 パルス幅比較モード
GX*のL入力の時間がカウンタタイムアウトより短ければ割り込み
1 0 0 シングルショットモード
GX*ネガティブエッジかラッチ書き込みかリセットでカウンタ初期化発生
1 0 1 周波数比較モード
GX*ネガティブエッジ間の時間がカウンタタイムアウトより長ければ割り込み
1 1 0 シングルショットモード
GX*ネガティブエッジかリセットでカウンタ初期化発生
1 1 1 パルス幅比較モード
GX*のL入力の時間がカウンタタイムアウトより長ければ割り込み

連続動作モードでは周期的パルスをOX端子から出力できるので、ビットレートジェネレータとかモータ駆動用の周期的信号などを作成できます。シングルショットモードでは、CPUによる初期化以降はCPUの介入なしに外部回路から一種のタイマのように利用できます。どちらのモードでも、Lになっている時間とHになっている時間はある程度プログラム可能です。周波数やパルス幅の比較モードは、やはり外部の機械なんかの動作監視に使えます。

さて、コントロールレジスタはこれくらいにして、ステータスレジスタはどうなっているかというと、こうなっています。

7 (MSB) 6 5 4 3 2 1 0 (LSB)
INT -- -- -- -- I3 I2 I1

結局、割り込み関係のフラグだけです。I1, I2, I3は各チャネルの割り込みフラグで、INTはMC6840全体の割り込みステータスです。INTとI1, I2, I3の関係は次のようになっています。

INT = I1*CR16 + I2*CR26 + I3*CR36

この式で*は論理積を、+は論理和を表します。つまり各チャネルの割り込みマスクでマスクした結果がINTに反映されます。

残りのレジスタはタイマラッチへの書き込みとカウンタの読み出しに使われていますが、上位バイトを先に読み書きして続けて下位バイトを読み書きすることによって、正しく16 bitの値を読み書きできるようになっています。
書き込みの際、まず上位バイトを書き込むと、バッファレジスタにデータが書き込まれます。次に下位バイトにデータを書き込むと、同じタイミングでバッファレジスタからカウンタラッチの上位バイトにもデータが転送されます。こうして、16 bitデータが同時に書き込まれるようになっています。このようにしないと、どちらか一方のバイトを書き込んだ後、カウンタの内容が変化してからもう一方のバイトが書き込まれるような可能性があり、カウンタのコヒーレンシを保証できなくなります。ただし、このバッファレジスタは全チャネルで共通に使われてしまうため、注意が必要です。たとえば、チャネル1の上位バイトに値を設定したあとで割り込みが発生し、その割り込みサービスルーチンの中でチャネル2のカウンタラッチを上位下位の順で正しく書き込んだ後、もとのチャネル1のカウンタラッチ書き込みルーチンに戻り、下位バイトの書き込みを行うと、チャネル1の上位バイトには意図した値でなくてチャネル2の上位バイトと同じものが書き込まれてしまいます。これを防ぐには、STX命令など16 bitデータの書き込み命令を必ず使用することにするか、MC6840のアクセス中は割り込み禁止にします。STX命令の書き込みシーケンスはMC6840の上位下位の順のシーケンスに適合しますし、MC6800系列のマイクロプロセッサではSTX命令の実行途中で割り込みサービスルーチンに制御が移ることがありませんから、安心でしょう。もちろん、DMAでMC6840のレジスタ操作したりマルチプロセッサ構成で同じMC6840を操作する場合には、この手は使えません。しかし、そのようなシステムでは、もっときちんとした資源管理と排他アクセス手順が存在するでしょうから、その手順を守ればよいだけのことです。
読み出しも同じで、カウンタの上位バイトを読み出すのと同じタイミングで下位バイトがバッファレジスタに書き込まれます。続く下位バイトの読み出しは、そのバッファレジスタの内容が渡されるようになっています。やはりLDX命令などを使ってアクセスするのがお勧めです。

Return to IC Collection.