我正在尝试使用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指示灯亮起。 这怎么可能?这种错误的从高到低的转变怎么会发生?
答案 0 :(得分:3)
这不会在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'
等。< / p>
听起来spi_cs
实际上是低活跃的。您需要确保spi_cs_s
和spi_cs_ss
等信号的初始值均正确无误。在这种情况下,我认为你应该将它们全部初始化为'1'
,因为这似乎是spi_cs
的正常状态。所以你的信号声明看起来像signal spi_cs_s : std_logic := '1'
。您应该能够在模拟中正确地看到这种行为。