Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Передача данных с Marvell'a в режиме GMII
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
ovs_pavel
Утро доброе. Коллеги, с приемом вроде бы разобрался (пакеты принимаются без сбоев), теперь отлаживаю передачу. Проходит без сбоев порядка 20% ... 30% информации. По аналогии с приемом сделал констрейны на передающие пины.

Регистры поместил в IOB'ы:
INST "U9/GM_TxD*" IOB = true ;
INST "U9/GM_TxEn" IOB = true ;

и задал фронты на выходных пинах:
Net "Phy_TxD<?>" SLEW = FAST;
Net "Phy_TxEn" SLEW = FAST;

Ошибка заключается в "выпадении" некоторых битах, хотя на приемопередатчик байты данных и CRC идут правильно (ставил ФИФО - ловушку непосредственно на передаваемый пакет данных уже у самих выходных регистрах; обратным чтением прочитал - все отлично). Но на персоналку приходят пакеты с ошибками.

Тактирую передающую часть частотой, той же самой, которая через буфер ODDR2 подается на Marvell 88E1111. Может ее надо пропустить через DCM с определенным сдвигом (больно Marvell капризен по времени установки)?
Boris_TS
По какому фронту TX_CLK, изменяются TX_EN и TX_D<*> ?
Через какие триггера выдаются TX_CLK, TX_EN, TX_D<*> ? (можно кусок кода привести – глядишь еще чего заметим)
И что-то я запамятовал: Какую ПЛИС используете
ovs_pavel
Цитата(Boris_TS @ Oct 5 2012, 08:10) *
По какому фронту TX_CLK, изменяются TX_EN и TX_D<*> ?
Через какие триггера выдаются TX_CLK, TX_EN, TX_D<*> ? (можно кусок кода привести – глядишь еще чего заметим)
И что-то я запамятовал: Какую ПЛИС используете


ПЛИС применяется Spartan6 - XC6SLX45.

Схема формирования частот - следующая:
1. На ПЛИС приходит частота от внешнего генератора - 125МГц.
2. Эта частота подается на DCM, с помощью которого формируется две частоты - 125 МГц (проходит через CLK0) и 25 МГц (проходит через CLKFX) и далее эти эти частоты через BUFG и ODDR2 подаются на Marvell. Передающая часть также синхронизируется от частоты 125МГц полученной с модуля DCM и пропущенной через буфер BUFG.

Ниже приводиться передающая часть. Данные в ФИФО набиваются от внешнего МП (стек TCP обрабатывается внешним контроллером; стек UDP обрабатывается внутри ПЛИС - видеопоток). Могу если интересно привести код CRC.
CODE

module Frame_Prd (
//------------------------- Сигналы синхронизации. -------------------------//
input Clk_125_MHz, // Тактовая частота 125 МГц.

//--------------- Сигналы модуля управления интерфейсом AVR. ---------------//
input Eth_ON, // Сигнал разрешения работы модуля (устанавливается AVR; активный уровень "1").

input [10:0] Len_Frm_Prd, // Длина передаваемого кадра (в байтах).

input [31:0] FIFO_Prd_AVR, // Данные, предназначенные для передачи по интерфейсу Ethernet (предварительно записываются в ФИФО).
input Wr_FIFO_Prd, // Сигнал разрешения записи в ФИФО передачи пакета.

input Prd_PKG_Rdy, // Сигнал начала выдачи кадра.
output reg Prd_PKG_Busy, // Сигнал активности операции передачи кадра (активный уровень "1"; выдается в регистр состояния AVR).

//----------------------- Интерфейс Ethernet 1Gb/s. ------------------------//
output [7:0] Phy_TxD, //
output Phy_TxEn, //
output Phy_TxEr, //

//---------------------------- Тестовые сигналы. ---------------------------//
output [7:0] test_Dout_FIFO, // Данные тестового ФИФО.
input test_Clr_FIFO, // Сигнал сброса тестового ФИФО (запись в 62-ой регистр).
input test_Rd_FIFO // Сигнал разрешения чтения тестового ФИФО (чтение 62-го регистра).

);


//--------------------------------------------------------------------------//
//--------------- Сигнал активности операции передачи кадра. ---------------//
//--------------------------------------------------------------------------//
reg Clr_PKG_Busy; // Сброс сигнала активности операции передачи кадра (также обнуляет ФИФО передачи кадра; на всякий случай).
always @ (posedge Clk_125_MHz or posedge Clr_PKG_Busy)
begin
if (Clr_PKG_Busy)
Prd_PKG_Busy <= 1'b0;
else if (Prd_PKG_Rdy)
Prd_PKG_Busy <= 1'b1;
end


//--------------------------------------------------------------------------//
//------------------- Счетчик длины передаваемого кадра. -------------------//
//--------------------------------------------------------------------------//
reg Dec_Cnt_FRM; // Сигнал декремента счетчика длины передаваемого кадра.
reg [10:0] Cnt_FRM; // Счетчик длины переданного кадра.
always @ (posedge Clk_125_MHz or negedge Eth_ON)
begin
if (~Eth_ON)
Cnt_FRM <= 11'd0;
else if (Prd_PKG_Rdy)
Cnt_FRM <= Len_Frm_Prd;
else if (Dec_Cnt_FRM)
Cnt_FRM <= Cnt_FRM - 1'd1;
end


//--------------------------------------------------------------------------//
//-------------------------- ФИФО передачи кадра. --------------------------//
//--------------------------------------------------------------------------//
reg Rd_FIFO_Prd; // Сигнал чтения ФИФО передачи кадра.
wire [31:0] w_FIFO_Prd;

FIFO_Prd U1 (
.clk (Clk_125_MHz),
.rst (Clr_PKG_Busy),
.din (FIFO_Prd_AVR),
.wr_en (Wr_FIFO_Prd),
.rd_en (Rd_FIFO_Prd),
.dout (w_FIFO_Prd),
.full (),
.empty ()
);


//--------------------------------------------------------------------------//
//--------------- Счетчик числа переданных ниблов преамбулы. ---------------//
//--------------------------------------------------------------------------//
reg [2:0] Cnt_Pream; // Счетчик числа переданных ниблов преамбулы.
reg Clr_Cnt_Pream; // Сброса счетчика числа переданных ниблов преамбулы.
always @(posedge Clk_125_MHz or negedge Clr_Cnt_Pream)
begin
if (~Clr_Cnt_Pream)
Cnt_Pream <= 3'd0;
else
Cnt_Pream <= Cnt_Pream + 1'b1;
end


//--------------------------------------------------------------------------//
//------------ Управление мультиплексором ФИФО передачи данных. ------------//
//--------------------------------------------------------------------------//
// ФИФО 4-х байтное, а интерфейс Ethernet - байтовый. Поэтому необходимо
// считывать слово данных один раз за 4 такта.
reg [1:0] Cnt_MUX; // Счетчик управления мультиплексором ФИФО передачи данных.
always @(posedge Clk_125_MHz or negedge Dec_Cnt_FRM)
begin
if (~Dec_Cnt_FRM)
Cnt_MUX <= 2'd0;
else
Cnt_MUX <= Cnt_MUX + 1'b1;
end


//--------------------------------------------------------------------------//
//------------------- Сигнал чтения ФИФО передачи кадра. -------------------//
//--------------------------------------------------------------------------//
always @ (posedge Clk_125_MHz or negedge Eth_ON)
begin
if (~Eth_ON)
Rd_FIFO_Prd <= 1'b0;
else
Rd_FIFO_Prd <= (Cnt_MUX == 2'd2);
end


//--------------------------------------------------------------------------//
//------------ Мультиплексор выбора данных ФИФО передачи кадра. ------------//
//--------------------------------------------------------------------------//
reg [7:0] Mux_FIFO_Prd; // Байт данных ФИФО передачи кадра.
always @(Cnt_MUX or w_FIFO_Prd)
begin
case (Cnt_MUX)
2'd0: Mux_FIFO_Prd <= w_FIFO_Prd[31:24];
2'd1: Mux_FIFO_Prd <= w_FIFO_Prd[23:16];
2'd2: Mux_FIFO_Prd <= w_FIFO_Prd[15:8];
2'd3: Mux_FIFO_Prd <= w_FIFO_Prd[7:0];
endcase
end


//--------------------------------------------------------------------------//
//--------- Управление мультиплексором регистра контрольной суммы. ---------//
//--------------------------------------------------------------------------//
reg [1:0] Cnt_CRC; // Счетчик управления мультиплексором регистра контрольной суммы.
always @(posedge Clk_125_MHz or posedge Dec_Cnt_FRM)
begin
if (Dec_Cnt_FRM)
Cnt_CRC <= 2'd0;
else
Cnt_CRC <= Cnt_CRC + 1'b1;
end


//--------------------------------------------------------------------------//
//-------- Мультиплексор выбора данных регистра контрольной суммы. ---------//
//--------------------------------------------------------------------------//
reg [7:0] Mux_KS; // Байт данных регистра контрольной суммы.
wire [31:0] Rg_CRC; // Регистр контрольной суммы.
always @(Cnt_CRC or Rg_CRC)
begin
case (Cnt_CRC)
3'd0: Mux_KS <= ~Rg_CRC[7:0];
3'd1: Mux_KS <= ~Rg_CRC[15:8];
3'd2: Mux_KS <= ~Rg_CRC[23:16];
3'd3: Mux_KS <= ~Rg_CRC[31:24];
endcase
end


//--------------------------------------------------------------------------//
//------------------ Выходной мультиплексор выбора данных. -----------------//
//--------------------------------------------------------------------------//
// Мультиплексирует данные преамбулы, начала кадра, ФИФО передачи и регистра
// контрольной суммы.
reg [1:0] Upr_D; // Регистр управления выходным мультиплексором выбора данных.
reg [7:0] Mux_D;
always @(Upr_D or Mux_FIFO_Prd or Mux_KS)
begin
case (Upr_D)
2'd0: Mux_D <= 8'b01010101;
2'd1: Mux_D <= 8'b11010101;
2'd2: Mux_D <= Mux_FIFO_Prd;
2'd3: Mux_D <= Mux_KS;
endcase
end


//--------------------------------------------------------------------------//
//---------------- Объявление регистров автомата состояний. ----------------//
//--------------------------------------------------------------------------//
reg Rg_TxEn; // Сигнал передачи действительных данных.


//--------------------------------------------------------------------------//
//--------------------- Объявление автомата состояний. ---------------------//
//--------------------------------------------------------------------------//
reg [2:0] CState;
parameter [2:0]
CS_Idle = 3'd0,
CS_Pream = 3'd1,
CS_SOF = 3'd2,
CS_Data = 3'd3,
CS_CRC = 3'd4,
CS_End = 3'd5;


//--------------------------------------------------------------------------//
//--------------------------- Автомат состояний. ---------------------------//
//--------------------------------------------------------------------------//
always @ (posedge Clk_125_MHz or negedge Eth_ON)
begin
if (~Eth_ON)
begin
CState <= CS_Idle;
Rg_TxEn <= 1'b0; // Сигнал передачи действительных данных.
Clr_Cnt_Pream <= 1'b0; // Сброса счетчика числа переданных ниблов преамбулы.
Dec_Cnt_FRM <= 1'b0; // Сигнал декремента счетчика длины передаваемого кадра.
Clr_PKG_Busy <= 1'b0; // Сброс сигнала активности операции передачи кадра (также обнуляет ФИФО передачи кадра; на всякий случай).
Upr_D <= 2'd0; // Регистр управления выходным мультиплексором выбора данных.
end
else
begin
case (CState)
CS_Idle: // ОЖИДАНИЕ СИГНАЛА НАЧАЛА ВЫДАЧИ КАДРА.
begin
if (Prd_PKG_Rdy)
begin
CState <= CS_Pream;
Rg_TxEn <= 1'b1;
Clr_Cnt_Pream <= 1'b1;
end
else
CState <= CS_Idle;
end

CS_Pream: // ФОРМИРОВАНИЕ ПРЕАМБУЛЫ.
begin
if (Cnt_Pream == 3'd6)
begin
CState <= CS_SOF;
Clr_Cnt_Pream <= 1'b0;
Upr_D <= 2'd1;
end
else
CState <= CS_Pream;
end

CS_SOF: // ФОРМИРОВАНИЕ СОСТОЯНИЯ "SOF".
begin
CState <= CS_Data;
Upr_D <= 2'd2;
Dec_Cnt_FRM <= 1'b1;
end

CS_Data: // ВЫДАЧА ДАННЫХ.
begin
if (Cnt_FRM == 11'd1)
begin
CState <= CS_CRC;
Upr_D <= 2'd3;
Dec_Cnt_FRM <= 1'b0;
end
else
CState <= CS_Data;
end

CS_CRC:
begin
if (Cnt_CRC == 2'd3)
begin
CState <= CS_End;
Rg_TxEn <= 1'b0;
Upr_D <= 2'd0;
Clr_PKG_Busy <= 1'b1;
end
else
CState <= CS_CRC;
end

CS_End:
begin
CState <= CS_Idle;
Clr_PKG_Busy <= 1'b0;
end

default:
begin
CState <= CS_Idle;
Rg_TxEn <= 1'b0;
Clr_Cnt_Pream <= 1'b0;
Dec_Cnt_FRM <= 1'b0;
Clr_PKG_Busy <= 1'b0;
Upr_D <= 2'd0;
end
endcase
end
end


//--------------------------------------------------------------------------//
//-------------- Привязка выходных данных к тактовой частоте. --------------//
//--------------------------------------------------------------------------//
reg GM_TxEn;
reg [7:0] GM_TxD;
always @ (posedge Clk_125_MHz or negedge Eth_ON)
begin
if (~Eth_ON)
begin
GM_TxEn <= 1'b0;
GM_TxD <= 8'd0;
end
else
begin
GM_TxEn <= Rg_TxEn;
GM_TxD <= Mux_D;
end
end

assign Phy_TxD = GM_TxD;
assign Phy_TxEn = GM_TxEn;


//--------------------------------------------------------------------------//
//------ Модуль вычисления CRC пакета передаваемого по сети Ethernet. -------//
//--------------------------------------------------------------------------//
wire [31:0] w_Rg_CRC;

my_crc_prd U2 (
.Clk_125_MHz (Clk_125_MHz),
.Eth_ON (Eth_ON),
.Clr_CRC (Clr_PKG_Busy),
.D_In (Mux_FIFO_Prd),
.En_CRC (Dec_Cnt_FRM),
.Rg_CRC (w_Rg_CRC)
);

assign Rg_CRC = w_Rg_CRC;


//--------------------------------------------------------------------------//
//--------------------- Назначение выходных сигналов. ----------------------//
//--------------------------------------------------------------------------//
assign Phy_TxEr = 1'b0;


//--------------------------------------------------------------------------//
//-------------------------- ФИФО передачи кадра. --------------------------//
//--------------------------------------------------------------------------//
wire [7:0] w_test_fifo;

test_fifo U_test (
.clk (Clk_125_MHz),
.rst (test_Clr_FIFO),
.din (Mux_D),
.wr_en (Rg_TxEn),
.rd_en (test_Rd_FIFO),
.dout (w_test_fifo),
.full (),
.empty ()
);

assign test_Dout_FIFO = w_test_fifo;

endmodule



Да, забыл, все тактируется положительным фронтом сигнала 125МГц.
Boris_TS
Цитата(ovs_pavel @ Oct 5 2012, 09:57) *
ПЛИС применяется Spartan6 - XC6SLX45.

Схема формирования частот - следующая:
1. На ПЛИС приходит частота от внешнего генератора - 125МГц.
2. Эта частота подается на DCM, с помощью которого формируется две частоты - 125 МГц (проходит через CLK0) и 25 МГц (проходит через CLKFX) и далее эти эти частоты через BUFG и ODDR2 подаются на Marvell. Передающая часть также синхронизируется от частоты 125МГц полученной с модуля DCM и пропущенной через буфер BUFG.

1. Попробуйте сделать вот такие времянки для TX GMII интерфейса:
Нажмите для просмотра прикрепленного файла
Этот вариант должен помочь со стабильность передачи данных в Eth Phy.
В Вашем исходнике я не заметил constaint'ов IOB для GM_TxD, GM_TxEn, если этих constaint'ов нет где-то в другом месте, то их необходимо добавить.

2. 88E1111 имеет очень жесткие требования к XTAL1, и меня берут жестокие сомнения, что после пропускания CLK через DCM получится что-то подходящее. Поэтому предлагаю 2 выхода:
1) завести на XTAL1 первородный входной Clock, который вы сейчас подаёте на DCM - в этом случае 88E1111 получит наиболее чистый clock. Правда для этого прийдётся ногу SEL_FREQ посадить на землю.
2) поделить входной Clock (не прошедший DCM) на триггерах и через ODDR (тактируемую первородным входным Clock'ом) выдать наружу.
На всякий случай посоветую еще раз внимательно просмотреть раздел XTAL1 Input Clock Timing 88E1111 Datasheet - особенно с три сноски внизу.

3. Для работы с 88E1111 GMII/RGMII я использовал Spartan-3A/Virtex-5/Virtex-6, и во всех случаях для всех сигналов использовал LVCMOS25, Drive=8,12, Slew=slow - так меньше звона стоит в линиях.
ovs_pavel
Цитата(Boris_TS @ Oct 5 2012, 10:02) *
1. Попробуйте сделать вот такие времянки для TX GMII интерфейса:
Нажмите для просмотра прикрепленного файла
Этот вариант должен помочь со стабильность передачи данных в Eth Phy.
В Вашем исходнике я не заметил constaint'ов IOB для GM_TxD, GM_TxEn, если этих constaint'ов нет где-то в другом месте, то их необходимо добавить.

2. 88E1111 имеет очень жесткие требования к XTAL1, и меня берут жестокие сомнения, что после пропускания CLK через DCM получится что-то подходящее. Поэтому предлагаю 2 выхода:
1) завести на XTAL1 первородный входной Clock, который вы сейчас подаёте на DCM - в этом случае 88E1111 получит наиболее чистый clock. Правда для этого прийдётся ногу SEL_FREQ посадить на землю.
2) поделить входной Clock (не прошедший DCM) на триггерах и через ODDR (тактируемую первородным входным Clock'ом) выдать наружу.
На всякий случай посоветую еще раз внимательно просмотреть раздел XTAL1 Input Clock Timing 88E1111 Datasheet - особенно с три сноски внизу.

3. Для работы с 88E1111 GMII/RGMII я использовал Spartan-3A/Virtex-5/Virtex-6, и во всех случаях для всех сигналов использовал LVCMOS25, Drive=8,12, Slew=slow - так меньше звона стоит в линиях.


Да, к сожалению ногу SEL_FREQ на землю посадить не удаться, т.к. корпус BGA (с многослойкой это проблемы). Вот не думал, что DCM так может сорить?

Судя по вашим времянкам, вы работаете от отрицательного фронта (либо подгоняете фронт под данные, т.к. после клока - падающего фронта, время установи данных равно практически 0). А в чем симулите - моделсим?
Просто я с 12-ой версии айса симулю его встроенным, вроде как от моделсима отошел.
Спасибо за советы, буду пробовать. Отпишусь что получилось.



Насчет констрейнов - я их добавил в файл .usf, т.е. с констрейнами все нормально.
Boris_TS
Цитата(ovs_pavel @ Oct 5 2012, 11:30) *
Да, к сожалению ногу SEL_FREQ на землю посадить не удаться, т.к. корпус BGA (с многослойкой это проблемы). Вот не думал, что DCM так может сорить?
Я скажу по другому - он не может выдавать чистый сигнал. Если входной сигнал совсем поганый - то DCM его хорошенько почистит,.. а если входной сигнал чистый, то, соответственно, несколько испоганит.
Но тут вопрос не столько в DCM, сколько в жёстких требованиях 88E1111 - у них, похоже, система чувствительна в jitter'у определённой частоты, т.е. во времена разработки 88E1111 явно предполагалось, что к ней будет подвешен кварц, а частоту будут брать уже с 88E1111 для своих целей - и нога для этого есть специальная. И я её даже пользовал в проекте со Spartan-3A: 88E1111 из 25МГц делал весьма чистенькие 125МГц.

Цитата(ovs_pavel @ Oct 5 2012, 11:30) *
Судя по вашим времянкам, вы работаете от отрицательного фронта (либо подгоняете фронт под данные, т.к. после клока - падающего фронта, время установи данных равно практически 0). А в чем симулите - моделсим?
Да, ModelSim.
На самом деле всё у меня работает тоже по положительному фронту... просто GTX_CLK выдаётся инверсным (на ODDR 1 и 0 на D местами поменяны).

Цитата(ovs_pavel @ Oct 5 2012, 11:30) *
Насчет констрейнов - я их добавил в файл .usf, т.е. с констрейнами все нормально.
Это хорошо. Но на будущее, моя практика показала, что лучше такие constaint'ы добавлять прямо в код - тогда код лучше (грамотнее) XST синтезируется.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.