目次
前
次
DCM(Digital Clock Manager)
XilinxのFPGAには、DCM(Digital Clock Manager)と呼ばれる
モジュールが含まれています。
このモジュールを利用するとクロックを任意の周波数まで
逓倍あるいは分周できます。
また、位相を変化させる機能もあり、デジタル回路による
フィルタや周波数シンセサイザを構成する等には重宝します。
DCMのブロック図は、以下です。
上のブロック図を初めてみたとき、PLLのブロック図に
似ているなと思いました。CLKINとCLKFBがあり、2つの
クロックを比較し出力を確定するのと、CLKFBが出力から
フィードバックしているので、PLLが頭に浮かびました。
PLLのブロック図は次のようになっています。
ブロック図をみると、クロック出力のブロックには
DLLと記されています。
DLL(Delayed Lock Loop)は、遅延ロックループとされて
いるので、PLLに似た機能を持ちます。
DLLにある次のクロック出力に関して、データシートを
読んで、内容を理解してみます。
- CLK0
- CLK90
- CLK180
- CLK270
- CLK2X
- CLK2X180
- CLKDV
- CLKFX
- CLKFX180
CLK0、CLK90、CLK180、CLK270は、位相が90度ずつ
ずれたクロックになります。このときCLKINに入力
できる周波数は、24MHzから326MHzの限定範囲に
なります。
90度ずつ位相がずれたクロックは、6809のE、Qのように
マイクロコンピュータのバスインタフェースや信号処理
で複素数を扱いたいときに使えます。
アマチュア無線で話題になるSDR(Software Defined Radio)を
実現するときに、よく使われます。
位相が90度ずつずれたクロックがあると、無線信号から
I信号、Q信号の正相、逆相を作るのが簡単になります。
これが複素数の実数部、虚数部にわけて計算する場面で
役に立ちます。
クワドラチャミキサと呼ぶ処理は、ブロック図をみると
90度位相がずれたクロックが必要になることがわかります。
クワドラチャミキサは、位相のずれたクロックを利用する
ので、使いたい周波数の4倍の周波数が必要です。
7MHzの周波数帯域の信号が欲しければ、28MHzのクロックが
必要になります。28MHzのクロックから、4つの位相を生成
しなければ、上のブロック図相当の回路は実現できません。
CLK0、CLK90、CLK180、CLK270の4つの位相差クロックが
あると、90度ずつ位相をずらす回路は不要になります。
アナログで90度ずつ位相をずらすのは大変ですが、デジタル
はアナログに比べて簡単になります。DCMのような回路がある
と、さらに簡単になります。
DCMを使う場合、普通は、CLKIN、CLKFBにバッファを入れます。
Xilinxの開発環境には、3つのモジュールをコンポーネントが
Language Templateに用意されています。
DCMを使う場合、この3つのコンポーネントを呼出して
VHDLコードの中に入れることになります。
VHDLコード内で、3つのコンポーネントを使うには
次の指定記述を入れます。
Library UNISIM;
use UNISIM.vcomponents.all;
上の記述を入れると、VHDLコードではコンポーネントを
呼出すだけになります。
-- input clock buffer handling
IBUFG_inst : IBUFG
generic map (IOSTANDARD => "DEFAULT")
port map (
O => iCLKIN_IBUFG, -- Clock buffer output
I => CLOCK -- Clock buffer input
-- (connect directly to top-level port)
);
-- DCM
DCM_inst : DCM
generic map (
CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
-- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
CLKFX_DIVIDE => 24, -- Can be any integer from 1 to 32
CLKFX_MULTIPLY => 2, -- Can be any integer from 2 to 32
CLKIN_DIVIDE_BY_2 => TRUE, -- TRUE/FALSE to enable CLKIN divide by two feature
CLKIN_PERIOD => 20.833, -- Specify period of input clock
CLKOUT_PHASE_SHIFT => "FIXED",-- Specify phase shift of NONE, FIXED or VARIABLE
CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE, 1X or 2X
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS",
-- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
-- an integer from 0 to 15
DFS_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for frequency synthesis
DLL_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for DLL
DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE
FACTORY_JF => X"C080",-- FACTORY JF Values
PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255
SIM_MODE => "SAFE", -- Simulation: "SAFE" vs "FAST", see "Synthesis and Simulation
-- Design Guide" for details
STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE
port map (
CLK0 => iCLK0_OUT, -- 0 degree DCM CLK ouptput
CLK180 => iCLK180_OUT, -- 180 degree DCM CLK output
CLK270 => iCLK270_OUT, -- 270 degree DCM CLK output
CLK2X => open, -- 2X DCM CLK output
CLK2X180 => open, -- 2X, 180 degree DCM CLK out
CLK90 => iCLK90_OUT, -- 90 degree DCM CLK output
CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE)
CLKFX => open, -- DCM CLK synthesis out (M/D)
CLKFX180 => open, -- 180 degree CLK synthesis out
LOCKED => open, -- DCM LOCK status output
PSDONE => open, -- Dynamic phase adjust done output
STATUS => open, -- 8-bit DCM status bits output
CLKFB => iCLKFB_IN, -- DCM clock feedback
CLKIN => iCLKIN_IBUFG, -- Clock input (from IBUFG, BUFG or DCM)
PSCLK => '0', -- Dynamic phase adjust clock input
PSEN => '0', -- Dynamic phase adjust enable input
PSINCDEC => '0', -- Dynamic phase adjust increment/decrement
RST => '0' -- DCM asynchronous reset input
);
-- output clock buffer handling
BUFG_inst : BUFG
port map (
O => iCLKFB_IN, -- Clock buffer output
I => iCLK0_OUT -- Clock buffer input
);
DCMを使いこなすには、Core Generatorを使えば、genericで指定
される内容を、開発環境に用意されているツールで生成できます。
DCMのブロック図とgenericの指定パラメータの
対応を理解しておきます。
CLKIN、CLKFB
CLKINは、周波数を指定します。
CLKIN_PERIODに、周期で数値をnsで記述します。
50MHzでは20nsですが、小数点以下も必要なので、20.0とします。
CLKINを2分周してDCMに入れることもできます。
この場合、CLKIN_DIVIDE_BY_2に与える論理値で
指定します。
CLKFBは、CLK0かCLK2Xのどちらかしか使えません。
CLK_FEEDBACKに与える論理値で指定します。
CLKINは、そのままの周波数か分周1/2にして
CLKDVに出力できます。
この指定は、CLKDV_DIVIDEを使います。
CLKDV_DIVIDEは、指定値が決まっています。
次のように小数第1位まで指定します。
- 1.5
- 2.0
- 2.5
- 3.0
- 3.5
- 4.0
- 4.5
- 5.0
- 5.5
- 6.0
- 6.5
- 7.0
- 7.5
- 8.0
- 9.0
- 10.0
- 11.0
- 12.0
- 13.0
- 14.0
- 15.0
- 16.0
CLKFX、CLKFX180
DFS(Digital Frequency Synthesizer)を使い、PLLのように
CLKINの周波数から、次の2パラメータで、目的の周波数を
合成します。
CLKFX_MULTIPLY
CLKFX_DIVIDE
周波数は、次の式で計算できます。
(CLKFX_MULTIPLY / CLKFX_DIVIDE ) x (CLKINの周波数)
2つのパラメータには、範囲制限があります。
CLKFX_MULTIPLY : 整数で2〜32(ステップは1刻み)
CLKFX_DIVIDE : 整数で1〜32(ステップは1刻み)
DFSを使う時、CLKINの周波数は1MHz〜326MHzです。
PSCLK、PSEN、PSINCDEC
生成クロックの位相をずらしたいとき、Phase Shifter
(位相シフター)を利用します。
PSを使うか使わないかは、CLKOUT_PHASE_SHIFTで指定します。
NONE、FIXED、VARIABLEのいずれかを設定します。
- NONE PSは使わない
- FIXED PSを使い、位相は90度単位で固定
- VARIABLE PSを使い、位相はパラメータの指定値分シフト
実際にPSを動かす場合、使うかどうかの指定は
PSENに設定する論理値に依存します。
PSEN <= '1' PSをenable
PSEN <= '0' PSをdisable
位相のもとになるクロックが必要なので
PSCLKに、CLKIN、CLK0、CLK2Xのいずれかを
接続します。
ブロック図にあるPSINCDECには、位相をPSCLKの1/256刻みで
進みか遅れのいずれかに指定します。どちらの方向にずらす
のかを論理値で与えます。
PHASE_SHIFTに、-255から+255を設定するとともに
PSINCDECに方向を表す論理値を設定します。
動作確認
3つのブロックのうち、DLL、DFSを利用して
モジュール動作を確認してみます。
手元にあるSpartan3の200kゲートボードには
48MHzのクリスタルが実装されているので、
この48MHzを利用して、「逓倍」による100MHz
を生成してみます。
100MHzクロックを生成しても、測定機器なしでは
確認できません。
100MHzでカウンタを動かし、1MHzまで周波数
を下げると、手持ちの周波数カウンタで観測
できます。
次のブロック図を描いて、信号のつながりを
確認してから、VHDLコードに変換します。
作成したVHDLコードは、以下。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Library UNISIM;
use UNISIM.vcomponents.all;
entity tdcm is
generic (
TOPX : integer := 5 ;
XMAX : integer := 24 -- ;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
CLK0_OUT : out std_logic ;
CLK90_OUT : out std_logic ;
CLK180_OUT : out std_logic ;
CLK270_OUT : out std_logic ;
CLKIN_IBUFG_OUT : out std_logic ;
--
COUT : out std_logic ;
COUTEX : out std_logic ;
SOUT : out std_logic -- ;
) ;
end tdcm;
architecture Behavioral of tdcm is
signal iCLKIN_IBUFG : std_logic ;
signal iCLKFB_IN : std_logic ;
signal iCLK0_OUT : std_logic ;
signal iCLK90_OUT : std_logic ;
signal iCLK180_OUT : std_logic ;
signal iCLK270_OUT : std_logic ;
signal iCLK90_BUF : std_logic ;
signal iCLK180_BUF : std_logic ;
signal iCLK270_BUF : std_logic ;
signal iCLKFX : std_logic ;
signal iCLKFX_OUT : std_logic ;
signal iCNTX : integer range 0 to 99 ;
-- component clock generator
component clkgenx is
generic (
TOPX : integer ;
RMAX : integer --;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
CLKOUT : out std_logic -- ;
);
end component ;
signal iSCLK : std_logic ;
signal iCNTX90 : integer range 0 to 99 ;
begin
-- component clock generator (48MHz/48 = 1MHz)
CLKX : clkgenx generic map (TOPX,XMAX) port map (nRESET,iCLKIN_IBUFG,iSCLK);
-- input clock buffer handling
IBUFG_inst : IBUFG
generic map (IOSTANDARD => "DEFAULT")
port map (
O => iCLKIN_IBUFG, -- Clock buffer output
I => CLOCK -- Clock buffer input (connect directly to top-level port)
);
-- output clock buffer handling
BUFG_inst : BUFG
port map (
O => iCLKFB_IN, -- Clock buffer output
I => iCLK0_OUT -- Clock buffer input
);
-- output clock buffer handling
BUFG_instX : BUFG
port map (
O => iCLKFX_OUT , -- Clock buffer output
I => iCLKFX -- Clock buffer input
);
-- DCM
DCM_inst : DCM
generic map (
CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
-- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
CLKFX_DIVIDE => 12, -- Can be any integer from 1 to 32
CLKFX_MULTIPLY => 25, -- Can be any integer from 2 to 32
CLKIN_DIVIDE_BY_2 => FALSE, -- TRUE/FALSE to enable CLKIN divide by two feature
CLKIN_PERIOD => 20.833, -- Specify period of input clock
CLKOUT_PHASE_SHIFT => "FIXED", -- Specify phase shift of NONE, FIXED or VARIABLE
CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE, 1X or 2X
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
-- an integer from 0 to 15
DFS_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for frequency synthesis
DLL_FREQUENCY_MODE => "LOW", -- HIGH or LOW frequency mode for DLL
DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE
FACTORY_JF => X"C080", -- FACTORY JF Values
PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255
SIM_MODE => "SAFE", -- Simulation: "SAFE" vs "FAST", see "Synthesis and Simulation
-- Design Guide" for details
STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE
port map (
CLK0 => iCLK0_OUT, -- 0 degree DCM CLK ouptput
CLK180 => iCLK180_OUT, -- 180 degree DCM CLK output
CLK270 => iCLK270_OUT, -- 270 degree DCM CLK output
CLK2X => open, -- 2X DCM CLK output
CLK2X180 => open, -- 2X, 180 degree DCM CLK out
CLK90 => iCLK90_OUT, -- 90 degree DCM CLK output
CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE)
CLKFX => iCLKFX, -- DCM CLK synthesis out (M/D)
CLKFX180 => open, -- 180 degree CLK synthesis out
LOCKED => open, -- DCM LOCK status output
PSDONE => open, -- Dynamic phase adjust done output
STATUS => open, -- 8-bit DCM status bits output
CLKFB => iCLKFB_IN, -- DCM clock feedback
CLKIN => iCLKIN_IBUFG, -- Clock input (from IBUFG, BUFG or DCM)
PSCLK => '0', -- Dynamic phase adjust clock input
PSEN => '0', -- Dynamic phase adjust enable input
PSINCDEC => '0', -- Dynamic phase adjust increment/decrement
RST => '0' -- DCM asynchronous reset input
);
-- check iSCLK about 1MHz
-- COUTEX = 10kHz
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iCNTX90 <= 0 ;
elsif rising_edge(iSCLK) then
if ( iCNTX90 = 99 ) then
iCNTX90 <= 0 ;
else
iCNTX90 <= iCNTX90 + 1 ;
end if ;
end if ;
end process ;
SOUT <= not iSCLK ;
COUTEX <= '1' when ( iCNTX90 = 0 ) else '0' ;
-- check DFS
-- CLKIN = 48MHz
-- CLKFX_MULTIPLY = 25 , CLKFX_DIVIDE = 12
-- CLKFX_OUT = 48 * (25 / 12) = 100 MHz
process (nRESET,iCLKFX_OUT)
begin
if ( nRESET = '0' ) then
iCNTX <= 0 ;
elsif rising_edge(iCLKFX_OUT) then
if ( iCNTX = 99 ) then
iCNTX <= 0 ;
else
iCNTX <= iCNTX + 1 ;
end if ;
end if ;
end process ;
COUT <= '1' when ( iCNTX = 0 ) else '0' ;
-- output
CLKIN_IBUFG_OUT <= not iCLKIN_IBUFG ;
iCLK90_BUF <= iCLK90_OUT ;
iCLK180_BUF <= iCLK180_OUT ;
iCLK270_BUF <= iCLK270_OUT ;
CLK0_OUT <= not iCLKFB_IN ;
CLK90_OUT <= not iCLK90_BUF ;
CLK180_OUT <= not iCLK180_BUF ;
CLK270_OUT <= not iCLK270_BUF ;
end Behavioral;
CLK0_OUT、CLK90_OUT、CLK180_OUT、CLK270_OUTの4信号は
48MHzですが、手持ちのマルチメータでは測定できません。
後日、CLKIN_DIVIDE_BY_2をTRUEにし24MHzが出力されること
を確認できました。また、オシロスコープで波形を表示させ
90度の位相差を持つことも確認しました。
COUTは、100MHzを100分周して1MHzが
出力されることで、間接的に100MHz
のクロック生成を確認しています。
測定は、Spartan3の200kゲートの基板を利用し
LED基板を接続して、マルチメータについている
周波数カウンタでクロック周波数を確認。
上のLED基板とFPGAボードを利用。
LEDのアノード、カソードに端子を出しているので
測定機器のプローブを接続できるようにしています。
周波数カウンタは、マルチメータのもつ機能を使いました。
マルチメータは、秋月電子\1000で販売されているP10です。
接続ピンは、次のUCFファイルに記述。
# tdcm user constraint file
NET "CLOCK" LOC = "P55" ;
NET "nRESET" LOC = "P73" ;
# group B1
NET "CLK0_OUT" LOC = "P116" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
NET "CLK90_OUT" LOC = "P113" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
NET "CLK180_OUT" LOC = "P119" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
NET "CLK270_OUT" LOC = "P118" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
NET "CLKIN_IBUFG_OUT" LOC = "P123" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
NET "COUT" LOC = "P122" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
NET "COUTEX" LOC = "P125" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
NET "SOUT" LOC = "P124" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
目次
前
次