Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Приемо-передатчик на плате Cyclone 4
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
Black_russian
Всем доброго времени суток. Хочу обратиться к Вам за помощью, так как сам в данной теме не разбираюсь, а дело сделать нужно.
Суть проблемы: некорректная работа системы, а именно примерно в каждом третьем случае приемник неверно ловит слово синхронизации, и само собой на выходе имеем совсем не то, что должно быть.
Плата EP4CGX30BF14C8, Functional mode - Basic.
Подскажите пожалуйста, какие моменты нужно проверить в первую очередь. Если нужна еще информация для ответа на мой вопрос - скажите пожалуйста какая именно, постараюсь все предоставить
likeasm
На каком языке пишите? Код описания схемы? Временные диаграммы можно выложить ? Как устроена "словесная" синхронизация ? Как устроена битовая синхронизация? На каких частотах работаете? Какой канал связи? Какой тип кодирования сигнала?
Black_russian
Язык verilog, входная тактовая частота 120MHz, передача данных в канале - 2Ггц , канал связи оптоволоконный, кодирование по собственному протоколу, с использованием базового режима. Код описания приемника:


CODE
// менеджер управления обменом информацией между узлами
module ExchangeManager (
output reg [15:0] out_tx_data, // данные для отправки через передатчик
output reg [1:0] out_tx_ctrlEnable, // выход типа отправляемых данных, 0 - данные, 1 - управление (2 байта)

output reg [15:0] out_data_i, // данные, полученные от ацп, выводимые на параллельный интерфейс (Синфазная часть сигнала)
output reg [15:0] out_data_q, // данные, полученные от ацп, выводимые на параллельный интерфейс (Квадратуная часть сигнала)
output reg out_data_ready, // данные на выходе готовы

output [15:0] out_temperature, // состояние ацп
output [15:0] out_voltage, // состояние ацп
output [15:0] out_current, // состояние ацп

input in_areset_n, // вход асинхронного сброса
input in_core_clk, // вход тактовой частоты ядра - 120 мгц
input in_data_clk, // вход частоты сопровождения данных - 40 мгц
input in_tx_clk, // вход тактовой частоты передатчика - 100 мгц
input in_rx_clk, // вход тактовой частоты приемника - 100 мгц

input [15:0] in_rx_data, // вход данных, полученных через приемник
input [1:0] in_rx_sync, // вход флагов битовой синхронизации (2 байта в слове)
input in_rx_byteOrderAlignStatus, // вход байтовой синхронизации слова
input [1:0] in_rx_ctrlDetect, // вход определения типа полученных данных (0 - данные, 1 - управление. 2 байта в слове)
input [1:0] in_rx_errDetect, // вход определения ошибки данных (2 байта в слове)
input [1:0] in_rx_dispErr // вход определения ошибки четности (2 байта в слове)
);
/* -------------------------------------------------------------------------------
логика работы модуля.
данные поступают на частоте 100 мгц, ядро работает на частоте 120 мгц, выдавать данные надо на частоте 40 МГц.
размер кадра - 50 слов. первое слово - синхронизации. дальше 9 слов служебки. дальше 40 слов данных (по очерди - слово синфазное - слово квадратурное)
для обеспечения постоянной частоты выдачи данных используется 2 циклических буфера по 20 слов.
запись в буферы идет на частоте 100 МГц, по очереди то в первый, то во второй буфер пишется по одному слову 20 слов (всего 40), затем 10 тактов перерыв.
чтобы не было коллизий при попытке чтения и записи в одну ячейку, между адресами чтения и записи поддерживается интервал равный 10.
после синхронизации начинается получение валидных данных.
9 слов служебки получили. начинаем заполнять буфер данных. записали 20 слов (по 10 в каждый буфер) - выставляем флаг готовности данных. начинается чтение.
читаем на частоте 40 МГц. запись идет быстрее чтения. после завершения записи буфера идет чтение из середины. ждем 10 тактов, чтобы чтение догнало запись.
затем начинаем писать с начала, когда запись будет в середине - чтение перейдет с конца буфера на начало.
---------------------------------------------------------------------------------- */

wire data_err = |in_rx_errDetect || |in_rx_dispErr; // флаг ошибки. нет ошибки - должны быть нули
wire sync_word = |in_rx_ctrlDetect; // флаг слова синхронизации
wire sync_ok = &in_rx_sync; // && in_rx_byteOrderAlignStatus // флаг синхронизации канала (флаг байтовой не выставляется почему-то)

localparam FRAME_SIZE = 50; // размер кадра в словах
localparam DATA_WORDS_COUNT = 40; // количество слов данных в кадре
localparam SYSINFO_WORDS_COUNT = FRAME_SIZE - DATA_WORDS_COUNT - 1; // количество слов служебной информации в кадре
localparam DATA_BUF_SIZE = 20; // размер буфера данных

localparam ST_SYNC = 0; // стадия синхронизации
localparam ST_SYSINFO = 1; // стадия отправки служебной информации
localparam ST_DATA = 2; // стадия отправки данных

// константы
parameter [15:0] SYNC_DATA_PATTERN = 16'b10111100_11001001; // синхронизирующее слово (старший байт - битовая синхронизация (k28.5- = 188), младший - байтовая.)
parameter [1:0] SYNC_DATA_CONTROL = 2'b10; // байт битовой синхронизации - управляющий (k28.5-), байт байтовой синхронизации - данные. (8b/10b)

// системная информация
reg [15:0] sysinfo_temperature; // температура модуля ацп
reg [15:0] sysinfo_current; // потребляемый модулем ацп ток
reg [15:0] sysinfo_voltage; // напряжение на модуле ацп
reg [47:0] sysinfo_frame_counter; // счетчик кадров, отправленных с модуля ацп

assign out_temperature = sysinfo_temperature;
assign out_current = sysinfo_current;
assign out_voltage = sysinfo_voltage;

reg [1:0] state; // состояние принимающей стороны
reg [4:0] counter_sysinfo; // счетчик слов служебной информации
reg [5:0] counter_data;
reg [15:0] in_rx_dataz;
reg state_data_i; // при получении данных - синфазное или квадратурное слово на входе.
reg wr_req;
reg rd_req;

// буфер синфазной части данных
wire wr_i_req = state_data_i & wr_req;
wire wr_i_full;
wire rd_i_empty;
wire [15:0] data_i;
fifo TheIFifo (
.wrclk (in_rx_clk),
.rdclk (in_data_clk),
.aclr (!in_areset_n),

.data (in_rx_dataz),
.q (data_i),

.wrreq (wr_q_req),
.rdreq (rd_req),

.wrfull (wr_i_full),
.rdempty (rd_i_empty)
);

// буфер квадратурной части данных
wire wr_q_req = !state_data_i & wr_req;
wire wr_q_full;
wire rd_q_empty;
wire [15:0] data_q;
fifo TheQFifo (
.wrclk (in_rx_clk),
.rdclk (in_data_clk),
.aclr (!in_areset_n),

.data (in_rx_data),
.q (data_q),

.wrreq (wr_q_req),
.rdreq (rd_req),

.wrfull (wr_q_full),
.rdempty (rd_q_empty)
);

// реализация сохранения входящих данных в циклический буфер
always @ (posedge in_rx_clk or negedge in_areset_n)
if (!in_areset_n)
begin
counter_sysinfo <= #1 0; // сброс счетчика слов системной информации
counter_data <= #1 0;
state <= #1 ST_SYNC; // состояние синхронизации
state_data_i <= #1 0; // сначала синфазное слово

out_data_ready <= #1 0; // данные не готовы
rd_req <= #1 0;
wr_req <= #1 0;
end
else if (sync_ok) // синхронизация выполнена
begin
if (sync_word) // пришло слово синхронизации
begin
state <= #1 ST_SYSINFO; // переключиться в стадию системной информации
counter_sysinfo <= #1 0; // сброс счетчика слов системной информации
counter_data <= #1 0;
end
else // идут данные
begin
case (state) // synopsys parallel_case full_case

ST_SYSINFO: // идет получение системной информации
begin
counter_sysinfo <= #1 counter_sysinfo + 1'b1;

case (counter_sysinfo) // synopsys parallel_case
0: sysinfo_temperature <= #1 in_rx_data; // первое слово
1: sysinfo_voltage <= #1 in_rx_data; // второе
2: sysinfo_current <= #1 in_rx_data; // третье
3: sysinfo_frame_counter[15:0] <= #1 in_rx_data; // первые 2 байта счетчика кадров
4: sysinfo_frame_counter[31:16] <= #1 in_rx_data; // вторые 2 байта счетчика кадров
5: sysinfo_frame_counter[47:32] <= #1 in_rx_data; // третьи 2 байта счетчика кадров
// остальные - резерв. ничего не делать, пропустить.
endcase

if (counter_sysinfo == SYSINFO_WORDS_COUNT - 1) // последнее слово системной информации - дальше данные.
begin
state <= #1 ST_DATA; // переключиться в состояние получения данных
wr_req <= #1 1'b1; // включаем запись в буферы
state_data_i <= #1 1; // сначала синфазное слово
//wr_i_req <= #1 !state_data_i; // если сейчас синфазное слово - дальше квадратурное. снять запрос
//wr_q_req <= #1 state_data_i; // если сейчас синфазное слово - поставить запрос
//wr_i_req <= #1 1'b1; // ставим запрос записи
//wr_q_req <= #1 0;
end
end

ST_DATA:
begin
state_data_i <= #1 ~state_data_i; // переключить стадию данных
in_rx_dataz <= in_rx_data;
if (counter_data == DATA_WORDS_COUNT - 1'b1)
begin
wr_req <= #1 0;
counter_data <= #1 0;
state <= #1 ST_SYNC;
end
else
begin
counter_data <= #1 counter_data + 1'b1;
wr_req <= #1 1;
end

if (!out_data_ready && counter_data == 6'd20) // данные готовы после записи нескольких слов (запись быстрее чтения)
begin
out_data_ready <= #1 1'b1;
rd_req <= #1 1'b1;
end
end
endcase
end
end

// реализация вывода данных
reg [15:0] ddz,err;
always @ (negedge in_data_clk or negedge in_areset_n)
if (!in_areset_n)
begin
out_data_i <= #1 0; // очистка выходных данных
out_data_q <= #1 0;
end
else if (out_data_ready) // данные готовы
begin
out_data_i <= #1 data_i; // выставляем данные из буфера на выход
out_data_q <= #1 data_q;
// ddz <= out_data_i; if(data_i+1 != data_q) err <= err+1; // для контроля надежности
end
else // данные не готовы
begin
out_data_i <= #1 0;
out_data_q <= #1 0;
end

// реализация отправки данных на модуль ацп
always @ (posedge in_tx_clk or negedge in_areset_n)
if (!in_areset_n)
begin
out_tx_data <= #1 0;
out_tx_ctrlEnable <= #1 0;
end
else // все время шлем синхрокадры
begin
out_tx_data <= #1 SYNC_DATA_PATTERN;
out_tx_ctrlEnable <= #1 SYNC_DATA_CONTROL;
end

endmodule

Код передатчика:

`timescale 1 ps / 1 ps

// логическое ядро модуля
module logicCore (
output reg [15:0] out_tx_data, // данные для отправки на модуль
output reg [1:0] out_tx_ctrl, // тип отправляемых данных (8b/10b, 0 - данные, 1 - управление. 2 байта в слове)
output out_gxb_pwr, // выход включения/выключения приемопередатчика 0 - включить, 1 - выключить

input in_areset_n, // асинхронный сброс
input in_clk_core, // входной синхросигнал - 120 мгц
input in_clk_data, // частота сопровождения данных - 40 МГц
input in_clk_tx, // синхросигнал от передатчика - 100 мгц. (по нему надо отправлять данные на передатчик)
input in_clk_rx, // синхросигнал от приемника - 100 мгц. (по нему надо получать данные из буфера приемника)

// входы системной информации
input [15:0] in_temperature, // вход значения температуры с датчика
input [15:0] in_current, // вход значения тока с датчика
input [15:0] in_voltage, // вход значения напряжения с датчика
input [15:0] in_data_i, // данные синфазная часть
input [15:0] in_data_q, // данные квадратурная часть

input [15:0] in_rxData, // данные, поступающие по оптоволокну от модуля , управляющие команды
input [1:0] in_rx_syncStatus, // флаги битовой снхронизации (2 байта в слове)
input in_rx_byteOrderAlignStatus, // флаг байтовой синхронизации
input [1:0] in_rx_ctrlDetect, // вход определения типа входящих данных (8b/10b, 0 - данные, 1 - управление. 2 байта в слове)
input [1:0] in_rx_errDetect, // вход определения ошибок данных (2 байта в слове)
input [1:0] in_rx_dispErr, // вход определения ошибок четности (2 байта в слове)

input in_sens_data_ready, // данные датчиков готовы
input in_quad_data_ready, // флаг готовности данных ацп
input in_sfp_detect_n, // вход обнаружения подключения приемопередатчика
input in_pwr_alert // вход оповещения о перегрузке по току
);
/* -------------------------------------------------------------
логика работы подсистемы передачи данных:
1)
передается 1 слово синхронизации, потом служебка, потом данные (по очереди - слово синфазное, слово квадратурное)
отправляется на 100 МГц.

2)
таким образом, инициализация идет следующим образом:
сначала идет ожидание готовности передатчика к отправке данных.
как только он инициализировался - начинается заполнение буфера данными, пока не будет достигнуто смещение между адресами записи и чтения, равное 4.
в это время автомат отправки находится в состоянии синхронизации.
как только половина буфера данных будет заполнена (спустя n 100мгц тактов), начинается передача по схеме, описанной далее.

3)
отправка данных идет по следующей схеме:
отправляется 1 слово синхронизации, затем m слов служебной информации, затем n слов данных.
пока данные не доступны - отправляются только кадры синхронизации.

4)
структура служебной информации:
1 слово:
2 слово -
3 слово -
4 - 6 слова: счетчик кадров.

5)
прием данных идет непрерывно. - пока ничего нет.
подразумевается прием и распозование различных управляющих команд.
*/// -----------------------------------------------------------

assign out_gxb_pwr = in_sfp_detect_n; // включить модуль приемопередатчика только когда подключен оптический трансивер

localparam FRAME_SIZE = 50; // размер кадра в словах, рабочий вариант - 50
localparam DATA_WORDS_COUNT = 40; // количество слов данных в кадре, рабочий вариант - 40
localparam SYSINFO_WORDS_COUNT = FRAME_SIZE - DATA_WORDS_COUNT - 1; // количество слов служебной информации в кадре (всего - данные - синхрокадр)

// константы
localparam [15:0] SYNC_DATA_PATTERN = 16'b10111100_11001001; // синхронизирующее слово (старший байт - битовая синхронизация (k28.5- = 188), младший - байтовая.)
localparam [1:0] SYNC_DATA_CONTROL = 2; // оба байта слова синхронизации являются управляющими (8b/10b)

wire rx_data_error = |in_rx_errDetect || |in_rx_dispErr; // флаг ошибки во входящих данных
reg [15:0] fifo_out_qz, fifo_out_qz2;

reg wr_req;
reg rd_req_i;
reg rd_req_q;
wire rd_empty_i;
wire rd_empty_q;
wire wr_full_i;
wire wr_full_q;
wire [15:0] fifo_out_i;
wire [15:0] fifo_out_q;
afifo TheIFifo (
.wrclk (in_clk_data),
.rdclk (in_clk_tx),
.aclr (!in_areset_n),

.data (in_data_i),
.q (fifo_out_i),

.rdreq (rd_req_i), // ранее было .rdreq (rd_req_i),
.wrreq (wr_req),

.rdempty (rd_empty_i),
.wrfull (wr_full_i)
);

afifo TheQFifo (
.wrclk (in_clk_data),
.rdclk (in_clk_tx),
.aclr (!in_areset_n),

.data (in_data_i), // ======================== .data (in_data_q),
.q (fifo_out_q),

.rdreq (rd_req_i), // ранее было .rdreq (rd_req_q),
.wrreq (wr_req),

.rdempty (rd_empty_q),
.wrfull (wr_full_q)
);

// служебная информация
reg [47:0] frame_count; // значение счетчика кадров
reg [15:0] sens_temp=1; // значение
reg [15:0] sens_cur=4'h0002; // значение
reg [15:0] sens_volt = 4'h0003; // значение

// автомат состояний
localparam ST_SYNC = 0; // стадия синхронизации
localparam ST_SYSINFO = 1; // стадия отправки служебной информации
localparam ST_DATA = 2; // стадия отправки данных
reg [1:0] state; // текущее состояние автомата
reg [7:0] counter_data; // счетчик отправленных слов данных
reg [7:0] fifo_written; // счетчик записанных в буфер слов
reg [4:0] counter_sysinfo; // счетчик отправленных слов служебной информации
reg state_data; // переключатель синфазных/квадратурных данных
reg transmitter_ready; // передатчик готов к отправке. (определяется наличием синхросигнала)
reg data_ready, data_readyz, data_ready2z; // данные готовы к отправке.

// реализация буферов данных
always @ (posedge in_clk_data or negedge in_areset_n)
if (!in_areset_n)
begin
data_ready <= #1 0; // сброс флага готовности данных
wr_req <= #1 0; // выключаем запись в фифо
fifo_written <= #1 0; // сброс количества записанных слов
end
else if (in_quad_data_ready) // запись в память только когда готовы данные
begin
wr_req <= #1 1'b1; // включаем запись в фифо

if (!data_ready)
begin
if (fifo_written == DATA_WORDS_COUNT/2) // записано слов данных на один кадр - чтение быстрее записи.
data_ready <= #1 1'b1; // можно отправлять данные
else
fifo_written <= #1 fifo_written + 1;
end
end

// данные датчиков
always @ (posedge in_clk_core or negedge in_areset_n)
if (!in_areset_n)
begin
sens_temp <= #1 0;
sens_cur <= #1 0;
sens_volt <= #1 0;
end
else if (in_sens_data_ready)
begin
sens_temp <= #1 in_temperature;
sens_cur <= #1 in_current;
sens_volt <= #1 in_voltage;
end

// готовность передатчика
always @ (posedge in_clk_tx or negedge in_areset_n)
if (!in_areset_n)
transmitter_ready <= #1 0;
else if (!in_sfp_detect_n)
transmitter_ready <= #1 1;

// реализация автомата состояний передатчика
always @ (posedge in_clk_tx or negedge in_areset_n)
if (!in_areset_n)
begin // начало, сброс
out_tx_data <= #1 0; // выход данных
out_tx_ctrl <= #1 0;
state <= #1 ST_SYNC; // сначала автомат в состоянии синхронизации
rd_req_i <= #1 0;
rd_req_q <= #1 0;
counter_data <= #1 0; // сброс счетчика слов данных
counter_sysinfo <= #1 0; // сброс счетчика слов системной информации
frame_count <= #1 0; // сброс счетчика кадров
state_data <= #1 0; // читаем синфазное слово
data_ready2z <= data_readyz; data_readyz <= data_ready;
end
else if (transmitter_ready)
begin //
data_ready2z <= data_readyz; data_readyz <= data_ready;
if((counter_data < FRAME_SIZE) && data_ready2z)
counter_data <= counter_data+8'h01;
else
counter_data <= 8'h01;

if(counter_data == 8'h00) // начало
begin
out_tx_ctrl <= #1 0;
out_tx_data <= #1 16'h1234; // выход данных
end
if(counter_data == 8'h01) // стадия синхронизации, counter_data=1
begin
out_tx_data <= #1 SYNC_DATA_PATTERN; // слово синхронизации
out_tx_ctrl <= #1 SYNC_DATA_CONTROL;
rd_req_i <= #1 0;
if (data_ready2z) // если данные готовы data_ready
begin
frame_count <= #1 frame_count + 1; // увеличиваем счетчик кадров
end // завершение стадии синхронизации
end
else if(counter_data < 8'h0b) // стадия отправки системной информации, counter_data=2...10
begin
// if(counter_data < 8'h0b)rd_req_i <= #1 0; // включаем чтение из того фифо, который по порядку должен быть.
// else rd_req_i <= #1 1;
// rd_req_q <= counter_data[0];
out_tx_ctrl <= #1 0; // данные 8b/10b
case (counter_data-16'h0002)
0: out_tx_data <= #1 sens_temp; //
1: out_tx_data <= #1 sens_volt; //
2: out_tx_data <= #1 sens_cur; //
3: out_tx_data <= #1 frame_count[15:0]; // первые 2 байта счетчика кадров
4: out_tx_data <= #1 frame_count[31:16]; // вторые 2 байта счетчика кадров
5: out_tx_data <= #1 frame_count[47:32]; // третьи 2 байта счетчика кадров
6: out_tx_data <= #1 16'h0777; // резерв
7: out_tx_data <= #1 16'h0888; // резерв
8: out_tx_data <= #1 16'h0999; // резерв
default: out_tx_data <= #1 16'hffff;// остальное - резерв
endcase
if(counter_data==16'h000a) rd_req_i <= 1;
else rd_req_i <= 0;
end
else // стадия отправки данных
begin
fifo_out_qz <= fifo_out_q; fifo_out_qz2 <= fifo_out_qz;
out_tx_data <= #1 (!counter_data[0]) ? fifo_out_qz : fifo_out_i; // данные из буфера // ранее было fifo_out_i : fifo_out_q;
out_tx_ctrl <= #1 0; // данные 8b/10b
if (counter_data < FRAME_SIZE - 1) rd_req_i <= !counter_data[0]; // если сейчас идет слово синфазное - то следующее слово квадратурное
// rd_req_q <= counter_data[0]; // если сейчас идет слово синфазное - то следующее слово квадратурное

if (counter_data == FRAME_SIZE - 1) // не все данные отправлены
begin
rd_req_i <= #1 0; // выключаем чтение из фифо
rd_req_q <= #1 0; // выключаем чтение из фифо
end
end
end

endmodule




Получить временные диаграммы сейчас, к сожалению, не могу. Но могу описать что видел на них: для данных с приемника четкое смещение на 1 байт. Некорректоное срабатывание по синхро-слову наблюдалось примерно 1 раз из 4 запусков, вне зависимости от изменения входного сигнала.
Maverick
Цитата(Black_russian @ Oct 8 2015, 15:46) *

пользуйтесь вставкой кода для оформления описания на хHDL
Модератор

Ваше сообщение отредактировал.
Black_russian
Добавляю временные диаграммы с примером правильного срабатывания и ошибки. Закономерность в появлении ошибки найти не удается. При перешивке одного и того же кода примерно в одном из 4-5 случаев получается ошибка, остальные срабатывания верны



Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.