VHDL:信号不能合成,同步描述不好

时间:2014-08-10 15:28:15

标签: hardware vhdl spi

我正在尝试在VHDL中实现类似SPI接口的东西,以便与FPGA一起使用。

我对VHDL的理解是有限的,因为我只使用它2天,我想我还没有理解如何使用时钟边缘控制数据流。

我目前的理解是,您可以将VHDL视为过程编程语言,只要您希望在过程中执行的每条指令按顺序完成,每个时钟周期一条指令。

这可能听起来很奇怪,所以这就是我到目前为止所做的。有一个名为SPI_REG的寄存器,它包含8位数据,由外部时钟输入和输出。 (主从SPI设备时钟.FPGA是从设备。主设备是Arduino,Raspberry Pi,手机等。)

有一个串行输入和串行输出端口,它连接到主设备。 (MISO和MOSI数据线。)

有一个计数器,用于计算时钟数。它有8个时钟,从0到7,然后翻转。当主设备将8位数据输入寄存器时,该计数器激活一个标志。

FPGA内部时钟的运行速度比SPI外部时钟高得多(50 MHz?)。在内部时钟的每个上升沿,我们检查标志是否已设置,这意味着已经传输了8位数据,并且FPGA必须将此数据复制出来,对其执行某些操作并将一些返回数据重新放入下一个SPI时钟。因此,为什么内部时钟必须高得多。

这个“字节改组”过程必须分阶段完成。

  1. 将字节从SPI寄存器复制到寄存器。
  2. 返回字节从另一个寄存器复制到SPI寄存器。
  3. 总共有3个寄存器。 SPI寄存器,发送寄存器和接收寄存器。

    为了测试程序,我决定填充发送寄存器,接收寄存器的内容与零字节进行异或。 “00000000”(这还没有“做”任何事情。)

    我希望我解释得很好,这里有一些代码。

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    
    entity interface is
    
        port
        (
    
            -- SPI
            SPI_MOSI: in std_logic;
            SPI_MISO: out std_logic;
            SPI_CLK: in std_logic;
    
            -- FPGA clocks
            SYSTEM_CLK: in std_logic;
        );
    
    end interface;
    
    architecture Behavioral of interface is
    
        -- SPI
        signal SPI_REG: std_logic_vector(7 downto 0) := (others => '0');
        signal SPI_BUFFER_OUT: std_logic_vector(7 downto 0) := (others => '0'); -- Holds most recent 8 bits transferred over SPI
        signal SPI_BUFFER_IN: std_logic_vector(7 downto 0) := (others => '0'); -- Holds next 8 bits to be transferred over SPI
    
        -- Shift register data
        --DATA_IN: in std_logic_vector(7 downto 0) := (others => '0');
        --DATA_OUT: out std_logic_vector(7 downto 0) := (others => '0');
    
    begin
    
        -- SPI interface
        process(SYSTEM_CLK, SPI_CLK)--, AUDIO_CLK, BUSY)
    
            -- SPI interface
            variable spi_clk_count: integer := 0; -- count 8 data clocks
            variable system_clk_count: integer := 0; -- count system clocks for moving data out and in to spi register
            variable system_clk_flag: boolean := false;
            variable send_data_count: integer := 0;
    
            -- ADC control
            variable read_data_clock_count: integer := 0; -- count clock pulses for timing the reading of the ADC
            variable convst_flag: integer := 0; -- flag for the convst signal to the ADC
    
        begin
    
            -- SPI external clock
            if rising_edge(SPI_CLK) then
                -- Clock data out of serial_out (MISO or MOSI)
    
                if system_clk_flag = false then
                    -- Complete transfers
                    SPI_MISO <= SPI_REG(7);
    
                    -- Clock data in spi_reg along 1 bit and feed in 1 bit from serial_in (MOSI or MISO)
                    SPI_REG <= SPI_REG(6 downto 0) & SPI_MOSI; -- Concatinate bits
                end if;
    
                -- Check for full 8 bits
                if spi_clk_count = 7 then
                    spi_clk_count := 0;
    
                    -- Signal system clock to move byte out of and byte in to register
                    if system_clk_flag = false then
                        -- Set buffer overrun error flag
    
                        -- Signal data to be clocked out and clocked in anyway
                        system_clk_flag := true;
                    end if;
                else
                    -- Increment spi clock counter
                    spi_clk_count := spi_clk_count + 1;
                end if;
    
            end if;
    
    
            -- System internal clock
            if rising_edge(SYSTEM_CLK) then
    
                -- To test, return the XOR of the bits with zero (do nothing)
                -- Continue shuffling data if required
                if system_clk_count = 1 then
                    -- Increment system_clock_count
                    -- Change flag to "step 2"
                    system_clk_count := 2;
    
                    -- This is for debugging purposes
                    SPI_BUFFER_IN <= SPI_BUFFER_OUT xor "00000000";
    
    
                elsif system_clk_count = 2 then
                    -- Increment system_clock_count
                    -- Change flag to "step 3"
                    system_clk_count := 3;
    
                    -- Move data from SPI_BUFFER_IN to register
                    SPI_REG <= SPI_BUFFER_IN;
    
                elsif system_clk_count = 3 then
                    -- Signal that we are done
                    system_clk_flag := false;
    
                    -- Reset clock count
                    system_clk_count := 0;
    
                -- Check for signal for system clock to move data to and from SPI register
                elsif system_clk_flag = true then -- This must be done here because it is the lowest priority of the statements
                    -- Signal for byte shuffling, clock data in and out
                    system_clk_count := 1;
    
                    -- Move data from SPI register to SPI_BUFFER_OUT register
                    SPI_BUFFER_OUT <= SPI_REG;
                end if;
    
            end if;
    
    end Behavioral;
    

    我有一种感觉,我构建它的方式是完全错误的。我可以绘制一个可以(我认为)工作的电路图,但是我在使用VHDL设计一些东西时遇到了麻烦。

    它没有语法错误,但不能合成。非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

某些综合工具在同一过程中不支持多个时钟。修复也会指出您正在尝试使用两个时钟加载SPI_REG。

作为建议,对每个时钟域使用一个进程,不要使用共享变量,不要使用标志。您需要跨时钟域握手的唯一地方是SPI_BUFFER_OUT。 SPI_BUFFER_IN由系统时钟加载,_OUT由SPI时钟加载。

注意由时钟边界交叉握手引起的亚稳态。应该只对具有更高速度时钟和/或异步操作的系统。没有定时模型就无法模拟亚稳性。这种模式通常只是抱怨

使用异步系统接口,您可以使用单个锁存器来缓冲从系统端或SPI端加载的缓冲区。这将需要一些输入多路复用和OR两个使能一起。

如果您的系统时钟和SPI时钟源自更高速度的时钟并且彼此之间具有整数关系,则可以使用时钟使能和更高速度的时钟。