2012年02月22日

MachXO2のクロック

MachXO2 Breakout ボードを使ってみて覚えたことをメモしておこうと思う。

内蔵オシレータ

    MachXO2 は、MachXO と同じくオシレータを内蔵している。MachXO2 から良くなったのは、周波数を設定できること と 精度が規定されたこと。

    MachXO は、18 〜 26 MHz と なっているだけで とりあえずクロックが使えれば良いという用途でしか使えなかった。

    MachXO2 では、133 MHz を 1 , 1.5 , 2, 2.5 ... 62 で分周した周波数を出力可能。64 通りの設定がある。精度は±5% で、あまり良いわけではないが、それでも 目安にはなる。

    分周比は、1 〜 16 の範囲では、0.5 刻み。16 〜 32 は 1 刻み、32 〜 62 では 2 刻み。

    OSCH #(.NOM_FREQ("24.18")) osc_internal
    (.OSC(CLK_INT), .STDBY(1'b0));

    こんな風に使う。NOM_FREQ の値は、TN1199 の表に書いてあるものと同じでないといけないことになっているが、本当かどうか 未確認。

PLL

    PLL は、EHXPLLJ というのを使うのだが、

      f = CLKI/CLKI_DIV(1-40) x CLKFB_DIV(1-40) x CLKOP_DIV(1-128:default 8)

    の周波数が VCO の周波数になる。実際に合成して Warning を見ると、VCO 周波数は、400 〜 800 MHz の範囲でないといけないらしい。... が、多分間違いで、データシートを見ると 200 〜 800 MHz の範囲。CLKOP_DIV が 8 なら CLKOP の範囲は、 25MHz 〜 100 MHz ということに。

    CLKOP の出力は

      f = CLKI/CLKI_DIV(1-40) x CLKFB_DIV(1-40)

    だが、CLKOS, CLKOS2, CLKOS3 は、

      f = CLKI/CLKI_DIV(1-40) x CLKFB_DIV(1-40) x CLKOP_DIV(1-128:default 8) / CLKOSn_DIV(1-128:default 8)

    になるようだ。

    あと、これらは、ENCLKOSn を 1 に設定してやらないと出力されない。

    (いろんな使い方をして構わないが) 基本 四相のクロック出力をするときに使う。その場合は、CLKOSn_DIV の値は、CLKOP_DIV に一致させる。

    位相は、CLKOSn_FPHASE パラメータで 0-7 を指定する。45°単位。

    さて、 ちゃんと記述しても Waring が出る。

      WARNING - par: Output clock frequency on pin CLKOP of pll is 100.0 MHz, which with divider 16, requires internal VCO frequency to be 1600.0 MHz ( 100.0 MHz x 16), outside VCO valid range [400, 800] MHz.

    こんなメッセージ。ここの 100.0 MHz は、制約による指定で、

    FREQUENCY NET "NET名" 24.0 MHz

    というのを制約ファイル(.lpf) に記述することで指定する。

    あと、正しいレンジは、200 - 800 MHz のようなので、400 MHz を切る設定をしても良さそうなのだが、Warning を消すのは難しいかも知れない。

    ついでに書いておくと、MachXO や LatticeXP2 も PLL を持っている。MachXO では、EHXPLLC LatticeXP2 では、EHXPLL1 というのを使うらしいのだが、MachXO2 のものほど 高機能ではない。

PLLの動作確認


    OSCH #(.NOM_FREQ("24.18")) osc_internal
    (.OSC(CLK_INT), .STDBY(1'b0));

    DCMA clk_selector (.CLK0(CLK_INT)
    , .CLK1(EXTOSC)
    , .SEL(1'b0) // 0: CLK0 1: CLK1
    , .DCMOUT(CLK_IN0)
    );

    EHXPLLJ #(
    .CLKI_DIV(24)
    , .CLKFB_DIV(24)
    , .CLKOP_DIV(16)
    , .CLKOS_DIV(16)
    , .CLKOS2_DIV(16)
    , .CLKOS3_DIV(16)
    , .CLKOP_FPHASE(0)
    , .CLKOS_FPHASE(2)
    , .CLKOS2_FPHASE(4)
    , .CLKOS3_FPHASE(6)
    ) pll
    (.CLKI(CLK_IN0)
    `ifdef SYS_DRIVEN_CLK4PH
    , .CLKOP(CLK0_OUT)
    , .CLKOS(CLK90_OUT)
    , .CLKOS2(CLK180_OUT)
    , .CLKOS3(CLK270_OUT)
    , .ENCLKOS(1'b1)
    , .ENCLKOS2(1'b1)
    , .ENCLKOS3(1'b1)
    `else
    , .CLKOP(CLK_IN)
    `endif
    );

    完全には正確ではないのだが、こんな感じで使ってみた。

    それぞれのクロックに カウンタを付けて、1 秒程度おきに点滅させてみたところ、おなじ周期で点滅した。ただし、PLLの出力が (CLK_IN0に対して) ずれていく現象になった。

    原因は PLL の ロック が外れまくるため(のはず)。内蔵オシレータを基準クロックに使うのは、さすがに無理があるようだ。ただ、水晶なら問題ないとして、セラミック発振子を使ったり RC 発振だとどうなるのだろう? いずれ実験してみたい。

    ちなみに DCMA (Dynamic Clock Mux) は、おまけ。ドキュメントに書いてあったので使ってみただけ。

PLLの出力周波数の設定

    切りの良い周波数を 出力するのに

      CLKI_DIV : 入力周波数と同じにする。(1-40)
      CLKFB_DIV:出力周波数と同じにする。(1-40)
      CLKOP_DIV: 出力周波数 x CLKOP_DIV が 200 (400?) を超えるように 8/16/32 .. から選ぶ。

    基本の考えかたを、こんな風にしようかと思う。そうするなら、入力周波数は、切りが良ければなんでも良い。ただ応用できる範囲を広げるには、5x4 MHz とか 6x4 MHz とかが良さそうな気がしている。

PLL周波数をユーザ回路で変更

    MachXO2 だとこれが出来る。

    lscc/diamond/1.4/cae_library/synthesis/verilog/machxo2.v に EHXPLLJ に定義がある。インターフェイス仕様は WISHBONE。ドキュメントは、TN1199(J) の付録 D 。

水晶発振器

    MachXO2 Breakout ボードには、5mm x 7mm のオシレータのパターンもある。

    EXTOSC 27 PL9A_PCLKT3_0
    EXTOSC_EN 32 PL10A

    クロック出力だけでなく、Enable ピンにも接続されている。(R54 でジャンパされている)。

    回路図には、CB3LV-3C の 50MHz が記載されているが、消費電流が 40mA と大きく、±50ppm と精度もいまいち。16mA で ±10ppm の ASYMB の方が良いかも。

    秋月だと 『クリスタルオシレーター 40MHz』というのがある。いつなくなるかも分からないが ..

    J4

    (EXTOSC)PL9A 27 (33) (34) 28 PL9B
    GND (35) (36) GND
    (EXTOSC_EN)PL10A 32 (37) (38) 33 PL10B
    PL10C 34 (39) (40) 35 PL10D

    この信号は、20x2 のコネクタにも出ている。場所は、内側の 左(J4) の下。

    ユニバーサル基板を載せるのなら、こちらを使っても同等になる。その場合は、DIP 品(3.3V)が使える。といっても秋月でも 300円

その他の発振回路

    例えば、(EXTOSC)と (EXTOSC_EN) は、GND を挟んで配置されているのだが ... ここに 水晶とか セラミック発振子を付けて発振させられないかと思っている。単なるインバータなら 簡単に実装できるが、なんとかなるものなのか? 入出力にはいろんな設定があるので、設定次第なのかも知れない。

    追記: オシレータが入手できたので、(EXTOSC)と (EXTOSC_EN)を使っての実験はヤメ。

    J2
    (1)(2)
    NC VCCIO0
    PT17D/DONE 109 110 PT17C/INTn
    PT17B 111 112 PT17A
    GND GND
    PT16D 113 114 PT16C
    PT16B 115 117 PT15A
    PT15D/PROGn 119 120 PT15C/JTAGen
    GND GND

    J2 左側の外側上あたり。PT17A と PT16C が良さそうな。

      設定できるのは、プルモード、ヒステリシス、クランプ動作 あと ドライブ強度。これらは、制約ファイル(.lsf) にも記述できるし、プリミティブもあるようだ。

      それに加えて DELAYE とかのプリミティブもある。なにがどう使えるかは良く分からない。

      追記:



      こんな回路で、XIN , XOUT にインバータを入れれば良いらしい。水晶+コンデンサをセラミック発振子に変えても良い。

      村田製作所の FAQ 『発振回路部の各部品の役割について教えてください。』を見ると、R1(1M) は、帰還抵抗で C-MOS ICでは100k〜10MΩ (通常1MΩ) とのこと。『大きすぎると帰還量が減って動作点が不安定になり、小さすぎるとゲインの低下や、電流の増大につながります』と書いてあるから、入れないと発振が不安定になるかも知れない。

      XOUT 側 帰還抵抗 R1 と 水晶(セラミック発振子)の間に抵抗を入れる場合がある。『負荷容量とローパスフィルタを形成し、高域のゲインを低下させることで、高周波の異常発振を抑えられます。』なんて説明があるが、通常不要らしい。もともと数十Ωが入っているようなものだし ... それにドライブ強度の変更で調整できるかも。

      ... というわけで FPGA でも 単なるインバータ + この回路で良さそうだ。(1M は省略しないこと)

      さて、『セラミック発振子 40MHz (YIC社)』というのは、使えるのだろうか? 周波数が高めで AVR とかでは使えないが FPGA なら丁度良いかも知れない。

      最も 『クリスタルオシレーター 40MHz』なんてのもあるのだが ... いつまでもあるとは限らないし、水晶発振子やセラミック発振子の回路も押さえておきたい。

      ちなみに、安い YIC社のやつは、8,12,16,20,25,32,40,48 MHz と各種ある。PLL が使えそうだからなんでも良さそうだが ...

      いつか実験しよう。

      RC発振器(1)



      シュミットトリガ入力 と オープンドレイン出力がある MachXO2 だとこういう回路もあり?
      (シュミットトリガ入力 = HYSTERESIS : LARGE ?)

      R1 = 10k , C1 = 20pF ぐらいで数MHz ?

      原理は、コンデンサに充電されていって 入力の電位が上がってくると 出力が L になって コンデンサが放電される。ただ 0 になる前に Hi-Z に戻る。入力の波形はのこぎり波(に近い三角波)。シュミットトリガ入力 でないと 波高が 0 だから使えない。

      RC発振器(2)



      むしろオープンドレイン出力を使わないこっちのが普通?

      こっちの原理は、入力 L のときは、 充電で H になると反転して 放電。入力の波形は三角波。こっちも、シュミットトリガ入力必須。

      出力強度を変えたり、 HYSTERESIS : SMALL にすると周波数が変わるはず。

      いずれにしてもあまり高い周波数向けではないような.. それに定数が分からない。

    ところで、 PL9A は、PCLKT3_0 というクロック入力用 ピンが割り当てられている。こういったピンは、他にもあって 1200 の LQFP144 は、

    PT12B_PCLKT0_1 128
    PR5C_PCLKT1_0 92
    PB9A_PCLKT2_0 49
    PB11A_PCLKT2_1 55
    PL9A_PCLKT3_0 27
    PL5A_PCLKT3_1 19
    PL3A_PCLKT3_2 5

    という割り当てになっている。

    これらのピンは、外部回路と同期を取るのに重要そうだが、PLL にクロックを供給するだけなら、これを使う必要はないはず。たまたま DCMA を使ってみたが、DCMA は、PLL にクロックを供給できる。DCMA の入力は、general routing が使えるみたいだから、要はなんでも良いみたいだ。

    RC発振器は、単なるインバータで良かったはず。そういえば、フランクリン発振器もそう。

四相クロックについて

    普通 四相クロック が欲しいなら PLL で良いわけだが、内蔵オシレータをクロック元にすると PLLのロックが外れることが頻繁に起きる。通信でこういうことが起きると少々具合がわるい。分周して 四相クロックを作る方法も 検討しておこう。


      reg [3:0] r_clk_0 = 4'b0110;
      reg [3:0] r_clk_90 = 4'b0011;
      reg [3:0] r_clk_180 = 4'b1001;
      reg [3:0] r_clk_270 = 4'b1100;

      always @(posedge CLK_IN0) // CLK4X
      begin
      r_clk_0 <= { r_clk_0[2:0] , r_clk_0[3] };
      r_clk_90 <= { r_clk_90[2:0] , r_clk_90[3] };
      r_clk_180 <= { r_clk_180[2:0] , r_clk_180[3] };
      r_clk_270 <= { r_clk_270[2:0] , r_clk_270[3] };
      end

      wire CLK0_OUT = r_clk_0[3];
      wire CLK90_OUT = r_clk_90[3];
      wire CLK180_OUT = r_clk_180[3];
      wire CLK270_OUT = r_clk_270[3];

    Xilinx だとこんなコードが良さそう。SRL16 を使っていることになるから 4LUT しか消費しないんじゃないかと思う。

    だが、Lattice では、SRL16 相当の機能はないようだ。MachXO2 では、カウンタとか 比較機能を持っているから素直なロジックのコードが良いのかも知れない。

      reg [1:0] r_clk_cnt = 2'b00;
      reg [3:0] r_clk_out = 4'b1100;

      always @(posedge CLK_IN0) // CLK4X
      begin
      r_clk_cnt <= r_clk_cnt + 1;
      r_clk_out[0] <= (r_clk_cnt == 0) | (r_clk_cnt == 1);
      r_clk_out[1] <= (r_clk_cnt == 1) | (r_clk_cnt == 2);
      r_clk_out[2] <= (r_clk_cnt == 2) | (r_clk_cnt == 3);
      r_clk_out[3] <= (r_clk_cnt == 3) | (r_clk_cnt == 0);
      end
      wire CLK0_OUT = r_clk_out[0];
      wire CLK90_OUT = r_clk_out[1];
      wire CLK180_OUT = r_clk_out[2];
      wire CLK270_OUT = r_clk_out[3];

    あと POWER ON RESET 関係。すこし遅延させたい。


      reg [15:0] reset_sft = 16'h0000;
      always @(posedge CLK)
      begin
      reset_sft <= { reset_sft[15-1:0] , 1'b1 };
      end
      wire RESET = reset_sft[15];

    Xilinx だと 16bit まで 1 LUT だから、こんなのもアリだと思うのだが、他は具合がわるい。


      reg [3:0] reset_cnt;
      reg r_reset;
      always @(posedge CLK)
      begin
      if (reset_cnt == 4'b1111)
      r_reset <= 1'b1;
      else
      reset_cnt <= reset_cnt + 1;
      end
      wire RESET = r_reset;

    素直な コードだとこう?

    ところで、MachXO2 だと、シフトを使った コードはどちらも期待どおりにならない。初期値の設定がどうやっても出来ず、最終的に 定数 になるようだ。Synplify Pro も LSEも同じ。

    上記の reset_cnt のコードだと Synplify Pro は定数でないものを合成してくれる。が、LSE はダメ。


      reg [15:0] reset_sft = 16'h0000;
      reg r_reset = 1'b0;
      always @(negedge CLK_IN)
      begin
      if (r_reset != 1'b1)
      begin
      r_reset <= 1'b1;
      reset_sft <= 16'h0000;
      end
      else
      reset_sft <= { reset_sft[14:0] , 1'b1 };
      end
      assign RESET = reset_sft[15];

    このコードだと Synplify Pro は定数でないものを合成してくれる。が、LSE はダメ。
    r_reset を使わずに、( reset_sft != 16'hFFFF) なんて条件を使うと、Synplify Pro でもダメ。

    Warning をしっかり見ないと 期待どおりかどうか分からない。

    WARNING: Register r_reset_11 is stuck at One

    LSE だとこういうエラー に注意。

    ちなみに、こういうコードは、クロックや RESET 自体の生成にしか重要でないように気をつけてはいるのだが...

参考資料
posted by すz at 22:53| Comment(0) | TrackBack(0) | MachXO2
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/54110085
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック