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

在您的设计中,您有三个不同的信号 SPITrigSPI_Clock_baseTX_Start,它们像时钟一样工作,这很可能会导致时序违规。

例如,在大进程的第一个if中,TX_Startdata_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;