FPGA上的输入信号边沿检测

时间:2015-07-14 13:25:21

标签: interface synchronization vhdl fpga spi

我正在尝试使用4线SPI(cs,sclk,miso,mosi)连接 Virtex 4(ML401)FPGA TIVA C系列板。 tiva充当主设备,FPGA充当从设备。 我能够从主设备接收SPI数据并在FPGA上显示LEDS上的数据(方法2)。然而, 我需要找到芯片选择信号的上升和下降转换(我的应用程序所需的同步目的)。 我已尝试过很多FIFO的方法(在仿真中运行良好),但只是不在FPGA上工作,如图所示:

注意: spi_cs 是从TIVA板输入到FPGA的异步SPI芯片选择信号,而其他信号(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;

方法2)

                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).

方法3)

                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;

指示灯总是“10101010”其他情况, spi_cs_h2l spi_cs_l2h < strong> ='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;

芯片选择引脚的至少一个从高到低的转换预计会点亮LED。 SPI芯片选择引脚始终接收“1”,当FPGA启动/复位时,LED指示灯亮起。 这怎么可能?这种错误的从高到低的转变怎么会发生?

1 个答案:

答案 0 :(得分:3)

方法1

这不会在spi_cs信号上执行任何类型的时钟域交叉,因此不是可靠的电路。

方法2

合成设计中的行if (spi_cs = '0' or spi_cs = '1') then始终为真,我不希望您能够使用此检测边缘

方法3

这确实为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'等。< / p>

方法3更新

听起来spi_cs实际上是低活跃的。您需要确保spi_cs_sspi_cs_ss等信号的初始值均正确无误。在这种情况下,我认为你应该将它们全部初始化为'1',因为这似乎是spi_cs的正常状态。所以你的信号声明看起来像signal spi_cs_s : std_logic := '1'。您应该能够在模拟中正确地看到这种行为。