SPI 接口在模拟中工作,但在实际硬件上不工作
SPI interface works in simulation but not on actual hardware
我试图在传输期间在 SPI 总线上发送多个字节 window。最初我在输入脉冲为高电平时从闪存 ADC 获取数据,然后计算其平均值并在 SPI 总线上按顺序传输每个平均值。我让 SPI vhdl 模块工作,当我尝试发送单个字节时它能够发送数据,但是当我尝试发送超过 1 个字节时它就不起作用了。 MOSI 线上为逻辑 0,SS 线上持续为高电平。这是我尝试发送多个字节的部分。
process(SPITrig, Clock, TX_Done, data_count, average2A_s, average2B_s)
begin
case data_count is
when 1 =>
TX_Data <= average2A_s;
when 2 =>
TX_Data <= average2B_s;
when others => TX_Data <= "0101010101010101";
end case;
end process;
process(SPIBusy, SPITrig, SPI_Clock_base, data_count, TX_Start)
begin
if falling_edge(SPITrig) then
SPIBusy <= '1';
TX_Start <= '0';
data_count <= 0;
delay_counter <= 0;
end if;
if rising_edge(SPI_Clock_base) and SPIBusy = '1' then
if data_count < 3 then
if delay_counter = 128 then
TX_Start <= not TX_Start;
delay_counter <= 0;
elsif delay_counter < 128 then
delay_counter <= delay_counter + 1;
end if;
elsif data_count >= 3 then
TX_Start <= '0';
delay_counter <= 0;
SPIBusy <= '0';
end if;
end if;
if rising_edge(TX_Start) then
data_count <= data_count + 1;
end if;
end process;
它在模拟中运行良好,但在硬件上没有输出。需要您的帮助才能找出问题所在。
PS: 这是我的第一个FPGA项目,所以我的代码可能没有那么高效。
我还附上了 ISIM 截图。
可点击
tx = TX Done pin
trig = TX Start ping
c1 = data count
注意:SPI 传输序列在平均输出可用时启动,并使用内部信号触发"SPITRig"。
查看综合和时序 (STA) 警告,因为这些将指示综合工具是否无法实现与 RTL VHDL 代码匹配的设计。
rising_edge(...)
或 falling_edge(...)
的边沿条件只能用于单个公共时钟信号,除非有充分的理由使用多个时钟信号;通常只使用 rising_edge(...)
。
在您的设计中,您有三个不同的信号 SPITrig
、SPI_Clock_base
和 TX_Start
,它们像时钟一样工作,这很可能会导致时序违规。
例如,在大进程的第一个if
中,TX_Start
和data_count
都在falling_edge(SPITrig)
上更新,而在最后一个if
rising_edge(TX_Start)
用于根据当前 data_count
值再次更新 data_count
。这在模拟中可能工作得很好,但在 HW 中你有信号传播延迟,这取决于路由和其他可能对不同信号保持警惕的因素,因此像这样的设计结构可能会在实现中出现问题。
如果您的设计有完整的静态时序分析 (STA) 设置,而您可能没有 第一次进行 FPGA 项目,那么 STA 工具将能不能赶上就报告,像上面这样的施工很可能赶不上时间
因此,改写您的设计以仅使用单个时钟边沿,例如 rising_edge(SPI_Clock_base)
。为此类设计进行正确的 STA 时序设置也容易得多,并且过程的敏感度列表应仅包含时钟和任何异步复位信号(如果使用),例如:
process (SPI_Clock_base) is
begin
if rising_edge(SPI_Clock_base) then
...
end if;
end process;
最后,初始进程的敏感列表应该减少到只包含进程中读取的信号,因为进程只需要对这些信号敏感。如果包含更多信号,设计不会失败,这会让 reader 想知道哪里出了问题;敏感列表或代码。
按照 Morten Zilmer 的建议,我进行了必要的更改以将所有内容与时钟同步。以下是代码,它正在运行。可能 post 稍后使用示波器截屏。
process(SPITrig, data_count, average2A_s, average2B_s)
begin
case data_count is
when 1 =>
TX_Data <= average2A_s;
when 2 =>
TX_Data <= average2B_s;
when others => TX_Data <= x"0000";
end case;
end process;
SPICycler : process(delay_counter, data_count, SPITrig, SPI_Clock_base, SPIBusy)
begin
if rising_edge(SPI_Clock_base) and SPIBusy = '1' then
if delay_counter < 511 then
delay_counter <= delay_counter + 1;
TX_Start <= '0';
else
delay_counter <= 0;
TX_Start <= '1';
data_count <= data_count + 1;
end if;
end if;
if rising_edge(SPI_Clock_base) then
if SPITrig = '1' then
SPIBusy <= '1';
data_count <= 0;
end if;
if data_count = 3 then
SPIBusy <= '0';
end if;
end if;
end process;
我试图在传输期间在 SPI 总线上发送多个字节 window。最初我在输入脉冲为高电平时从闪存 ADC 获取数据,然后计算其平均值并在 SPI 总线上按顺序传输每个平均值。我让 SPI vhdl 模块工作,当我尝试发送单个字节时它能够发送数据,但是当我尝试发送超过 1 个字节时它就不起作用了。 MOSI 线上为逻辑 0,SS 线上持续为高电平。这是我尝试发送多个字节的部分。
process(SPITrig, Clock, TX_Done, data_count, average2A_s, average2B_s)
begin
case data_count is
when 1 =>
TX_Data <= average2A_s;
when 2 =>
TX_Data <= average2B_s;
when others => TX_Data <= "0101010101010101";
end case;
end process;
process(SPIBusy, SPITrig, SPI_Clock_base, data_count, TX_Start)
begin
if falling_edge(SPITrig) then
SPIBusy <= '1';
TX_Start <= '0';
data_count <= 0;
delay_counter <= 0;
end if;
if rising_edge(SPI_Clock_base) and SPIBusy = '1' then
if data_count < 3 then
if delay_counter = 128 then
TX_Start <= not TX_Start;
delay_counter <= 0;
elsif delay_counter < 128 then
delay_counter <= delay_counter + 1;
end if;
elsif data_count >= 3 then
TX_Start <= '0';
delay_counter <= 0;
SPIBusy <= '0';
end if;
end if;
if rising_edge(TX_Start) then
data_count <= data_count + 1;
end if;
end process;
它在模拟中运行良好,但在硬件上没有输出。需要您的帮助才能找出问题所在。 PS: 这是我的第一个FPGA项目,所以我的代码可能没有那么高效。 我还附上了 ISIM 截图。
tx = TX Done pin
trig = TX Start ping
c1 = data count
注意:SPI 传输序列在平均输出可用时启动,并使用内部信号触发"SPITRig"。
查看综合和时序 (STA) 警告,因为这些将指示综合工具是否无法实现与 RTL VHDL 代码匹配的设计。
rising_edge(...)
或 falling_edge(...)
的边沿条件只能用于单个公共时钟信号,除非有充分的理由使用多个时钟信号;通常只使用 rising_edge(...)
。
在您的设计中,您有三个不同的信号 SPITrig
、SPI_Clock_base
和 TX_Start
,它们像时钟一样工作,这很可能会导致时序违规。
例如,在大进程的第一个if
中,TX_Start
和data_count
都在falling_edge(SPITrig)
上更新,而在最后一个if
rising_edge(TX_Start)
用于根据当前 data_count
值再次更新 data_count
。这在模拟中可能工作得很好,但在 HW 中你有信号传播延迟,这取决于路由和其他可能对不同信号保持警惕的因素,因此像这样的设计结构可能会在实现中出现问题。
如果您的设计有完整的静态时序分析 (STA) 设置,而您可能没有 第一次进行 FPGA 项目,那么 STA 工具将能不能赶上就报告,像上面这样的施工很可能赶不上时间
因此,改写您的设计以仅使用单个时钟边沿,例如 rising_edge(SPI_Clock_base)
。为此类设计进行正确的 STA 时序设置也容易得多,并且过程的敏感度列表应仅包含时钟和任何异步复位信号(如果使用),例如:
process (SPI_Clock_base) is
begin
if rising_edge(SPI_Clock_base) then
...
end if;
end process;
最后,初始进程的敏感列表应该减少到只包含进程中读取的信号,因为进程只需要对这些信号敏感。如果包含更多信号,设计不会失败,这会让 reader 想知道哪里出了问题;敏感列表或代码。
按照 Morten Zilmer 的建议,我进行了必要的更改以将所有内容与时钟同步。以下是代码,它正在运行。可能 post 稍后使用示波器截屏。
process(SPITrig, data_count, average2A_s, average2B_s)
begin
case data_count is
when 1 =>
TX_Data <= average2A_s;
when 2 =>
TX_Data <= average2B_s;
when others => TX_Data <= x"0000";
end case;
end process;
SPICycler : process(delay_counter, data_count, SPITrig, SPI_Clock_base, SPIBusy)
begin
if rising_edge(SPI_Clock_base) and SPIBusy = '1' then
if delay_counter < 511 then
delay_counter <= delay_counter + 1;
TX_Start <= '0';
else
delay_counter <= 0;
TX_Start <= '1';
data_count <= data_count + 1;
end if;
end if;
if rising_edge(SPI_Clock_base) then
if SPITrig = '1' then
SPIBusy <= '1';
data_count <= 0;
end if;
if data_count = 3 then
SPIBusy <= '0';
end if;
end if;
end process;