Xilinx社のCPLDである「XC95108」を使って50nsec刻みで
1secまでのパルスを発生するブロックを作って見ました。
ディジタル回路のクロック信号やテストなどに使える連続パルスの発生ができる
シグナルジェネレータです。最小分解能は50nsecか500nsecで、出力パルスは
100nsecから1secまでの連続パルスを発生出来ます。
またデューティも0から100%の間で自由に変えられます。このデューティも分解能は
50nsecか500nsecです。
つまり下記の2段階でパルスを出力します。
出力 100nsec〜100msec 最小分解能 50nsec
出力 1μsec〜1sec 最小分解能 500nsec
下記はこれを応用した汎用シグナルジェネレータのモジュールで、PICのプログラム
で、ディジスイッチの入力をチェックしていて、マニュアル設定した時間のパルスを
出力します。さらにロータリーエンコーダの入力もして、デューティを連続的に可変
出来るようにしています。
さらにパソコンをUSBで接続してマニュアルと同じように、パルス幅とデューティを
リモートコントロール出来るようにしたものです。
ディジタルブロックを組み込んだXC95108を中心に
PIC16F876を制御用チップとして構成。
外部とのインターフェースにはUSBを使っています。
CPLDと外付けの出力バッファとなる74AC04。
左端のJTAGコネクタから何時でもVHDLの結果を変更して
CPLDの内部回路を変更することが出来ます。
クロックは20MHzの発振器を使っています。
外部とのインターフェースのUSBのBタイプソケット
放熱板付きの3端子レギュレータ
USBN9603はフラット実装パッケージなので、半田付け
にはちょっとしたこつが必要。
まずたっぷりの半田でピンとパターンを完全に覆う
次に基板を縦にして半田こてをあてて、余分の半田を
下向きに流すようにして取り除きます。
【全体の構成】
このシグナルジェネレータブロックの内部構成は下図のようになっています。原理は
PICのPWMモジュールと同じになっています。これをVHDLで記述してCPLDに実装
しています。
まず、出力には1個のDフリップフロップが使われています。このDフリップフロップ
のセットとリセットを一定周期で制御してパルスを作り出しています。
この一定周期を生成するために、まずカウンタがあります。このカウンタは50nsec
(500nsec)つまり20MHz(2MHz)のクロックで常時カウントアップしています。
20MHz(2MHz)で最大10Hz(1Hz)までカウントするため、20ビットのカウンタとなって
います。
このカウンタの出力はやはり20ビットのコンパレータに接続されていて、常に設定
値を保持している20ビットのシフトレジスタの出力と比較されています。そして両者の
値が一致するとコンパレータから一致信号が出力されて、出力Dフリップフロップが
セットされます。同時にカウンタがゼロクリアされて最初に戻ります。
この間、カウンタの出力は、もうひとつのコンパレータで比較されていて、こちら側が
デューティの制御となります。このコンパレータの一致出力がでると、出力のDフリップ
フロップがリセットされます。このリセットされるタイミングはカウンタのカウントアップ
する途中になるような値であることが必要です。つまりデューティのシフトレジスタの
値は、必ず周期のシフトレジスタより小さいことが条件になります。
この動作を図で示すと下図のような関係になります。
上側にあるBCDカウンタは外部の20MHzのクロックを1/10にして2MHzのクロック
を生成します。この20MHzと2MHzのどちらをカウンタのクロックにするかをhiloという
信号で選択しています。
【改版】
上記で動作確認を行ったところ、私が入手した XC95108-15 ではクロックが20MHz
では正常に動作せず、クロックの速さに追従しないことが判明しました。
そこでいろいろ代替回路を試してみた結果、下図のような構成にすれば、20MHzでも
動作することが分かりました。ただし、この回路でのコンパレータはマクロセルを沢山
使うようでXC95108ではぎりぎりとなってしまいました。
それでも当初の仕様は満足しますので、これで進めることとしました。
この時の動作タイミングは下図のようになり、出力のフリップフロップが無くなって
コンパレータの出力がそのまま外部ピンに接続されています。この回路では、確実
に20MHzで動作します。
【さらに改版】
改版版では、出力にヒゲが出ることがわかったので、レジスタを追加
して同期化した。当然といえば当然ですね。
また100nsec単位で1Hzまでのパルス幅とするため21ビット幅にして
1ビット増やしました。
【PICとのインターフェースの動作タイミング】
動作タイミングとしては、周期の設定とデューティの設定の2つの要素がありますが、
全く同じ動作をしますので扱いは同じとなります。
入力となるシフトレジスタへのクロック(fclkまたはdclk)とデータ(sdata)のタイミングは、
シフト用のクロックであるfclk(またはdclk)の立ち上がりで、シフトデータのsdataを
シフトレジスタに取り込み、シフトレジスタを1ビットシフトします。
この関係を図示すると下図のようになります。時間的にはsclk(dclk)のパルス幅が
50nsec以上あれば問題なく動作し、パルス幅に上限はありません。
シフトレジスタはsclk(dclk)の度に、最上位ビットを捨てますので、20ビット以上の
データを入力しても問題なく、最後の20ビットが残ります。
【VHDLの内容】
VHDLの内容は基本的なモジュールの組合せだけですから難しくはありません。
しかし、XC95108の中に全てを実装できるようにするため、少し工夫をしました。
本来でしたら、20MHzから1Hzを作り出すには、24ビット程度のビット幅が必要に
なるのですが、それではXC95108では入りきりませんでした。
そこで、20ビット幅と約1/10にして、余裕が出来たところにBCDカウンタを1個
追加してクロックを1/10にする回路を追加しました。これで、外部クロックを20MHz
とすれば、カウンタへのクロックは20MHzと2MHzと切り替えて使うことが出来ます。
これで、長いパルス幅の時には分解能を500nsecとすることで、回路規模を縮小する
ことが出来ますので、これでXC95108の中に全てを実装可能とすることが出来ました。
下記よりVHDLのソースファイルがダウンロード出来ますのでお使いください。
お使いになるときにはピン配置を設定する必要があります。
★ シグナルジェネレータVHDLファイル
(1) まずは信号の定義です。Entityで外部ピンの信号を定義します。
ピンの指定は、WebPACKの「Pin Assignment ChipViewer」で行います。
この定義部分は下記のようになっています。porcess文の中では、出力信号は直接
ピンの信号名を使わず、一旦内部信号として出力してから、別に外部ピンとの接続
の記述をします。 こうすると確実に出力にバッファが挿入されますので安心出来ます。
(2) VHDL本体の最初はクロックの1/10デバイダの回路部分です。
これで20MHzのクロックを1/10にして2MHzにします。
さらに外部のhiloの信号で20MHzと2MHzを選択して外部ピンに出力します。
この出力をCPLDの標準クロックピンに接続します。このピンを使うと、ファンアウト
など最適化されますので最高速度での動作が可能となります。
VHDLは下記のようになります。
(3) 次は、PICからの入力を処理するシフトレジスタ部で、周期とデューティと2つの
シフトレジスタがあります。
いずれも20ビットで、シフトクロックの都度1ビットずつシフトします。最上位は
捨てますので最後の20ビットが残って有効ということになります。
またここだけ外部リセットを有効とし、電源ON時に0クリアするようにしています。
(4) 次はカウンタとコンパレータの部分です。
周期のレジスタと比較して同じになったらカウンタを0クリアします。
デューティのコンパレータでは、小さいかという比較信号を使い、その信号を
外部出力とするようにします。 最後に出力を外部ピンに出しています。
出力にはイネーブル信号によるゲートをかけていますので、その判断ロジック
が入ります。
外部カウンタ用の出力はゲートは必要無いので、そのまま出力としています。