01signal.com

FPGA を適切に起動およびリセットするための logic

これは、 FPGAsの resetsに関するシリーズの 3 番目で最後のページです。この前に最初の 2 つを読むことをお勧めします。

概要

resetsを作成するための適切な logic をセットアップするために時間をかけることは常に良い考えです。そのままの design に明らかな問題がなくても、 design でこの段階をスキップすると、犠牲になる可能性があります。 後で、 logic が適切に初期化されていないことが原因であることに気付かずに、不安定な問題を解決しようと何日も費やすかもしれません。このような問題を解決しようとする試みの中で、 design は問題の根本を理解せずに作成された厄介な回避策を蓄積しています。奇妙な不安定性に関するこのページの詳細。

プロジェクトの最初から reset 信号を熟考して設計することも、新しい機能が追加されたときに適切に成長することを保証するために重要です。 FPGA プロジェクトがゼロから開始される場合、多くの場合、そのコア機能が最初に実装され、時間の経過とともに機能が追加されます。 modules が異なると clocks と resetsが別々に必要になることが多いため、パーツごとに別々に何かをすばやく書き留めるという罠に陥りがちです。これにより、プロジェクトが進行するにつれて、プロジェクトがますます混乱することがよくあります。

resets と clocksを含むために、初日から適切に作成された中央の moduleを用意することで、厄介なプロジェクトを回避する方が簡単です。また、以下でさらに説明するように、 reset controller と clock resources (必要に応じてPLLs と clock buffers ) は互いに影響を与えるため、それらを同じ module に配置すると効果があります。私は通常、この module に clkrst.vという名前を付けます。

ただし、一部の IP cores、サブシステム、または design blocks が resets および clocksの独自のグループを生成する可能性があるため、これらすべてを 1 つの moduleに集中させることはしばしば不可能です。この場合、何が何に依存しているか、また異なるソースから到着した resetsの要求にシステム全体がどのように反応するかについて、慎重に考える必要があります。たとえば、 reset から PCIe block への信号は、ほぼ常に bus 自体から到達し、 block は、この blockに接続されている logic で使用する reset 信号を生成します。このような状況では、たとえば、 PCIe bus から reset が到着した場合、システム全体がどのように応答する必要があるか (まったく応答しない可能性も含めて) を考慮する必要があります。

各プロジェクトには独自のストーリーがあるため、すべてのケースに対応できる単一のソリューションはありません。このページでは、概念について説明し、独自の reset controllerのビルディング ブロックとして使用できるアイデアとコード スニペットを提案します。ただし、これらのコード スニペットはプロジェクトに直接カット アンド ペーストするためのものではなく、デモンストレーションとして扱う必要があります。

簡単にするために、システム内の他の block が clocks も resetsも生成しないと仮定しますが、 controller を一般的なケースに拡張することはかなり簡単です。

reset state machine

ほとんどの designsでは、リセットが必要な主なシナリオが 2 つあります。

さらに、 watchdog timers の有効期限が切れるか、その他の手段で主要なシステム障害が検出されたときに、リセットが必要になる場合があります。

これらすべてのシナリオに対して期待される対応は、根本的な再起動であり、何がうまくいかなかったとしても、それが修正されることを保証します。これは、開始された理由に関係なく、一貫性があり反復可能な reset sequence を保証する、ある種の state machineで行うのが最適です。

そうは言っても、ローカルの、おそらく繰り返しのリセットが理にかなっているシナリオがあります。たとえば、 video image frames を処理する logic は、各フレームの開始前にリセットできます。これは通常、ローカル synchronous reset がアクティブ化されたときにいくつかの registers に初期値を割り当てるという軽量メカニズムを必要とします。これは他のメカニズムと同様にリセット メカニズムであり、多くの場合、堅牢な動作を確保するためのクリーンでシンプルな方法です。

しかし、この可能性について追加することはあまりないため、このページの残りの部分では、 FPGA全体をカバーする基本的なリセットに焦点を当てます。

不安定な clocks と resetの必要性

clocksを生成するために FPGA独自の PLLs を使用することは非常に一般的です (通常は推奨されます)。ただし、これらの PLLs は通常、 FPGA 上の他のすべての logic がアクティブになると同時に動作を開始します。その結果、これらの clocks に依存する logic には、通常よりも大幅に高い周波数を持つ不安定な clockが供給されます。

この場合、該当する logic paths の timing は保証されません。したがって、 PLLs によって生成された clocks に依存する logic は、 PLL がロックされるまで timing constraints を達成できなかったかのように扱われるべきです。

適切で一般的な解決策は、関連する PLL がロックされるまで、そのようなすべての logic を reset に保持することです。あるいは、この logic は、 PLL がロックされるまで clock を無視するように設定できます。たとえば、 flip-flopsの Clock Enable input (CE) が非アクティブであることを確認します。

外部 clock が FPGAの pin から logic elementsに直接接続されている場合、問題は clock generator (通常は PLL) が FPGA に bitstreamをロードしたときよりも速くロックするかどうかです。これを確認するのは必ずしも容易ではありません。

その結果、ほとんどの designsで synchronous elements の多くをリセットする必要があります。より正確には、不安定な clockのために reset が必要かどうかという問題について、これらの elements を 3 つのグループに分けることができます。

一部の FPGAs では configuration プロセス (つまり、 bitstream をロードして FPGAを初期化するプロセス) をセットアップできるため、すべての PLLs がロックされるまで FPGAのウェイクアップが遅延されます。これは、この問題を解決する方法になる可能性があります。このソリューションの欠点は、外部 clockに問題がある場合、 FPGA がまったく起動しないことです。このような状況は、非常に混乱する可能性があります。

シンプルな state machine

基本的な起動または再起動は非常にまれなイベントであるため、必要以上に数マイクロ秒かかっても問題ありません。多くの場合、 100 ms 程度まででも問題なく、これを利用できます。したがって、単純な counter は一連のイベントを実装する簡単な方法です。

最も単純な形式では、次のようになります。

reg [4:0] reset_count;
reg       rst_src_pll, rst_src_shreg, rst_src_debounce;
reg       clear_counter;
reg       master_reset;

initial reset_count = 0;
initial master_reset = 1;
initial clear_counter = 1;

always @(posedge wakeup_clk)
  begin
    clear_counter <= rst_src_pll || rst_src_shreg || rst_src_debounce;

    master_reset <= (reset_count != 31);

    if (clear_counter)
      reset_count <= 0;
    else if (reset_count != 31)
      reset_count <= reset_count + 1;
  end

@rst_src_pll、 @rst_src_shreg 、および @rst_src_debounce は、システムをリセットするさまざまな理由を表しています。これらの registers は、他の logicによって値が与えられます。このような logicの例をいくつか見ていきますが、今のところ重要な点は、これらの registers が @wakeup_clk と同期していることです (したがって、 clock domain crossingは必要ありません)。

@clear_counter は resetのこれらの理由の logic OR です。この register は、 @reset_count をゼロに変更します。それ以外の場合、このカウンターは (この例では) 0 から 31 まで進み、その後停止します。

最後に、 @reset_count がカウントを終了しない限り、 @master_reset はアクティブです。これは reset state machineの最も単純な形式であり、31 まで数えることも非常に控えめです。

したがって、 @rst_src_N 信号のいずれかがアクティブである場合、 clock cycleが 1 台であっても、 synchronous reset は 31 個の clock cyclesに対してアクティブです。

長い reset pulseには 2 つの利点があります。 まず、関連する @rst_src_N がランダムにオンまたはオフになる場合 (たとえば、 PLL lock detectors、 push buttonsの揺れ、 resets を複数回要求するソフトウェア)、これらの複数のアクティベーションは可視の synchronous resetに伝達されません。通常、このような複数のアクティベーションは無害ですが、 output pinsの不要なアクティビティが発生する可能性があります。このような活動はマイナスの影響を与える可能性があります。たとえば、電子機器をテストする人を混乱させて、何かがおかしいと思い込ませることがあります。

そういう意味では、31 clock cycles の例はかなりミニマルです。そのような遅延が許容できる場合は、 10-100 msに対応する値までカウントすることをお勧めします。そうすることで、それより短いウォブルは reset controllerによって隠されます。

reset pulse が長くなる 2 つ目の理由は、元の synchronous reset をローカル コピーに配布する際に (前述のように)、1 つの clock cycleの遅延が発生することです。 logic 全体に reset を分散させるために信号を複数回コピーする必要がある場合、遅延の合計が長くなるだけでなく、不均一になる可能性もあります。長い reset pulse は、ある時点で、すべての logic がアクティブな synchronous resetに公開されることを保証します。 reset の非アクティブ化も不均一になるため、 reset pathで不均一な遅延を持つことは依然として悪い考えですが、問題がない場合もあります。この件に関しては、 reset pulse の 31 clock cycles はおそらく必要以上に長いですが、問題はありません。

他の clock domainsのResets

@master_reset は通常の synchronous resetですが、 application logicで使用される clocks とは異なる clock と同期されます。他の clocks用に synchronous resets を生成するには、各 clockに対して次のような操作を行う必要があります。

reg reset_clk_pre1, reset_clk_pre2;
reg reset reset_clk;

always @(posedge clk)
  begin
    reset_clk <= reset_clk_pre2;
    reset_clk_pre2 <= reset_clk_pre1;
    reset_clk_pre1 <= master_reset;
  end

これは、 @reset_clkを生成する 3 段の通常の clock domain crossing です。この信号は、 @clkに付随する synchronous reset です。実際には 2 段階で十分ですが、これは重要な信号なので、余分な registerを追加して安全を確保しました。

reset controllerの clock

@wakeup_clk、つまり reset state machineとして使用できる clocks には、原則として次の 3 種類があります。

最初のオプションは、作業が最も簡単です。ほとんどの場合、 FPGAの PLLsを駆動する reference clock があるため、この reference clock を wakeup clockとして直接使用できることがよくあります。ただし、 FPGA がウェイクアップしたときに clock が実際に安定していること、つまり、 FPGA が bitstream をロードするのにかかる時間が、外部 oscillator が有効な clockを生成するのにかかる時間よりも長いことを確認することが重要です。これは通常、 datasheetsを見たときに大きなマージンがある場合です。しかし、ボードの powerup sequence が適切に計画されていない場合、 oscillator の supply voltage が正しいレベルに達するずっと前に、 FPGA が bitstream を読み取ることを許可される可能性があります。

2 番目のオプションは、 FPGA 自体で PLL によって生成された clock を使用することです。明らかな利点は、この clock が application logic にも使用される可能性があるため、 powerだけでなく clock リソースでもより効率的であることです。この選択では、 clock が安定するまで reset state machine を初期状態に保持する必要があります。これは、次のような方法で実行できます。

reg rst_src_pll;
reg rst_src_pll_pre;

initial rst_src_pll = 1;
initial rst_src_pll_pre = 1;

always @(posedge wakeup_clk)
  begin
    rst_src_pll <= rst_src_pll_pre;
    rst_src_pll_pre <= !pll_locked;
  end

@pll_locked は、 @wakeup_clk (active high) を生成する PLL の lock detector output です。このシグナルは非同期であるため、最初に @wakeup_clkと同期され、次に上記のように @clear_counterをアクティブにする理由の 1 つとして使用されます (つまり、 @rst_src_pllを使用)。

このオプションのもう 1 つの利点は、 reference clock が一時的に不安定または存在しない場合 (特にボードの電源を入れた後)、 lock detector も不安定になる可能性が高いことです。したがって、 @master_resetを非アクティブ化する前に @reset_count が大きな数 (確かに 31 よりもはるかに大きい) にカウントされる場合、 reference clock が適切に動作するようになるまで、 FPGA が reset にしっかりと残る可能性があります。ただし、これに依存することはできません。

いずれにせよ、 @wakeup_clk が PLL の output であるという事実は、この clock が安定する前に logic にフィードすることを必然的に意味します。したがって、その期間中に state machine が適切に動作するかどうかは明らかではありません。ある時点で clock が十分に良くなり、適切な resets が生成されるため、これは問題ではないと主張することができます。 resetの後にすべてが過去に残されている場合、その前に何が起こったのか誰が気にしますか?

より厳密なアプローチは、 wakeup clock がロックされるまで resets を安定してアクティブにしておく必要があるため、 FPGA が bitstream configurationの直後に奇妙な動作をしないようにすることです。これは、この clockで非常に単純な logic のみを使用することに注意を払う必要があります。言い換えれば、 logic は、 clock が予想よりも高い周波数を持っていても、大幅に故障しないようなものでなければなりません。

@wakeup_clk の周波数が一時的に高すぎる場合に何が起こるかを分析するには、 @reset_count が vectorである reset state machine の唯一の register であることに注意してください。これは、他のすべての flip-flops が、 timingに違反しているため、最悪の場合、計算された "next value" 1 つの clock をサンプリングするのが遅すぎる可能性があることを意味します。特に、 PLL がロックされていないときに @pll_locked がローであるため、 @rst_src_pll はすぐに着実に高くなり、したがって @clear_counter も着実に高くなります。 flip-flop の D input (次の value) が変わらない場合、 clock がどれほど高速であっても問題ありません。

したがって、考えられる唯一の問題は @reset_countであり、計算された next value が @clear_counterのためにゼロに安定して保持されるまで、誤ってカウントアップする可能性があります。たとえば、現在の値が 3 (binary 011) の場合、次に計算される値は 4 (binary 100) です。ただし、 timingのために 2 つの LSBs がサンプリングされず、それでも 3 番目の bit がサンプリングされる場合、カウンターの値は代わりに 7 (111 binary) にジャンプする可能性があります。

これが起こらないようにするために、 @pll_locked から @clear_counter までの registers のチェーンの初期値はすべて、 @reset_count を安定してゼロに保持するように割り当てられます。したがって、 @wakeup_clk が安定するまで @pll_locked が安定してローのままである場合、 @reset_count はゼロから離れず、 @master_reset は安定してアクティブなままです。

最後のオプションとして、 reset controllerに FPGAの ring oscillator を使用するには: 私はそれを自分で試したことがないので、それがどれほど良いアイデアなのかわかりません。しかし、それが他に選択肢がなくて困っている人を救うのであれば、 Xilinxの FPGAsを使って多かれ少なかれそれを行う方法は次のとおりです。 FPGA の Configuration User Guide で STARTUPE2 (またはそのようなもの)と呼ばれる primitive を検索してください。 CFGMCLKという名前の output が必要です。これは、 FPGA 自体の不正確な ring oscillator からの clock です。その頻度は 50-65 MHz前後です。この clock は、 FPGA が起動したときに安定していることが保証されているため、 timing constraint をかなり高い周波数 (たとえば、 100 MHz) に設定します。

しかし、これは、本当に他に選択肢がない場合に私が行うことです.たとえば、 FPGA が起動したときに外部 reference clock が安定していない場合、 logicに追加の遅延を実装する必要があります。

PLLsのリセット

一般に、 reset sequenceの一部として PLLs をリセットすることをお勧めします。これにより、 reference clock が有効であることがわかっているときに確実にリセットされます。また、 reset がユーザーによって開始された場合 (たとえば、 reset pushbuttonを押す)、これは PLLの不十分なロックに起因する問題に対応している可能性があります。あってはならないことですが、万が一の場合に備えて。

@clear_counter は、 PLL のロックが解除されるとすぐにアクティブになるため、 PLLのリセットには使用できません。これを使用すると、 PLL はリセット状態のままになり、ロックされることはなく、 reset が解放されることもありません。同じ理由で、 PLLsの resets を @reset_countから派生させることはできません。 すべての PLLs がロックされている場合を除き、ゼロに保持されます。

解決策は、 @clear_counterに似た PLL用に別の reset register を作成することです。したがって、ロックされていない PLLs が @rst_src_pllに反映されるという上記の表記を使用すると、次のようになります。

reg clear_counter;
reg reset_plls;

initial clear_counter = 1;
initial reset_plls = 1;

assign reset_sources = rst_src_shreg || rst_src_debounce;

always @(posedge wakeup_clk)
  begin
    clear_counter <= rst_src_pll || reset_sources;
    reset_plls <= reset_sources;

[ ... ]

このコード スニペットでは、 @rst_src_pll は @reset_sourcesから除外され、 @clear_counterにのみ使用されます。その結果、 PLLs は FPGA全体と共にリセットされますが、それ自体がロックされていない場合を除きます。

@reset_sources がランダムに Low と High に切り替わると、ここに示されているコードに従って @reset_plls も変わることに注意してください。 reset が狂ったようにオンとオフを繰り返すとき、 PLLs に悪いことは何も起こらないので、これは通常無害です。ただし、次に説明するように、これを回避する方法もあります。

より複雑な起動シーケンス

単純な counter (@reset_count) を state variable として使用すると、より複雑な startup sequencesを簡単に実装できます。たとえば、 clocks をオフにしてアクティブにする適切な asynchronous resetsを生成するのは非常に簡単です。 これは、 clocks がオフになっているときと resets がアクティブになっているときのタイムスロットを定義する単純な logic expressions で行われます。

したがって、この単純な counter メソッドは、プロジェクトの開始時に reset state machine からの単純なニーズがあるように見える designs の場合でも、適切な出発点となります。後で複雑な startup sequence が必要であることが判明した場合、この目標を達成するために既存の logic を拡張するのは簡単です。

いずれにせよ、 startup sequence の計画は、 sequence の各フェーズが有効になる期間を定義することに要約されます。そのような各期間は、 @reset_count が持つべき値の範囲に変換されます。

たとえば、 design に関連のない clocksが 2 つ以上ある場合、上記のように clock domain ごとに reset 信号を作成できます (「他の clock domainsのResets 」を参照)。しかし、その方法を採用すると、各 clock domains は実質的にランダムな順序で reset から出てきます。通常、これは問題ではありませんが、問題がある場合、各 clock domain は、 @reset_countの進行状況に基づいて、定義された時間に reset を無効にすることができます。

複数の counterを実装することも可能です。これは、 reset sequence が続行する前に特定の条件が満たされるまで待機する必要がある場合に役立ちます。たとえば、 reset sequence が PLLsをリセットし、それらがロックされるのを待ってから reset sequenceを続行する場合、すべての PLLs がロックされるまで 1 つの counter をゼロに保持することは理にかなっています。 2 番目のカウンターは、最初の counter がカウントを終了するまでゼロに保持されます。

PLL がその lockを失った場合、 PLLs 自体はリセットされませんが、それらに依存するすべてがリセットされることに注意してください。 lock を失った PLL は、ほとんどの designsで重大な障害になるため、これは望ましい動作ではない可能性があります。 lockが失われた場合に完全な reset を要求するには、以下に定義されているように @pll_restart を OR と組み合わせて @reset_sourcesを取得する信号に追加します。

assign pll_restart = rst_src_pll && !master_reset;

これは単に次のように述べています。 master reset が非アクティブになった後に PLL のロックが解除された場合は、 PLLsを含むすべてを再度リセットします。これが機能するためには、 reset count は lock detectorsの可能性のあるぐらつきに耐えるのに十分な長さである必要があります。つまり、 PLL がまだロックされていなくても、 reset count は、 PLLの lock detector が高くなる時間より長くなければなりません。これは、 PLL が lockを取得するのにかかる時間と混同しないでください。一部の lock detectors はまったくぐらつきません。これらのぐらつきは、 PLLの lock time よりもかなり短い可能性があります ( datasheetで指定)。

wakeup shift register

少し overkillかもしれませんが、私は通常、この種の wakeup shift register を designsに追加します。

reg [15:0]   wakeup_shift;
reg          rst_src_shreg;

initial rst_src_shreg = 1;
initial wakeup_shift = 0;

always @(posedge wakeup_clk)
  begin
    rst_src_shreg <= !wakeup_shift[15];
    wakeup_shift <= { wakeup_shift, 1'b1 };
  end

ほとんどの FPGAs は、 @wakeup_shift を LUTと同等のものを消費する shift register primitiveとして実装しているため、リソースが安価であり、電源投入時に reset が確実に実行されるようにする別のメカニズムを提供します。これは、 @clear_counterをアクティブにするものがないため、 PLLsのない design で必要です。ただし、 PLLsがある場合でも、 FPGA がウェイクアップしたときにすでにロックされている可能性があります。これは、一部の FPGAsでの bitstream configuration の可能なオプションであるためです。

いずれにせよ、これは推奨されるアドオンです。転ばぬ先の杖。

外部 reset button

Reset buttons は非常に一般的です。それらが行うことは、 design ごとに異なります。 1 つの可能性は、ユーザーが「reset」と見なす button が FPGA pin に接続され、 bitstream を FPGAにロードするプロセスを開始することです。 embedded processorがある FPGAs で、 processorの reset pinに接続することもできます。

そして、この reset button は、 FPGA logicをリセットする目的で、 FPGA上の一般的な I/O pin に接続できます。この場合、 @clear_counterを有効にするもう 1 つの理由です。

@reset_count が 10 ms 以上に対応する数にカウントされる場合、 counter 自体によってウォブルが吸収されるため、 input pinからの信号の debounce は必要ありません。この場合、これで十分です。

reg rst_src_debounce;
reg rst_src_debounce_pre;

initial rst_src_debounce = 1;
initial rst_src_debounce_pre = 1;

always @(posedge wakeup_clk)
  begin
    rst_src_debounce <= rst_src_debounce_pre;
    rst_src_debounce_pre <= reset_button_pin;
  end

ただし、 counter がすぐに終了する場合 (上記の例に示すように、 31に到達するまで)、 pushbutton には debouncingが必要です。これを行うには、いくつかの方法があります。たとえば、次のとおりです。

reg [17:0] debounce_count = 0;
reg        reset_button_d, reset_button_d2, reset_button_d3;

wire       debounce_reached = (debounce_count == 250000);

initial debounce_count = 0;
initial rst_src_debounce = 1;

always @(posedge wakeup_clk)
  begin
    reset_button_d3 <= reset_button_d2;
    reset_button_d2 <= reset_button_d;
    reset_button_d <= reset_button_pin;

    if (reset_button_d2 != reset_button_d3)
      debounce_count <= 0;
    else if (!debounce_reached)
      debounce_count <= debounce_count + 1;

    if (debounce_reached)
      rst_src_debounce <= reset_button_d3;
  end

これは比較的厳密な debouncerであり、ノイズの多い入力信号ではうまく機能しません。これは、ニーズに応じて長所または短所になります。

このコード例は、 25 MHz clock用に書かれています。 @reset_button_pin が 10 msの間に同じ値を持っていた場合、 @reset_button_pin の値は @rst_src_debounce にコピーされます。 @reset_button_d3 が値を変更するときと同じ clock cycle で、 @debounce_count がゼロに変更されることに注意してください。したがって、 @reset_button_d3 が値を変更すると、すぐに @rst_src_debounce にコピーされることはなく、同じ値を長期間維持した後にのみコピーされます。

概要

FPGAの初期化を設計する際には、考慮すべきことがたくさんあります。このページではいくつかの概念とアイデアを紹介しましたが、実際のタスクは、アクションを開始する必要があるイベントを正しく認識することであることに留意することが重要です。 logic を確実に稼働状態にするために、そのような各イベントに対する正しい応答を定義することも重要です。

このページは英語から自動翻訳されています。 不明な点は元のページを参照してください。
Copyright © 2021-2024. All rights reserved. (6f913017)