[英]FPGA to HPS communication in VHDL with FIFO
我正在尝试在 Altera DE10nano 开发板上实现我的 FPGA 和 HPS 之间的通信。 要编辑 vhdl,我使用 Quartus Prime 软件。
虽然通信正常工作(因为我可以从 fpga 获取一些数据到 hps),但我有一个问题是创建一个适当的状态机,它可以使用不同的时钟向 FIFO 添加一个新值(在这个情况下 12500Hz) 比 50MHz 的基本时钟。 其他时钟(100kHz 和 12500Hz)在不同的 vhdl 模块中生成。
总体思路是在 12.5kHz 时钟的每个周期写入一个样本。 每个周期我都有一个增加的计数器以及来自上游 FFT 的一些数据。
我在 HPS 中使用一个简单的 C 代码来读取我的 fifo 并将读取的值保存到一个 .csv 文件中。
现在,问题是:当我使用我的电路板加载我的设计时,我没有得到正确的样本编号。 我在 .csv 文件中获得随机值(来自“counter_sample”),而状态机的模拟(使用 ModelSim)正在做我想要它做的事情。 此外,当我使用 100kHz 时钟触发该过程时,该设计确实工作得很好,但有人告诉我这是不好的做法,因为时钟不是由 pll 生成的。 这也让我认为使用的 C 代码不是问题。
我得到的随机值不是连续的,而是彼此分开的 200-300 个计数器值。
我不是编程 vhdl 的老手(正如你可能知道的那样),但我会在下面复制我的状态机。 我很高兴听到您的意见,并会在需要时提供更多信息。
fft_sop 和 fft_eop 信号是来自上游 fft 的 start- 和 endofpacket 信号。
谢谢!
process(Clk_50MHz, in_reset)
begin
if (in_reset = '1') then
f2h_state <= f2h_idle;
counter_sample <=0;
counter_wait <=0;
out_fifo_write <='0';
out_fifo_writedata <= (others => '0');
fft_sop_old <= '0';
fft_eop_old <= '0';
Clk_12500Hz_alt<='0';
elsif(rising_edge(Clk_50MHz)) then
fft_sop_old <= in_fft_sop;
fft_eop_old <= in_fft_eop;
Clk_12500Hz_old <= Clk_12500Hz;
case f2h_state is
when f2h_idle =>
if ((Clk_12500Hz = '1') and (Clk_12500Hz_old = '0')) then
counter_wait <= counter_wait + 1;
if counter_wait = 8190 then
f2h_state <= f2h_wait_start;
else
f2h_state <= f2h_idle;
end if;
else
f2h_state <= f2h_idle;
end if;
when f2h_wait_start =>
out_fifo_write <= '0';
if ((in_fft_sop = '1') and (fft_sop_old = '0')) then
out_fifo_write <= '1';
out_fifo_writedata(10 downto 0) <= conv_std_logic_vector(1, 11);
counter_sample <= 2;
out_fifo_writedata(22 downto 11) <= in_fft_real(11 downto 0);
out_fifo_writedata(34 downto 23) <= in_fft_imag(11 downto 0);
out_fifo_writedata(63 downto 35) <= (others => '0');
f2h_state <= f2h_writesample;
end if;
when f2h_writesample =>
if ((Clk_12500Hz = '1') and (Clk_12500Hz_old = '0')) then
out_fifo_write <= '1';
counter_sample <= counter_sample + 1;
out_fifo_writedata(10 downto 0) <= conv_std_logic_vector(counter_sample, 11);
out_fifo_writedata(22 downto 11) <= in_fft_real(11 downto 0);
out_fifo_writedata(34 downto 23) <= in_fft_imag(11 downto 0);
out_fifo_writedata(63 downto 35) <= (others => '0');
if in_fft_eop = '1' then
f2h_state <= f2h_wait_start;
end if;
f2h_state <= f2h_writesample;
else
out_fifo_write <= '0';
end if;
end case;
end if;
end process;
所有三个状态都正确同步到系统时钟clk_50MHz
,但是第一个和第三个状态F2H_IDLE
和F2H_WRITESAMPLE
正在寻找clk_12500Hz
的上升沿,而第二个 state F2H_WAIT_START
不是。 相反,它只是在寻找in_fft_sop
的上升沿。 这意味着第一个和第三个状态同步到clk_12500Hz
信号的上升沿,但是第二个state不同步到clk_12500Hz
信号(只有in_fft_sop
信号)。 这是你想要的吗? 这可以解释为什么您在counter_sample
上获得随机值。
我已经重组了逻辑,以便所有状态都与系统时钟clk_50MHz
和clk_12500Hz
信号同步,这是我从你的问题中理解的,我假设新数据只是在out_fifo_write
时输入 FIFO高的。
我还添加了三个边缘检测器以使代码更具可读性,并将第三个 state 中的电平检测器更改为上升沿检测器。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity FPGA2HPS is
port
(
clk_50MHz: in std_logic;
clk_12500Hz: in std_logic;
in_reset: in std_logic;
in_fft_sop: in std_logic;
in_fft_eop: in std_logic;
in_fft_real: in std_logic_vector(11 downto 0);
in_fft_imag: in std_logic_vector(11 downto 0);
out_fifo_write: out std_logic;
out_fifo_writedata: out std_logic_vector(63 downto 0)
);
end entity;
architecture V1 of FPGA2HPS is
type F2H_STATES is (F2H_IDLE, F2H_WAIT_START, F2H_WRITESAMPLE);
signal f2h_state: F2H_STATES;
signal rising_edge_clk_12500Hz: std_logic;
signal rising_edge_in_fft_sop: std_logic;
signal rising_edge_in_fft_eop: std_logic;
signal clk_12500Hz_old: std_logic;
signal fft_sop_old: std_logic;
signal fft_eop_old: std_logic;
signal clk_12500Hz_alt: std_logic;
signal counter_sample: integer;
signal counter_wait: integer;
begin
--
-- Rising edge detectors
--
rising_edge_clk_12500Hz <= clk_12500Hz and not clk_12500Hz_old;
rising_edge_in_fft_sop <= in_fft_sop and not fft_sop_old;
rising_edge_in_fft_eop <= in_fft_eop and not fft_eop_old;
process(clk_50MHz, in_reset)
begin
if in_reset then
f2h_state <= F2H_IDLE;
counter_sample <= 0;
counter_wait <= 0;
out_fifo_write <= '0';
out_fifo_writedata <= (others => '0');
fft_sop_old <= '0';
fft_eop_old <= '0';
clk_12500Hz_alt <= '0';
elsif rising_edge(clk_50MHz) then
-- Ensure all the state machine logic works on the rising edge of the clk_12500Hz signal while also synchronised to the clk_50MHz clock.
if rising_edge_clk_12500Hz then
fft_sop_old <= in_fft_sop;
fft_eop_old <= in_fft_eop;
clk_12500Hz_old <= clk_12500Hz;
case f2h_state is
when F2H_IDLE =>
f2h_state <= F2H_IDLE;
counter_wait <= counter_wait + 1;
if counter_wait = 8190 then
f2h_state <= F2H_WAIT_START;
end if;
when F2H_WAIT_START =>
f2h_state <= F2H_WAIT_START;
out_fifo_write <= '0';
if rising_edge_in_fft_sop then
out_fifo_write <= '1';
out_fifo_writedata(10 downto 0) <= std_logic_vector(to_unsigned(1, 11)); -- CHANGED
counter_sample <= 2;
out_fifo_writedata(22 downto 11) <= in_fft_real(11 downto 0);
out_fifo_writedata(34 downto 23) <= in_fft_imag(11 downto 0);
out_fifo_writedata(63 downto 35) <= (others => '0');
f2h_state <= F2H_WRITESAMPLE;
end if;
when F2H_WRITESAMPLE =>
f2h_state <= F2H_WRITESAMPLE;
counter_sample <= counter_sample + 1;
out_fifo_writedata(10 downto 0) <= std_logic_vector(to_unsigned(counter_sample, 11)); -- CHANGED
out_fifo_writedata(22 downto 11) <= in_fft_real(11 downto 0);
out_fifo_writedata(34 downto 23) <= in_fft_imag(11 downto 0);
out_fifo_writedata(63 downto 35) <= (others => '0');
if rising_edge_in_fft_eop then -- CHANGED: Should this be on the rising edge of in_fft_eop?
out_fifo_write <= '0'; -- ADDED: End of write mode?
f2h_state <= F2H_WAIT_START;
end if;
end case;
end if;
end if;
end process;
end architecture;
我希望这会有所帮助,但是没有 FFT 和 FIFO 的时序图,也没有测试台,我无法模拟它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.