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_sspi_cs_ss 等信号的初始值都是正确的。在这种情况下,我认为你应该将它们全部初始化为 '1',因为这似乎是 spi_cs 的正常状态。所以你的信号声明看起来像 signal spi_cs_s : std_logic := '1'。您应该能够在模拟中看到此行为正常。