#vhdl #fpga #lattice-diamond
#vhdl #fpga #решетка-ромб
Вопрос:
Я пытался реализовать UART для связи между моей платой Lattice MachXO3D и моим компьютером. На данный момент я пытаюсь реализовать передачу с FPGA.
После тестирования на оборудовании я столкнулся с очень странной проблемой. При нормальной работе он будет работать несколько секунд, а затем внезапно перестанет функционировать (CH340, подключенный к моему компьютеру, сообщит, что получает сообщения, содержащие 0x0). Однако, если я встрою логический анализатор в FPGA с помощью программного обеспечения Lattice Diamond и запущу анализатор, он будет отлично функционировать в течение длительного периода времени.
К сожалению, у меня нет логического анализатора, поэтому встроенный логический анализатор — мой единственный шанс узнать, что на самом деле передается.
Это файлы, связанные с моей реализацией:
baud_gen
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- Generates 16 ticks per bit
ENTITY baud_gen IS
GENERIC(divider: INTEGER := 13 -- 24M/115200*16
);
PORT(
clk, reset: IN STD_LOGIC;
s_tick: OUT STD_LOGIC
);
END baud_gen;
ARCHITECTURE working OF baud_gen IS
BEGIN
PROCESS(clk)
VARIABLE counter: UNSIGNED(3 DOWNTO 0) := to_unsigned(0,4);
BEGIN
IF clk'EVENT AND clk='1' THEN
IF reset='1' THEN
s_tick <= '0';
counter := to_unsigned(0,4);
ELSIF counter=to_unsigned(divider-1,4) then
s_tick <= '1';
counter:= to_unsigned(0,4);
ELSE
s_tick <= '0';
counter := counter 1;
END IF;
END IF;
END PROCESS;
END working;
rs232_tx
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY rs232_tx IS
PORT(clk: IN std_logic;
tx: OUT std_logic;
rst: IN std_logic;
fifo_empty: IN std_logic;
fifo_RdEn, fifo_RdClock: OUT std_logic;
fifo_data: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
Q: OUT STD_LOGIC_VECTOR(1 DOWNTO 0));
END rs232_tx;
ARCHITECTURE working OF rs232_tx IS
TYPE state IS (idle,start,data);
SIGNAL tx_pulse: STD_LOGIC := '1';
SIGNAL s_tick: STD_LOGIC;
SIGNAL pr_state, nx_state: state := idle;
SIGNAL data_val: std_logic_vector(7 DOWNTO 0):=(others=>'0');
SIGNAL data_count: unsigned(2 DOWNTO 0):=to_unsigned(0,3);
BEGIN
process(s_tick, rst)
VARIABLE count: unsigned(3 DOWNTO 0):= to_unsigned(0,4);
BEGIN
IF rising_edge(s_tick) THEN
count := count to_unsigned(1,4);
IF count = to_unsigned(15,4) THEN
tx_pulse <= '1';
ELSE
tx_pulse <='0';
END IF;
END IF;
END PROCESS;
process(tx_pulse,rst)
BEGIN
IF rising_edge(tx_pulse) THEN
IF rst='1' THEN
pr_state <= idle;
data_val <= (others=>'0');
data_count <= to_unsigned(0,3);
ELSE
pr_state <= nx_state;
CASE pr_state IS
WHEN idle =>
data_count <= to_unsigned(0,3);
WHEN data =>
data_count <= data_count to_unsigned(1,3);
WHEN start =>
data_val <= fifo_data;
WHEN OTHERS =>
END case;
END IF;
END IF;
END process;
process(fifo_empty,rst,data_count,pr_state,data_count)
BEGIN
case pr_state is
when idle =>
Q <= ('1','1');
fifo_RdEn <= '0';
tx <= '1';
IF fifo_empty='0' AND rst='0' THEN
nx_state <= start;
ELSE
nx_state <= idle;
END IF;
WHEN start =>
Q <= ('1','0');
fifo_RdEn <= '1';
tx <= '0';
nx_state <= data;
WHEN data =>
Q <= ('0','1');
fifo_RdEn <= '0';
tx <= data_val(to_integer(data_count));
if data_count=to_unsigned(7,3) then
nx_state <= idle;
ELSE
nx_state <= data;
end if;
end case;
END process;
fifo_RdClock <= tx_pulse;
baud_gen: ENTITY work.baud_gen
PORT MAP(clk,reset=>'0',s_tick=>s_tick);
END working;
testbench
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY rs232_tx_test IS
GENERIC(clk_period: TIME := 41666666.7 fs;
baud_period: TIME := 8680.55556 ns);
END rs232_tx_test;
ARCHITECTURE working OF rs232_tx_test IS
SIGNAL clk: STD_LOGIC := '0';
SIGNAL tx, rst, fifo_empty, fifo_RdEn, fifo_RdClock: STD_LOGIC;
SIGNAL fifo_data: STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
clk <= NOT clk AFTER clk_period/2;
rst <= '1', '0' AFTER 100 ns;
PROCESS
BEGIN
fifo_empty <= '1';
WAIT FOR baud_period;
fifo_empty <= '0';
WAIT FOR baud_period*16;
END PROCESS;
fifo_data <= ('1','1','0','0','1','0','1','1') WHEN fifo_RdEn='1' ELSE (others=>'0');
dut: ENTITY work.rs232_tx
PORT MAP(clk,tx,rst,fifo_empty,fifo_RdEn,fifo_RdClock,fifo_data);
END working;
Редактировать
Я протестировал другой дизайн UART, который я нашел в Интернете при скорости 9600 бит / с, и он выходит из строя таким же образом. Он может отправлять постоянный символ, в данном случае ‘a’, на терминал на моем компьютере, а затем внезапно перестает что-либо отправлять. Однако, если я начну прослушивать программный логический анализатор, который я создал в Lattice Diamond, он работает без проблем и не дает сбоев.
Комментарии:
1. Вы это имитировали?
2. @MatthewTaylor Конечно, при моделировании он работает отлично. На аппаратном обеспечении он выходит из строя примерно через 2 секунды. Я даже моделировал его в течение 5 секунд, что заняло довольно много времени с шагом 1fs, и даже тогда он работал хорошо. Проблема определенно возникает после синтеза, но не при моделировании
3. Извините — глупый вопрос — есть тестовый стенд. Как насчет STA и / или моделирования уровня вентиля?
4. Я отмечаю, что вы используете логически сгенерированные часы
s_tick
в качестве фактических часов. Это не рекомендуется в ПЛИС, поскольку логические тактовые сигналы могут вызывать проблемы с синхронизацией. Гораздо лучше использовать одни и те же часы для всей логики и вместо этого использовать s_tick, как включение часов.5. @BrianDrummond Да, я это понимаю. Это потому, что я хочу, чтобы счетчик оставался на 0 в течение одного тика после изменения состояния на него. Должен ли я был спроектировать его по-другому?
Ответ №1:
Это похоже на классическую проблему синхронизации.
В комментариях другие объяснили, где в коде есть недостатки, которые могут косвенно привести к этому. Я собираюсь сосредоточиться на том, что происходит.
Как вы уже заявили, при моделировании ваш код работает так, как вы ожидаете. Однако это только половина истории. Для создания битового потока FPGA инструменты сборки берут ваш код и несколько других файлов, синтезируют и проводят Place amp; Route. Ваша проблема с синхронизацией возникает во время P amp; R. Вот почему ваша симуляция не обнаруживает никаких ошибок, поскольку я предполагаю, что это симуляция RTL (pre-place amp; route).
Во время P amp; R инструменты наилучшим образом настраивают логику в соответствии с моделью синхронизации устройства, чтобы все пути соответствовали их требованиям к синхронизации. Требования к синхронизации пути получены из явных инструкций в файле временных ограничений и выведены из вашего кода (вот почему ваш стиль кодирования имеет значение, кстати).
После завершения P amp; R инструменты передадут артефакт сборки через инструмент static timing analyzer (STA) и сообщат, не соответствует ли сборка требованиям синхронизации.
Это приводит к двум вопросам:
- Сообщает ли сборка об ошибке синхронизации?
- Есть ли у вас файл с временными ограничениями — если вы не уверены, ответ отрицательный.
Способ отладки вашей проблемы — использовать отчет о времени, созданный Lattice Diamond, чтобы увидеть, где находятся сбои. Если нет сообщений о сбоях, это означает, что ваша модель синхронизации неверна из-за отсутствия соответствующих временных ограничений. Как минимум, вам нужно будет ограничить все операции ввода-вывода в проекте и описать все тактовые частоты в вашем проекте.
Вот хороший документ, который вам поможет: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/RZ/Timing_Closure_Document.ashx?document_id=45588
Причина, по которой ваш проект работает при использовании встроенного анализатора логики, заключается в том, что в проект была добавлена дополнительная логика, которая изменяет модель синхронизации. Инструменты P amp; R по-разному разрабатывают дизайн и, по счастливой случайности, разместили дизайн таким образом, чтобы он соответствовал реальным требованиям к времени.
Как я часто говорю своим коллегам-программистам, языки программирования создают набор инструкций, HDL создает набор предложений.
Комментарии:
1. Мне удалось использовать FT2232 на плате вместо CH340, и теперь он работает. Единственное, что отличается, — это используемые I контакты, а также расстояние, которое должен пройти сигнал, поэтому я считаю, что это действительно была проблема с синхронизацией. Мне нужно будет найти способ моделирования синхронизации в Linux.