Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Использование ISERDES2
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
ZZZRF413
Всем доброго дня!
Посоветуйте пожалуйста по следующему вопросу. Есть плата с Xilinx Spartan-6 FPGA (XC6SLX100T-3FGG676C). Необходимо записать данные с АЦП (AD9434) в ОЗУ (тип DDR2). АЦП работает на частоте порядка 400 МГц. Тактовые частоты для ПЛИС и АЦП формируются с помощью микросхемы AD9518. Я хочу задействовать ISERDES2, для того чтобы в ПЛИС работать на меньшей частоте, но к сожалению пока не очень получается.
Я делал как ug382 разными способами и через BUFIO2 и через PLL_BASE, но на этапе MAP вылетает ошибка (см. приложение). Через IP тоже не работает, также вылетает ошибка. Часть электрической схемы платы так же в приложении. Собственно вопрос в чем причина ошибки и как её можно исправить?

Код:
Формирование тактового сигнала
CODE
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 08:29:32 01/13/2015
-- Design Name:
-- Module Name: CLK_Module - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity CLOCK is
Port ( clk0_p : in STD_LOGIC;
clk0_n : in STD_LOGIC;
clk_in : in STD_LOGIC;
clk_out : out STD_LOGIC;
clk0_out : out STD_LOGIC;
dclk0_out : out STD_LOGIC;
SerDes_Strobe : out STD_LOGIC;
SerDes_CLK : out STD_LOGIC);
end CLOCK;

architecture Behavioral of CLOCK is

attribute IOSTANDARD : string;
attribute DIFF_TERM : string;
attribute IBUF_DELAY_VALUE : string;
attribute IFD_DELAY_VALUE : string;
attribute DIVIDE : string;
attribute DIVIDE_BYPASS : string;
attribute I_INVERT : string;
attribute USE_DOUBLER : string;
attribute ENABLE_SYNC : string;
attribute COMPENSATION : string;
attribute BANDWIDTH : string;
attribute CLKOUT0_DIVIDE : string;
attribute CLKOUT0_PHASE : string;
attribute CLKOUT0_DUTY_CYCLE : string;
attribute CLKOUT1_DIVIDE : string;
attribute CLKOUT1_PHASE : string;
attribute CLKOUT1_DUTY_CYCLE : string;
attribute CLKOUT2_DIVIDE : string;
attribute CLKOUT2_PHASE : string;
attribute CLKOUT2_DUTY_CYCLE : string;
attribute CLKOUT3_DIVIDE : string;
attribute CLKOUT3_PHASE : string;
attribute CLKOUT3_DUTY_CYCLE : string;
attribute CLKOUT4_DIVIDE : string;
attribute CLKOUT4_PHASE : string;
attribute CLKOUT4_DUTY_CYCLE : string;
attribute CLKOUT5_DIVIDE : string;
attribute CLKOUT5_PHASE : string;
attribute CLKOUT5_DUTY_CYCLE : string;
attribute CLKFBOUT_MULT : string;
attribute DIVCLK_DIVIDE : string;
attribute CLKFBOUT_PHASE : string;
attribute REF_JITTER : string;
attribute CLKIN_PERIOD : string;
attribute CLK_FEEDBACK : string;
attribute RESET_ON_LOSS_OF_LOCK : string;
attribute BOX_TYPE : string;

component IBUFGDS
-- synopsys translate_off
generic( DIFF_TERM : boolean := FALSE);
-- synopsys translate_on
port ( I : in std_logic;
IB : in std_logic;
O : out std_logic);
end component;
attribute IOSTANDARD of IBUFGDS : component is "DEFAULT";
-- attribute IOSTANDARD of IBUFGDS : component is "LVPECL_33";
attribute DIFF_TERM of IBUFGDS : component is "FALSE";
attribute IBUF_DELAY_VALUE of IBUFGDS : component is "0";
attribute BOX_TYPE of IBUFGDS : component is "BLACK_BOX";

component BUFIO2
port ( I : in std_logic;
IOCLK : out std_logic;
DIVCLK : out std_logic;
SERDESSTROBE : out std_logic);
end component;
attribute DIVIDE of BUFIO2 : component is "4";
attribute DIVIDE_BYPASS of BUFIO2 : component is "FALSE";
attribute I_INVERT of BUFIO2 : component is "FALSE";
attribute USE_DOUBLER of BUFIO2 : component is "FALSE";
attribute BOX_TYPE of BUFIO2 : component is "BLACK_BOX";

component BUFG
port (I : in std_logic;
O : out std_logic);
end component;
attribute BOX_TYPE of BUFG : component is "BLACK_BOX";

component BUFPLL
port (
PLLIN : in std_logic;
GCLK : in std_logic;
LOCKED : in std_logic;
IOCLK : out std_logic;
SERDESSTROBE : out std_logic;
LOCK : out std_logic
);
end component;

attribute DIVIDE of BUFPLL : component is "4";
attribute ENABLE_SYNC of BUFPLL : component is "TRUE";
attribute BOX_TYPE of BUFPLL : component is "BLACK_BOX";
component PLL_BASE
port (
CLKIN : in std_logic;
CLKFBIN : in std_logic;
RST : in std_logic;
CLKOUT0 : out std_logic;
CLKOUT1 : out std_logic;
CLKOUT2 : out std_logic;
CLKOUT3 : out std_logic;
CLKOUT4 : out std_logic;
CLKOUT5 : out std_logic;
CLKFBOUT : out std_logic;
LOCKED : out std_logic
);
end component;
attribute COMPENSATION of PLL_BASE : component is "SYSTEM_SYNCHRONOUS";
attribute BANDWIDTH of PLL_BASE : component is "OPTIMIZED";
attribute CLKOUT0_DIVIDE of PLL_BASE : component is "1";
attribute CLKOUT0_PHASE of PLL_BASE : component is "0.0";
attribute CLKOUT0_DUTY_CYCLE of PLL_BASE : component is "0.5";
attribute CLKOUT1_DIVIDE of PLL_BASE : component is "4";
attribute CLKOUT1_PHASE of PLL_BASE : component is "0.0";
attribute CLKOUT1_DUTY_CYCLE of PLL_BASE : component is "0.5";
attribute CLKOUT2_DIVIDE of PLL_BASE : component is "1";
attribute CLKOUT2_PHASE of PLL_BASE : component is "0.0";
attribute CLKOUT2_DUTY_CYCLE of PLL_BASE : component is "0.5";
attribute CLKOUT3_DIVIDE of PLL_BASE : component is "1";
attribute CLKOUT3_PHASE of PLL_BASE : component is "0.0";
attribute CLKOUT3_DUTY_CYCLE of PLL_BASE : component is "0.5";
attribute CLKOUT4_DIVIDE of PLL_BASE : component is "1";
attribute CLKOUT4_PHASE of PLL_BASE : component is "0.0";
attribute CLKOUT4_DUTY_CYCLE of PLL_BASE : component is "0.5";
attribute CLKOUT5_DIVIDE of PLL_BASE : component is "1";
attribute CLKOUT5_PHASE of PLL_BASE : component is "0.0";
attribute CLKOUT5_DUTY_CYCLE of PLL_BASE : component is "0.5";
attribute CLKFBOUT_MULT of PLL_BASE : component is "1";
attribute CLKFBOUT_PHASE of PLL_BASE : component is "0.0";
attribute DIVCLK_DIVIDE of PLL_BASE : component is "1";
attribute REF_JITTER of PLL_BASE : component is "0.1";
attribute CLKIN_PERIOD of PLL_BASE : component is "2.5";
attribute RESET_ON_LOSS_OF_LOCK of PLL_BASE : component is "FALSE";
attribute BOX_TYPE of PLL_BASE : component is "BLACK_BOX";

component BUFIO2FB
-- synopsys translate_off
generic( DIVIDE_BYPASS : boolean := TRUE);
-- synopsys translate_on
port ( I : in std_logic;
O : out std_logic);
end component;
attribute DIVIDE_BYPASS of BUFIO2FB : component is "TRUE";
attribute BOX_TYPE of BUFIO2FB : component is "BLACK_BOX";

signal clk0_pll:std_logic:='0';
signal clk0:std_logic:='0';
signal clk0fb:std_logic:='0';
signal dclk0:std_logic:='0';
signal LOCKED:std_logic:='0';
signal clk0_out0:std_logic:='0';
signal clk0_out1:std_logic:='0';
signal SD_CLK:std_logic:='0';

begin

CLK0_DIFF_BUF : IBUFGDS
port map( I => clk0_p,
IB => clk0_n,
O => clk0);

CLK_BUF : BUFG
port map( I => clk_in,
O => clk_out);
--CLK0_BUFIO2: BUFIO2
-- port map ( I => clk0,
-- IOCLK => SerDes_CLK,
-- DIVCLK => dclk0,
-- SERDESSTROBE => SerDes_Strobe
-- );
CLK0_BUFIO2: BUFIO2
port map ( I => clk0,
IOCLK => open,
DIVCLK => clk0_pll,
SERDESSTROBE => open
);
CLK0PLL:PLL_BASE
port map ( CLKIN => clk0_pll,
CLKFBIN => clk0fb,
RST => '0',
CLKOUT0 => clk0_out0,
CLKOUT1 => clk0_out1,
CLKOUT2 => open,
CLKOUT3 => open,
CLKOUT4 => open,
CLKOUT5 => open,
CLKFBOUT => open,
LOCKED => LOCKED
);
CLK0_BUFFPLL:BUFPLL
port map ( PLLIN => clk0_out0,
GCLK => dclk0,
LOCKED => LOCKED,
IOCLK => SD_CLK,
SERDESSTROBE => SerDes_Strobe,
LOCK => open
);

CLK0_FB: BUFIO2FB
port map( I => SD_CLK,
O => clk0fb);
DCLK0_BUF : BUFG
port map( I => clk0_out1,
O => dclk0);

SerDes_CLK<=SD_CLK;
clk0_out<=clk0;
dclk0_out<=dclk0;
end Behavioral;

Прием данных с АЦП
CODE
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 09:15:39 01/13/2015
-- Design Name:
-- Module Name: Tochnost_FPGA_ADC_BUF - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity ADC_BUFFER is
Port (
Divclk : in STD_LOGIC;
SerDes_Strobe : in STD_LOGIC;
SerDes_CLK : in STD_LOGIC;
ADC1_D_P : in STD_LOGIC_VECTOR (11 downto 0);
ADC1_D_N : in STD_LOGIC_VECTOR (11 downto 0);
ADC1_OR_P : in STD_LOGIC;
ADC1_OR_N : in STD_LOGIC;
ADC1_DCO_P : in STD_LOGIC;
ADC1_DCO_N : in STD_LOGIC;
ADC2_D_P : in STD_LOGIC_VECTOR (11 downto 0);
ADC2_D_N : in STD_LOGIC_VECTOR (11 downto 0);
ADC2_OR_P : in STD_LOGIC;
ADC2_OR_N : in STD_LOGIC;
ADC2_DCO_P : in STD_LOGIC;
ADC2_DCO_N : in STD_LOGIC;
ADC1_DATA : out STD_LOGIC_VECTOR (47 downto 0);
ADC2_DATA : out STD_LOGIC_VECTOR (47 downto 0));
end ADC_BUFFER;

architecture Behavioral of ADC_BUFFER is

attribute IOSTANDARD : string;
attribute DIFF_TERM : string;
attribute IBUF_DELAY_VALUE : string;
attribute IFD_DELAY_VALUE : string;
attribute DATA_RATE : string;
attribute DATA_WIDTH : string;
attribute BITSLIP_ENABLE : string;
attribute SERDES_MODE : string;
attribute INTERFACE_TYPE : string;
attribute IDELAY_VALUE : string;
attribute IDELAY2_VALUE : string;
attribute IDELAY_MODE : string;
attribute ODELAY_VALUE : string;
attribute IDELAY_TYPE : string;
attribute COUNTER_WRAPAROUND : string;
attribute DELAY_SRC : string;
-- attribute SERDES_MODE : string;
attribute SIM_TAP_DELAY : string;
-- attribute DATA_RATE : string;
attribute BOX_TYPE : string;

component IBUFDS
-- synopsys translate_off
generic( DIFF_TERM : boolean := FALSE);
-- synopsys translate_on
port ( I : in std_logic;
IB : in std_logic;
O : out std_logic);
end component;
attribute IOSTANDARD of IBUFDS : component is "DEFAULT";
-- attribute IOSTANDARD of IBUFGDS : component is "LVPECL_33";
attribute DIFF_TERM of IBUFDS : component is "FALSE";
attribute IBUF_DELAY_VALUE of IBUFDS : component is "0";
attribute BOX_TYPE of IBUFDS : component is "BLACK_BOX";

component IODELAY2
port (
IDATAIN : in std_logic;
T : in std_logic;
ODATAIN : in std_logic;
CAL : in std_logic;
IOCLK0 : in std_logic;
IOCLK1 : in std_logic;
CLK : in std_logic;
INC : in std_logic;
CE : in std_logic;
RST : in std_logic;
BUSY : out std_logic;
DATAOUT : out std_logic;
DATAOUT2 : out std_logic;
TOUT : out std_logic;
DOUT : out std_logic
);
end component;

attribute IDELAY_VALUE of IODELAY2 : component is "0";
attribute IDELAY2_VALUE of IODELAY2 : component is "0";
attribute IDELAY_MODE of IODELAY2 : component is "NORMAL";
attribute ODELAY_VALUE of IODELAY2 : component is "0";
attribute IDELAY_TYPE of IODELAY2 : component is "DEFAULT";
attribute COUNTER_WRAPAROUND of IODELAY2 : component is "STAY_AT_LIMIT";
attribute DELAY_SRC of IODELAY2 : component is "IDATAIN";
attribute SERDES_MODE of IODELAY2 : component is "NONE";
attribute SIM_TAP_DELAY of IODELAY2 : component is "50";
attribute DATA_RATE of IODELAY2 : component is "SDR";
attribute BOX_TYPE of IODELAY2 : component is "BLACK_BOX";

component ISERDES2
port ( CLK0 : in std_logic;
CLK1 : in std_logic;
CLKDIV : in std_logic;
CE0 : in std_logic;
BITSLIP : in std_logic;
D : in std_logic;
RST : in std_logic;
IOCE : in std_logic;
SHIFTIN : in std_logic;
CFB0 : out std_logic;
CFB1 : out std_logic;
DFB : out std_logic;
SHIFTOUT : out std_logic;
FABRICOUT : out std_logic;
Q4 : out std_logic;
Q3 : out std_logic;
Q2 : out std_logic;
Q1 : out std_logic;
VALID : out std_logic;
INCDEC : out std_logic
);
end component;

attribute DATA_RATE of ISERDES2 : component is "SDR";
attribute DATA_WIDTH of ISERDES2 : component is "4";
attribute BITSLIP_ENABLE of ISERDES2 : component is "FALSE";
attribute SERDES_MODE of ISERDES2 : component is "NONE";
attribute INTERFACE_TYPE of ISERDES2 : component is "NETWORKING";
attribute BOX_TYPE of ISERDES2 : component is "BLACK_BOX";

signal ADC1_D:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC1_D1:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC1_D2:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC1_D3:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC1_D4:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC1_D_Delayed:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC2_D:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC2_D1:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC2_D2:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC2_D3:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC2_D4:std_logic_vector(11 downto 0):=(others=>'0');
signal ADC2_D_Delayed:std_logic_vector(11 downto 0):=(others=>'0');
begin

ADC1_DATA_BUFFERS:
for i in 0 to 11 generate
ADC1_D_BUF : IBUFDS
port map( I => ADC1_D_p(i),
IB => ADC1_D_n(i),
O => ADC1_D(i));
ADC1_D_IODELAY : IODELAY2
port map(
IDATAIN => ADC1_D(i),
T => '1',
ODATAIN => '0',
CAL => '0',
IOCLK0 => SerDes_CLK,
IOCLK1 => '0',
CLK => Divclk,
INC => '1',
CE => '1',
RST => '0',
BUSY => open,
DATAOUT => ADC1_D_Delayed(i),-- to SERDES
DATAOUT2 => open, -- to FPGA Logic
TOUT => open,
DOUT => open
);
ADC1_D_SERDER : ISERDES2
port map(
CLK0 => SerDes_CLK,
CLK1 => '0',
CLKDIV => Divclk,
CE0 => '1',
BITSLIP => '0',
D => ADC1_D_Delayed(i),
RST => '0',
IOCE => SerDes_Strobe,
SHIFTIN => '0',
CFB0 => open,
CFB1 => open,
DFB => open,
SHIFTOUT => open,
FABRICOUT => open, -- to FPGA Logic
Q4 => ADC1_D4(i),
Q3 => ADC1_D3(i),
Q2 => ADC1_D2(i),
Q1 => ADC1_D1(i),
VALID => open,
INCDEC => open
);

ADC1_DATA(i)<=ADC1_D1(i);
ADC1_DATA(i+12)<=ADC1_D2(i);
ADC1_DATA(i+24)<=ADC1_D3(i);
ADC1_DATA(i+36)<=ADC1_D4(i);
end generate ADC1_DATA_BUFFERS;

ADC2_DATA_BUFFERS:
for i in 0 to 11 generate
ADC2_D_BUF : IBUFDS
port map( I => ADC2_D_p(i),
IB => ADC2_D_n(i),
O => ADC2_D(i));
ADC2_D_IODELAY : IODELAY2
port map(
IDATAIN => ADC2_D(i),
T => '1',
ODATAIN => '0',
CAL => '0',
IOCLK0 => SerDes_CLK,
IOCLK1 => '0',
CLK => Divclk,
INC => '1',
CE => '1',
RST => '0',
BUSY => open,
DATAOUT => ADC2_D_Delayed(i),-- to SERDES
DATAOUT2 => open, -- to FPGA Logic
TOUT => open,
DOUT => open
);
ADC2_D_SERDER : ISERDES2
port map(
CLK0 => SerDes_CLK,
CLK1 => '0',
CLKDIV => Divclk,
CE0 => '1',
BITSLIP => '0',
D => ADC2_D_Delayed(i),
RST => '0',
IOCE => SerDes_Strobe,
SHIFTIN => '0',
CFB0 => open,
CFB1 => open,
DFB => open,
SHIFTOUT => open,
FABRICOUT => open, -- to FPGA Logic
Q4 => ADC2_D4(i),
Q3 => ADC2_D3(i),
Q2 => ADC2_D2(i),
Q1 => ADC2_D1(i),
VALID => open,
INCDEC => open
);

ADC2_DATA(i)<=ADC2_D1(i);
ADC2_DATA(i+12)<=ADC2_D2(i);
ADC2_DATA(i+24)<=ADC2_D3(i);
ADC2_DATA(i+36)<=ADC2_D4(i);
end generate ADC2_DATA_BUFFERS;
ADC1_OR_BUF : IBUFDS
port map( I => ADC1_OR_p,
IB => ADC1_OR_n,
O => open);
ADC1_DCO_BUF : IBUFDS
port map( I => ADC1_DCO_p,
IB => ADC1_DCO_n,
O => open);
ADC2_OR_BUF : IBUFDS
port map( I => ADC2_OR_p,
IB => ADC2_OR_n,
O => open);
ADC2_DCO_BUF : IBUFDS
port map( I => ADC2_DCO_p,
IB => ADC2_DCO_n,
O => open);

end Behavioral;
serjj
У вас скорее всего BUFPLL и ножки входные в разных IO банках оказались, а компонент BUFPLL жёстко привязан к своему банку. Скидайте их констрейнами в один банк, можно через ГУИ прям, тогда должно развестись
ZZZRF413
Цитата(serjj @ Jan 13 2015, 17:19) *
У вас скорее всего BUFPLL и ножки входные в разных IO банках оказались, а компонент BUFPLL жёстко привязан к своему банку. Скидайте их констрейнами в один банк, можно через ГУИ прям, тогда должно развестись

serjj, большое спасибо! Действительно они находятся в разных банках. Прописал позицию вручную через LOC для PLLBUF и BUFIO2 и все заработало. Единственное только пришлось упростить обратную связь убрав BUFIO2FB.
Bad0512
Цитата(ZZZRF413 @ Jan 14 2015, 12:33) *
serjj, большое спасибо! Действительно они находятся в разных банках. Прописал позицию вручную через LOC для PLLBUF и BUFIO2 и все заработало. Единственное только пришлось упростить обратную связь убрав BUFIO2FB.

Можно сделать проще, без PLL. Но для этого надо завести DCO с обеих АЦПеек на соответствующий клоковый вход. И чтобы все биты данных были в соответствующем банке.
ZZZRF413
Ну вот рано я обрадовался...
Теперь тайминги никакие... Fmax 13 MHz
Цитата(Bad0512 @ Jan 14 2015, 14:42) *
Можно сделать проще, без PLL. Но для этого надо завести DCO с обеих АЦПеек на соответствующий клоковый вход. И чтобы все биты данных были в соответствующем банке.

К сожалению так сделать нельзя. Плата физически уже есть, а DCO на клоковый вход не заведен sad.gif

Я думаю тут надо попробовать 2 PLL поставить. Один в банке где, вход тактового сигнала, а другой в банке где входы данных с АЦП.
Timmy
Цитата(ZZZRF413 @ Jan 14 2015, 16:53) *
К сожалению так сделать нельзя. Плата физически уже есть, а DCO на клоковый вход не заведен sad.gif

На 400Msps это не проблема. Можно применить тактирование на 800МГц и динамическую подстройку фазы PLL по фронтам ADC_DCO с обычных пинов. Причём для каждого АЦП свою фазу, если получится подключить к разным АЦП разные выходы PLL. Данное решение получится более точным, чем непосредственное использование ADC_DCO с клокового входа.
ZZZRF413
Цитата(Timmy @ Jan 15 2015, 12:39) *
На 400Msps это не проблема. Можно применить тактирование на 800МГц и динамическую подстройку фазы PLL по фронтам ADC_DCO с обычных пинов. Причём для каждого АЦП свою фазу, если получится подключить к разным АЦП разные выходы PLL. Данное решение получится более точным, чем непосредственное использование ADC_DCO с клокового входа.


Что-то я не совсем понял... "если получится подключить к разным АЦП разные выходы PLL" - это как? Тактовый сигнал на АЦП не идет с FPGA, его формирует отдельная микросхема на плате - AD9518. Она же формирует тактовый сигнал на ПЛИС. Или имеется ввиду схема наподобии как в приложении?
SM
Вообще, DCO заводить на клоковый пин вредно. DCO надо рассматривать как вход данных, так как частота DCO может меняться в зависимости от настройки АЦП (его там делить можно, уменьшая частоту дискретизации). Поэтому, лучше всего, если на клоковый пин заведен входной клок АЦП, а там уже вполне себе четкие Tco(min) и Tco(max) прописаны у АЦП (в даташите на АЦП, Tpd/Tcpd), так что можно спокойно прописать констрейны на сетап и холд для FPGA по DCO и данным, там вилка получается достаточной, чтобы быть выдержанной. Ошибки по этим констрейнам можно исправлять как подстройкой фазы входного клока на PLL (фиксированное, на конкретное числовое значение), так и изменением задержки внутри I/O пада (если таковая доступна для конкретной FPGA)

Ну а DCO использовать совместно с данными - данное считается валидным только тогда, когда на DCO (с DDR-приемом) произошла смена уровня.
Timmy
Цитата(ZZZRF413 @ Jan 16 2015, 14:37) *
Что-то я не совсем понял... "если получится подключить к разным АЦП разные выходы PLL" - это как? Тактовый сигнал на АЦП не идет с FPGA, его формирует отдельная микросхема на плате - AD9518. Она же формирует тактовый сигнал на ПЛИС. Или имеется ввиду схема наподобии как в приложении?

Фразу надо уточнить - к входам от разных АЦП разные выходы PLL. Каждому АЦП свой PLLBUF.
dm.pogrebnoy
Цитата(SM @ Jan 16 2015, 15:23) *
Вообще, DCO заводить на клоковый пин вредно. DCO надо рассматривать как вход данных, так как частота DCO может меняться в зависимости от настройки АЦП (его там делить можно, уменьшая частоту дискретизации). Поэтому, лучше всего, если на клоковый пин заведен входной клок АЦП, а там уже вполне себе четкие Tco(min) и Tco(max) прописаны у АЦП (в даташите на АЦП, Tpd/Tcpd), так что можно спокойно прописать констрейны на сетап и холд для FPGA по DCO и данным, там вилка получается достаточной, чтобы быть выдержанной. Ошибки по этим констрейнам можно исправлять как подстройкой фазы входного клока на PLL (фиксированное, на конкретное числовое значение), так и изменением задержки внутри I/O пада (если таковая доступна для конкретной FPGA)

Ну а DCO использовать совместно с данными - данное считается валидным только тогда, когда на DCO (с DDR-приемом) произошла смена уровня.


Интересно, для 1-3 ГГц АЦП тоже входной такт АЦП заводить на ПЛИС? По-моему лишнее это, все отлично работает с DCO, а то что он меняться может, обычно жестко завязано на режим работы преобразователя, с которым нужно заранее определиться.

По топику, я бы поставил в IOB фазовый детектор, по которому подстраивал бы фазу сигнала с DCM.
SM
Цитата(dm.pogrebnoy @ Jan 19 2015, 09:52) *
Интересно, для 1-3 ГГц АЦП тоже входной такт АЦП заводить на ПЛИС? По-моему лишнее это, все отлично работает с DCO, а то что он меняться может, обычно жестко завязано на режим работы преобразователя, с которым нужно заранее определиться.


Это, как сказать. У меня, к примеру, частотой DCO рулят программисты, как хотят. А система должна работать. Для 1-3 ГГц, я думаю, все будет по-другому, DCO надо будет уже заводить на DQS-входы и использовать примитивы приема сигнала и переноса ее на внутреннюю тактовую от DDR памяти. И, вообще, я не знаю таких ПЛИС, которые могут принять по LVDS 2-3 гигабита. Это уже прерогатива гигабитных трансиверов.
dm.pogrebnoy
Цитата(SM @ Jan 19 2015, 11:58) *
Это, как сказать. У меня, к примеру, частотой DCO рулят программисты, как хотят. А система должна работать. Для 1-3 ГГц, я думаю, все будет по-другому, DCO надо будет уже заводить на DQS-входы и использовать примитивы приема сигнала и переноса ее на внутреннюю тактовую от DDR памяти. И, вообще, я не знаю таких ПЛИС, которые могут принять по LVDS 2-3 гигабита. Это уже прерогатива гигабитных трансиверов.


Во всех устройствах, по моему опыту, DCO достаточно жестко задается конфигурацией аппаратной части, и просто так поменять не получится (не заработает). Хотя не исключаю возможности других вариантов использования DCO, надо смотреть конкретную м/сх.
И обычно получается не 2-3 гигабита, а меньше.
ADS5400 1 ГГц тактовая, 500 МБит LVDS, 250 МГц в DDR. Принимает Spartan-6.
ADC08300 3 ГГц таковая, 700 Мбит LVDS, 350 МГц в DDR. Принимал когда-то даже Virtex-4, cейчас Virtex-6.

Для более скоростных преобразователей JESD204 входит в моду. Там да, гигабитные приемо-передатчики.
SM
Цитата(dm.pogrebnoy @ Jan 19 2015, 13:40) *
и просто так поменять не получится (не заработает).

Вот именно поэтому, я и описал, как сделать так, чтобы заработало. И заодно убить второго зайца, о котором тема.
Сколько я видел АЦП от AD - там у всех (виденных) имеется регистр 0x0B - Clock divide (global) - которым можно менять частоту преобразования, и, соотв., DCO. Но, при этом, тайминги CLK->[DCO, DATA] не меняются. Только фронты на них реже становятся.

Цитата(dm.pogrebnoy @ Jan 19 2015, 13:40) *
250 МГц в DDR.

Не думаю, что при 250 МГц будут проблемы с приемом DCO как DDR-бита данных. У меня DCO может быть от 125/16 (чуть больше 7) до 125 МГц, но запас в обе стороны по отчету STA - по холду 1.6 нс, по сетапу 0.866 нс, это значит, что Fmax в этом месте 325 МГц (с учетом, что это DDR, то есть, за период берется пол-периода). Хотя, тут еще надо учитывать, какая вилка у min <= Tpd <= max у конкретного АЦП
Bad0512
Клок с АЦП заводить на ПЛИС напрямую не рекомендуется по следующим причинам :
В случае Схемы типа источник клока -> clock distributor с двумя выходами -> с его выходов один клок идёт на ПЛИС, а другой на АЦП.
Здесь появляется в цепи клока клок дистрибьютор - это дополнительный источник джиттера, что ухудшает характеристики АЦП. Кроме этого ещё и дополнительное
потребление плюс стоимость самого компонента.
Кроме того в этом варианте разница в путях распространения distributor->ADC и distributor->FPGA неконтролируема и нигде не учитывается, на высоких частотах может быть критично.
Как правило времянки выходных данных АЦП нормируются именно по отношению к DCO, а не к сэмплирующему клоку. И это неслучайно. Кроме того в продвинутых моделях АЦП-ЦАП есть механизм
плавной подстройки DCO относительно данных, что практически исключает необходимость геморроя с IDELAY2 внутри ПЛИС - зачем плодить механизмы подстройки фазы если они уже есть?
В общем, DCO как раз для этой цели и придуман чтобы сопровождать данные, и да, его частота в общем случае может и не совпадать с сэмплирующей (например если выход полифазный).
Это не баг, это фича. Делается для большего удобства дизайна интерфейсов к ПЛИС.
З Ы Для шустрых АЦП JESD204 - не единственный вариант, хотя и очень распространённый. Некоторые разбивают выход на несколько фаз, плюс фазы работают в DDR режиме.
Для исключения зависящих от цифровых данных спурсов применяют скремблирование.
SM
Цитата(Bad0512 @ Jan 20 2015, 06:29) *
Кроме того в этом варианте разница в путях распространения distributor->ADC и distributor->FPGA неконтролируема и нигде не учитывается,

Ну это в корне неверно, она учитывается добавлением соответствующего пессимизма к setup и hold констрейнам (set_input_delay), равного джиттер + разница в путях. И отлично контролируема, так как все это хорощо документировано (для дистрибьютеров), или рассчитывается (для длин дорожек и емкостей нагрузок) - Смотрим отчет STA, и видим все как на ладони, сколько запаса по чему.

Цитата(Bad0512 @ Jan 20 2015, 06:29) *
Как правило времянки выходных данных АЦП нормируются именно по отношению к DCO, а не к сэмплирующему клоку.

Как правило, они нормируются и к тому, и к другому. Для DCO определяют расхождение +- от данных, а для входного клока - время распространения от входного клока до DCO и до данных.

PS.
Офигенное удобство - делать переход с клока DCO на основной клок ПЛИС для каждого подключенного АЦП, когда еще и заранее неизвестно, какая частота на DCO придет, как ее вздумается пользователю поделить внутри АЦП, докучи, по-разному для нескольких АЦП... И еще. Пока не настроен АЦП, клок с DCO идет, как правило не в том виде - например, CMOS, вместо LVDS, который нужен ПЛИСе. Это еще одна причина не использовать его как основной клок ПЛИС, а брать с дистрибьютера отдельный. Нормальный дистрибьютер джиттера привносит так мало, что им пренебречь можно.
Bad0512
Цитата(SM @ Jan 20 2015, 15:02) *
Офигенное удобство - делать переход с клока DCO на основной клок ПЛИС для каждого подключенного АЦП, когда еще и заранее неизвестно, какая частота на DCO придет, как ее вздумается пользователю поделить внутри АЦП, докучи, по-разному для нескольких АЦП... И еще. Пока не настроен АЦП, клок с DCO идет, как правило не в том виде - например, CMOS, вместо LVDS, который нужен ПЛИСе. Это еще одна причина не использовать его как основной клок ПЛИС, а брать с дистрибьютера отдельный. Нормальный дистрибьютер джиттера привносит так мало, что им пренебречь можно.

Если клоки отличаются только по фазе (например несколько АЦП с общим исходным клоком) то переход вообще тривиален. Если клоки разные по частоте, то переход чуть сложнее. Опять же не совсем понятно почему бы не работать на клоке DCO, чем он плох? Конфигурирование АЦП - процесс не слишком сложный, делается простеньким софт процессором (пикоблейз,микроблейз или что-то ещё), который в свою очередь тактируется независимым клоком.
dm.pogrebnoy
Цитата(SM @ Jan 20 2015, 12:02) *
Офигенное удобство - делать переход с клока DCO на основной клок ПЛИС для каждого подключенного АЦП, когда еще и заранее неизвестно, какая частота на DCO придет, как ее вздумается пользователю поделить внутри АЦП, докучи, по-разному для нескольких АЦП... И еще. Пока не настроен АЦП, клок с DCO идет, как правило не в том виде - например, CMOS, вместо LVDS, который нужен ПЛИСе.


Вы пытаетесь нас убедить в том, что тактировать от DCO свои управляющие автоматы не всегда корректно. Так с вами никто и не спорит. Для этого нужен отдельный опорный генератор. А вот уж данные принимать можно начать после того, как все устройства в системе сконфигурированы теми самыми автоматами, и когда точно известно что, где, откуда и в каком виде приходит. А программистам нечего лезть в то, в чем они не разбираются. И вы должны им выдать четкие требования что можно, а что нельзя.
SM
Цитата(dm.pogrebnoy @ Jan 20 2015, 13:34) *
Для этого нужен отдельный опорный генератор.

Вот именно, отдельный. И переход в его домен из доменов со всех DCO всех АЦП системы... Геморрой. А так, все АЦП работают от одного качественного источника тактов, ПЛИС - тоже, и сразу принимает на главном такте данные от всех АЦП, несмотря на то, что они могут работать с разной частотой дискретизации, заданной программистом. Просто и удобно. Я хочу показать, что такая схема добавляет удобства в проект ПЛИС и расширяет возможности по программированию частоты DCO.

Цитата(dm.pogrebnoy @ Jan 20 2015, 13:34) *
А программистам нечего лезть в то, в чем они не разбираются. И вы должны им выдать четкие требования что можно, а что нельзя.

Это, как сказать... У меня наоборот - программистам лишь требование не менять фазу DCO, и режимы I/O (понятно почему). А уметь менять частоту дискретизации - это их полное право. ПЛИС сама это должна понять, и корректно все принять.

Цитата(Bad0512 @ Jan 20 2015, 12:41) *
Опять же не совсем понятно почему бы не работать на клоке DCO, чем он плох?

DCO плох тем, что, получается, что каждому АЦП свой клоковый домен. Плюс некий анализатор частоты DCO (ну мне бы понадобился, а так, видимо, опционально). Плюс отдельный генератор для работы того, что занимается конфигурированием АЦП - совсем лишний домен. Зачем делать кучу доменов, когда можно работать на одном общем клоке, и совершенно беззатратно автоматизировать обработку задания частоты DCO. Просто глобальное упрощение всей схемы и экономия ресурсов.

Единственное, можно рассмотреть использование DCO для подачи на вход DQS, и использовать блок выравнивания данных от DDR-памяти (DQSBUFF у латиса, как он у ксилинкса называется, я не знаю), но тут я не уверен, что это все удастся, хотя, по идее, должно. И, опять же, будут отдельные проблемы с анализом текущей частоты DCO.
ZZZRF413
Я пока решил дальше продолжить делать схему, т.к. на мой взгляд пока не совсем честно смотреть тайминги, и там у меня возник ещё один вопрос. Как я уже говорил данные с АЦП необходимо сохранить в ОЗУ типа DDR2. Данные с ISERDES идут на вход порта IP контроллера памяти DDR2 сгенерированного MIG. Вопрос такой: Как c одного тактового входа ПЛИС затактировать все? А именно:
1) ISERDES (частота 400 МГц) - данные с АЦП
2) DDR2 (частота 400 МГц) - входной буфер данных
3) LPDDR (частота 200МГц) - выходной буфер данных

Я пробовал так:
clk0_p/n => IBUFGDS => PLL => BUFG => GCLK_400 { 1,2
1) => PLL => BUFPLL => ISERDES
2) => cX_sys_clk (DDR controller)

Выдает ошибку: нельзя последовательно использовать BUFG и IBUFG

По другому:
clk0_p/n { 1,2
1) => IBUFGDS => PLL => BUFG => GCLK_400 =>...
2) => cX_sys_clk (DDR controller)

Выдает ошибку: нельзя нагружать PAD (может быть только один компонент)

Как убрать/нейтролизовать IBUFG в IP контроллера DDR? (IP я подключал как компонент example_top.vhd)
ZZZRF413
Для данной платы я решил остановиться на тактирований от DCO, хотя я тоже считаю, что лучше работать от одного источника тактов.
Пришлось выставить параметр CLOCK_DEDICATED_ROUTE = FALSE, поскольку DCO заведен не на тактовый домен, задействовать PLL с BUFPLL и прописать их место положение, задать режим "Retimed" для ISERDES2.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.