この記事では、リセットコントローラの動作の詳細とソースコードについて書きます。
目次
- 1. 動作概要
- 2. Port (ポート)
- 3. Signal (シグナル)
- 4. 動作詳細
-
- 4-1. 入力リセット信号
- 4-2. 初期化
- 4-3. カウンタのビット幅
- 4-4. 100 µs経過後の動作
- 4-5. 64 ms経過後の動作
- 5. VHDL ソースコード
- 6. トップに接続
- 7. ソースファイルをプロジェクトに追加
動作概要
今回作る「USBブラスター的なもの」のリセットコントローラの動作の概要です。
- コンフィグ完了までリセットコントローラ内をリセット状態に保つ
- PLLがクロックを供給し始めると、コントローラ内のカウンタが動き始める
- リセットコントローラが64 msをカウントする
- 1つめのカウンタで100 µsをカウント
- 2つめのカウンタで64 msをカウント
- 64 ms経過後、リセットコントローラ内部にリセット信号を生成する
- 出力FFを通してリセット信号を出力する
Port (ポート)
リセットコントローラのポートです。
ポート名 | 方向 | ビット | 説明 |
---|---|---|---|
clk | in | 1 | クロック (24 MHz) |
conf_done | in | 1 | コンフィグ完了信号 |
rst_o | out | 1 | リセット出力 |
- クロックとコンフィグ完了信号を入力
- リセット信号を出力
Signal (シグナル)
シグナルです。内部で使用する信号線です。
シグナル名 | ビット | 説明 |
---|---|---|
count_100us | 12 | カウンタ1 (100 µsをカウント) |
count_ms | 10 | カウンタ2 (0.1 ms単位で64 msをカウント) |
rst | 1 | 出力前リセット信号 |
- 100 µsまでカウントアップするカウンタ
- ミリ秒単位でカウントアップしていくカウンタ
- 出力FFで叩く前の(出力前)リセット信号
動作詳細
入力リセット信号
リセット系統は図のようになります。
間違えて下記モジュールにこのモジュールの出力をつなぐと、モジュール内のカウンタが回らず永遠にリセット解除されないので気を付けましょう。
- リセットコントローラ (=このモジュール。カウンタが初期値のまま変化しない)
- PLL (クロックが出力されず、すべての回路が動かない)
このモジュール自体の初期化にはCONF_DONE信号を使います。
基板上に電源監視ICがあればベストですが、MAX1000にはそんなICがないのでCONF_DONE信号に落ち着きました。MAX1000のCONF_DONE信号はコンフィグ完了LEDにつながっていたので、LEDの端子からジャンパ線で外部IOピンに戻しています。
ちなみに、ジャンパ線なしでMAX10内部だけで完結させたければ、PLLのロック信号を使えば良さそうです。
初期化
CONF_DONEがリリースされるまでの間、↓のようなリセット状態にしておきます。
- 2つのカウンタの値を0
- 出力するリセット信号の値を0(Low)
カウンタのビット幅
2つのカウンタそれぞれのビット幅を決めますが、その前にFPGAでの時間計測の基本的な考え方を書きます。
FPGAで時間を計る
FPGAで時間を計るには、入力されたクロック(周期は既知)の数を数えて
\[周期×クロック数=時間\]
で経過時間を求めます。また、
\[時間÷周期=クロック数\]
で、計測したい時間までのクロック数を計算できます。
100 µs をカウントするカウンタのビット幅
今回は下記の条件なので、2400クロックで100 µsとなります。
- 使用しているクロックの周波数は24 MHz (周期: 1/24,000,000 s = 約41.667 ns)
- 100 µsをカウントする
カウンタはSignalで作ります。
まず、2進数で2400を数えられるビット数を考え、Signal宣言で必要なビット幅を指定します。
\[2400_{10} = 1001,01100000_{2}\]
のように12ビットなので、カウンタのビット幅も12以上あれば大丈夫です。
Signal宣言は次のようになります。
signal count_100us : std_logic_vector(11 downto 0);
0からカウントを始めて、カウント値が2399(=2400-1)になったときが100 µsです。
64 msをカウントするカウンタ
上で設計したカウンタが100 μsを教えてくれます。それに連動してもう1つのカウンタを回していき、64 msを計測します。(なお設計時に、100 µsという時間を他の用途に使う可能性があったのでカウンタを分けています。)
100 µsごとにトリガが入るので、入力されたトリガの回数から経過時間を把握することができます。64 msの場合は640回です。\(640 \, \mathrm{(ms)} / 0.1 \, \mathrm{(ms)} = 640\)
また、640カウントできるカウンタに必要なビット幅は10ビットです。
\[640_{10} = 10,10000000_{2}\]
Signal宣言は次のようになります。
signal count_ms : std_logic_vector(9 downto 0);
100 µs経過後の動作
100 µs経過後は次のように動きます。
- カウンタ1(100 µsカウント用)は値をリセットし、再び100 µsのカウントが始まる
- カウンタ2(64 msカウント用)は、カウンタ値を1つ増やす
64 ms経過後の動作
64 ms経過後は次のように動き、出力用のリセット信号の状態を変化させます。
- 出力するリセット信号をHに変更する
- 各カウンタのカウント動作を停止する
リセット解除後はリセット信号の状態を変化させないので、カウンタ動作は不要になります。消費電力の節約にもなるので、カウンタの動作を止めてしまいます。
VHDL ソースコード
ソースコードはGitHubに置いています。
https://github.com/tetsufuku81/max1000_usb_jtag/blob/master/source/reset_control.vhd
トップに接続
完成したモジュールを組み込みます。
- トップソースのEntity内でcomponent宣言
- このソースのArchitecture内でport map
これでトップソースの下にリセットコントローラが接続されます。
該当部分のソース抜粋を以下に載せます。
コンポーネント宣言
トップ(jtag_logic_top.vhd)のEntity内
ポートマップ
リセットコントローラ(reset_control.vhd)のArchitecture内
ソースファイルをプロジェクトに追加
このままコンパイルをすると「そんなモジュールはない」と怒られます。
Quartus Primeにソースコードの存在を認識してもらうために、このソースファイルをプロジェクトで使用するファイルのリストに追加します。
コメントを残す