VHDL尝试实现SPI接口

时间:2014-08-11 17:49:32

标签: vhdl spi

我正在尝试实现SPI接口。我有2个问题,这是第一个。 (我决定单独提出每个问题以简化事情。

似乎没有任何工作,所以我将我的设计剥离到一个移位寄存器,其中输入的数据应该返回到SPI主设备。

这就是我现在所拥有的。

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

end interface;

architecture Behavioral of interface is

-- SPI
signal SPI_REG: std_logic_vector(7 downto 0) := (others => '0');

-- SPI interface
process(SPI_CLK)

begin

    if rising_edge(SPI_CLK) then

        SPI_MISO <= SPI_REG(7);
        SPI_REG <= SPI_REG(6 downto 0) & SPI_MOSI; -- Concatenate bits

    end if;

end process;

end Behavioral;

我还有一个在Raspberry Pi上运行的主(cpp)程序。

它再次非常基础,这就是它的作用。

#include <wiringPiSPI.h>
#include <iostream>

int main()
{
    wiringPiSPISetup(0, 500000); // Device 0, slowest speed available

    // Create array of 64 bytes (unsigned char)
    // Print this array

    wiringPiSPIDataRW(0, data, 64);

    // Print array again and compare data by eye
}

目前我已经设置了数组创建,因此它按顺序包含数字0到63。在将每个转换为int之后打印出来。 (为简单起见,我省略了这段代码。)

这是一个典型的输入:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...

这是典型的输出:

31 128 0 129 1 130 2 131 3 132 4 135 5 134 6 ...

所以前2个字节是垃圾。我本来期望返回1个垃圾字节...一个被设置为包含零! (与VHDL代码一样。)

然后在此之后,每隔一个字节都是垃圾,我不知道为什么......并且发送的实际数据似乎被返回,尽管它返回中间有垃圾字节......

我不确定这是因为我误解了SPI硬件定义,还是我的VHDL代码不正确。

1 个答案:

答案 0 :(得分:1)

快速回答

第一个时钟输入位需要9个时钟周期才能出现在输出端。

验证方法

我将代码更改为以下内容,并注意到与将MOSI连接到MISO的直线相比,输出延迟了1位。 (将这2个引脚短接,没有延迟,正如预期的那样,但是下面的代码产生了1位延迟。)

请注意,对于熟悉VHDL的人来说,这应该是非常明显的。

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

end interface;

architecture Behavioral of interface is

-- SPI
signal SPI_REG: std_logic_vector(7 downto 0) := (others => '0');

-- SPI interface
process(SPI_CLK)

begin

    if rising_edge(SPI_CLK) then

        SPI_MISO <= SPI_MOSI;

    end if;

end process;

end Behavioral;

如果这会产生1位延迟,那么你应该明白为什么,如果你已经完成了一些基本的数字电子设备。 (这是由于时钟边缘通过系统传输数据的方式,当然。)

完整解决方案

因此,为了解决这个问题,您只需更改代码即可使用异步数据传输。 (不确定VHDL世界中这个名称的正确名称。)

这是改变:

process(SPI_CLK)

begin

    SPI_MISO <= SPI_MOSI;

    if rising_edge(SPI_CLK) then

    end if;

end process;

这种数据传输立即发生(或至少非常快,纳秒或更短),而不仅仅是在时钟边缘。

所以8位的完整解决方案就是这样:

实体界面

port
(
     -- SPI
    SPI_MOSI: in std_logic;
    SPI_MISO: out std_logic;
    SPI_CLK: in std_logic;
);

end interface;

architecture Behavioral of interface is

-- SPI
signal SPI_REG: std_logic_vector(7 downto 0) := (others => '0');

-- SPI interface
process(SPI_CLK)

begin

    SPI_MISO <= SPI_REG(7);

    if rising_edge(SPI_CLK) then

        SPI_REG <= SPI_REG(6 downto 0) & SPI_MOSI; -- Concatenate bits

    end if;

end process;

end Behavioral;

输入需要8个时钟周期才能出现在输出端,而不是9。