FPGA 上的输入信号边沿检测
Input Signal Edge Detection on FPGA
我正在尝试使用 4 线 SPI(cs, sclk、味噌、mosi)。 tiva 作为主机,FPGA 作为从机。
我能够从主机接收 SPI 数据并在 FPGA 上的 LEDS 上显示数据(方法 2)。然而,
我需要找到芯片 select 信号的上升和下降转换(我的应用需要同步)。
我已经尝试了很多使用 FIFO 的方法(在模拟中效果很好),但就是在 FPGA 上不起作用,如图所示:
注意:spi_cs是异步SPI芯片select信号从TIVA板输入到FPGA,而其他信号 (spi_cs_s、spi_cs_ss、spi_cs_h2l、spi_cs_l2h 等) 是在 FPGA 内部创建的。
方法 1)
prc_sync_cs: process(clk)
begin
if (clk'event and clk = '1') then
spi_cs_s <= spi_cs;
end if;
end process prc_sync_cs;
spi_cs_l2h <= not (spi_cs_s) and spi_cs;
spi_cs_h2l <= not (spi_cs) and spi_cs_s;
方法二)
process (spi_cs)
begin
if (spi_cs = '0' or spi_cs = '1') then
-- update ledss with new MOSI on rising edge of CS
spi_cs_ss <= spi_cs_s;
spi_cs_s <= spi_cs;
--leds <= spi_wdata; --leds display the received data on the FPGA (saved into spi_wdata in another process)
-- THIS WORKS ON THE FGPA BUT the edge detection doesn't. Why?
end if;
end process;
spi_cs_h2l <= '1' when (spi_cs_s = '0' and spi_cs_ss = '1') else '0';
spi_cs_l2h <= '1' when (spi_cs_s = '1' and spi_cs_ss = '0') else '0';
leds <= "000000" & spi_cs_h2l & spi_cs_l2h; -- ALL leds are off always (i,e both transitions are '0' always).
方法三)
prc_sync_cs: process(clk)
begin
if (clk'event and clk = '1') then
spi_cs_ss <= spi_cs_s;
spi_cs_s <= spi_cs;
end if;
end process prc_sync_cs;
prc_edge_cs: process(clk)
begin
if (clk'event and clk = '1') then
spi_cs_ss_del <= spi_cs_ss;
end if;
end process prc_edge_cs;
spi_cs_h2l <= '1' when (spi_cs_ss_del = '1' and spi_cs_ss = '0') else '0';
spi_cs_l2h <= '1' when (spi_cs_ss_del = '0' and spi_cs_ss = '1') else '0';
所有方法在仿真中都能完美运行,但下载到 FPGA 时却不行。我编写了一个过程来更密切地监视转换(以监视亚稳态值,如果有的话):
led_test: process(spi_cs_h2l, spi_cs_l2h)
begin
if spi_cs_h2l = '1' or spi_cs_l2h = '1' then
leds <= "111100" & spi_cs_h2l & spi_cs_l2h;
elsif spi_cs_h2l = 'X' or spi_cs_h2l = 'U' or spi_cs_h2l = 'Z' or
spi_cs_l2h = 'X' or spi_cs_l2h = 'U' or spi_cs_l2h = 'Z' then
leds <= "00001111";
else
leds <= "10101010";
end if;
end process led_test;
LED 总是 "10101010" 即 else 情况 spi_cs_h2l 和spi_cs_l2h是='0'。我错过了什么??
任何指示都会非常有帮助,因为很多天以来我一直坚持这个问题。
更新
使用时钟域交叉的方法3(如Jeff所建议的),并通过将所有的LED和信号初始化为零,点亮LED的过程改变如下:
led_test: process(spi_cs_h2l)
begin
if rising_edge(clk) then
if spi_cs_h2l = '1' then
leds <= "11110011";
end if;
end if;
end process led_test;
芯片 select 引脚的至少一个高电平到低电平转换预计会点亮 LED。 SPI 芯片 select 引脚始终接收“1”,当 FPGA 为 started/reset 时,LED 亮起。
这怎么可能?这种从高到低的假转换是如何发生的?
方法一
这不会在 spi_cs
信号上执行任何类型的时钟域交叉,因此不是可靠的电路。
方法二
if (spi_cs = '0' or spi_cs = '1') then
行在合成设计中始终为真,我不希望您能够使用此
检测边缘
方法三
这确实为 spi_cs
提供了时钟域交叉,总体上看起来还不错。您在 LED 上看到 "10101010"
的原因是因为在 SPI 事务的开始或结束时,它们一次只显示一个 clk
周期的不同内容。这可能比您在 LED 上用肉眼看到的要快得多。
此外,行elsif spi_cs_h2l = 'X' or spi_cs_h2l = 'U' or spi_cs_h2l = 'Z' or spi_cs_l2h = 'X' or spi_cs_l2h = 'U' or spi_cs_l2h = 'Z' then
不会转化为FPGA中的任何真实硬件,因为真实硬件没有办法检查'U'
、'Z'
等.
方法 3 更新
听起来 spi_cs
实际上是低电平有效。您需要确保 spi_cs_s
和 spi_cs_ss
等信号的初始值都是正确的。在这种情况下,我认为你应该将它们全部初始化为 '1'
,因为这似乎是 spi_cs
的正常状态。所以你的信号声明看起来像 signal spi_cs_s : std_logic := '1'
。您应该能够在模拟中看到此行为正常。
我正在尝试使用 4 线 SPI(cs, sclk、味噌、mosi)。 tiva 作为主机,FPGA 作为从机。 我能够从主机接收 SPI 数据并在 FPGA 上的 LEDS 上显示数据(方法 2)。然而, 我需要找到芯片 select 信号的上升和下降转换(我的应用需要同步)。 我已经尝试了很多使用 FIFO 的方法(在模拟中效果很好),但就是在 FPGA 上不起作用,如图所示:
注意:spi_cs是异步SPI芯片select信号从TIVA板输入到FPGA,而其他信号 (spi_cs_s、spi_cs_ss、spi_cs_h2l、spi_cs_l2h 等) 是在 FPGA 内部创建的。
方法 1)
prc_sync_cs: process(clk)
begin
if (clk'event and clk = '1') then
spi_cs_s <= spi_cs;
end if;
end process prc_sync_cs;
spi_cs_l2h <= not (spi_cs_s) and spi_cs;
spi_cs_h2l <= not (spi_cs) and spi_cs_s;
方法二)
process (spi_cs)
begin
if (spi_cs = '0' or spi_cs = '1') then
-- update ledss with new MOSI on rising edge of CS
spi_cs_ss <= spi_cs_s;
spi_cs_s <= spi_cs;
--leds <= spi_wdata; --leds display the received data on the FPGA (saved into spi_wdata in another process)
-- THIS WORKS ON THE FGPA BUT the edge detection doesn't. Why?
end if;
end process;
spi_cs_h2l <= '1' when (spi_cs_s = '0' and spi_cs_ss = '1') else '0';
spi_cs_l2h <= '1' when (spi_cs_s = '1' and spi_cs_ss = '0') else '0';
leds <= "000000" & spi_cs_h2l & spi_cs_l2h; -- ALL leds are off always (i,e both transitions are '0' always).
方法三)
prc_sync_cs: process(clk)
begin
if (clk'event and clk = '1') then
spi_cs_ss <= spi_cs_s;
spi_cs_s <= spi_cs;
end if;
end process prc_sync_cs;
prc_edge_cs: process(clk)
begin
if (clk'event and clk = '1') then
spi_cs_ss_del <= spi_cs_ss;
end if;
end process prc_edge_cs;
spi_cs_h2l <= '1' when (spi_cs_ss_del = '1' and spi_cs_ss = '0') else '0';
spi_cs_l2h <= '1' when (spi_cs_ss_del = '0' and spi_cs_ss = '1') else '0';
所有方法在仿真中都能完美运行,但下载到 FPGA 时却不行。我编写了一个过程来更密切地监视转换(以监视亚稳态值,如果有的话):
led_test: process(spi_cs_h2l, spi_cs_l2h)
begin
if spi_cs_h2l = '1' or spi_cs_l2h = '1' then
leds <= "111100" & spi_cs_h2l & spi_cs_l2h;
elsif spi_cs_h2l = 'X' or spi_cs_h2l = 'U' or spi_cs_h2l = 'Z' or
spi_cs_l2h = 'X' or spi_cs_l2h = 'U' or spi_cs_l2h = 'Z' then
leds <= "00001111";
else
leds <= "10101010";
end if;
end process led_test;
LED 总是 "10101010" 即 else 情况 spi_cs_h2l 和spi_cs_l2h是='0'。我错过了什么?? 任何指示都会非常有帮助,因为很多天以来我一直坚持这个问题。
更新
使用时钟域交叉的方法3(如Jeff所建议的),并通过将所有的LED和信号初始化为零,点亮LED的过程改变如下:
led_test: process(spi_cs_h2l)
begin
if rising_edge(clk) then
if spi_cs_h2l = '1' then
leds <= "11110011";
end if;
end if;
end process led_test;
芯片 select 引脚的至少一个高电平到低电平转换预计会点亮 LED。 SPI 芯片 select 引脚始终接收“1”,当 FPGA 为 started/reset 时,LED 亮起。 这怎么可能?这种从高到低的假转换是如何发生的?
方法一
这不会在 spi_cs
信号上执行任何类型的时钟域交叉,因此不是可靠的电路。
方法二
if (spi_cs = '0' or spi_cs = '1') then
行在合成设计中始终为真,我不希望您能够使用此
方法三
这确实为 spi_cs
提供了时钟域交叉,总体上看起来还不错。您在 LED 上看到 "10101010"
的原因是因为在 SPI 事务的开始或结束时,它们一次只显示一个 clk
周期的不同内容。这可能比您在 LED 上用肉眼看到的要快得多。
此外,行elsif spi_cs_h2l = 'X' or spi_cs_h2l = 'U' or spi_cs_h2l = 'Z' or spi_cs_l2h = 'X' or spi_cs_l2h = 'U' or spi_cs_l2h = 'Z' then
不会转化为FPGA中的任何真实硬件,因为真实硬件没有办法检查'U'
、'Z'
等.
方法 3 更新
听起来 spi_cs
实际上是低电平有效。您需要确保 spi_cs_s
和 spi_cs_ss
等信号的初始值都是正确的。在这种情况下,我认为你应该将它们全部初始化为 '1'
,因为这似乎是 spi_cs
的正常状态。所以你的信号声明看起来像 signal spi_cs_s : std_logic := '1'
。您应该能够在模拟中看到此行为正常。