LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.STD_LOGIC_signed.ALL;
-------------------------------------------------------------------------------------------
ENTITY spi IS
GENERIC(CPHA: INTEGER := 1;CPOL: INTEGER := 1);--模式3空闲高电平,前沿输出后沿采样
PORT(
--系统时钟与复位
clk : IN STD_LOGIC;--50MHZ
rst_n : IN STD_LOGIC;
--与主机的接口
din : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
req : IN STD_LOGIC;
dout : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
dout_vld : OUT STD_LOGIC;
--SPI物理接口
cs_n : OUT STD_LOGIC;--片选信号
sclk : BUFFER STD_LOGIC;--串行时钟
miso : IN STD_LOGIC;--主机输入从机输出
mosi : OUT STD_LOGIC --主机输出从机输入
);
END spi;
--------------------------------------------------------------------------------------------
ARCHITECTURE spi OF spi IS
CONSTANT SCLK_NUM: INTEGER := 16;--对系统时钟进行16分频变为3125KHZ
CONSTANT SCLK_BEFORE: INTEGER := SCLK_NUM/4;
CONSTANT SCLK_AFTER: INTEGER := SCLK_NUM*3/4;
TYPE state IS(IDLE,WAIT_L,DATA,DONE);
SIGNAL state_c,state_n: state;
SIGNAL bit_cnt: INTEGER RANGE 0 TO 7;--bit计数器
SIGNAL sclk_cnt: INTEGER RANGE 0 TO 15;--时钟计数器
SIGNAL tx_data: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL rx_data: STD_LOGIC_VECTOR(7 DOWNTO 0);
signal t,t_l,tmp:STD_LOGIC;
BEGIN
PROCESS(clk,rst_n)
BEGIN
IF(rst_n = '0') THEN
state_c <= IDLE;
ELSIF(clk'EVENT AND clk = '1') THEN
state_c <= state_n;
END IF;
END PROCESS;
-------------------------------------------------------------------------------------------
PROCESS(state_c,req,bit_cnt)
BEGIN
CASE state_c IS
WHEN IDLE =>
IF(req = '1')THEN
state_n <= WAIT_L;
END IF;
WHEN WAIT_L =>
state_n <= DATA;
WHEN DATA =>
IF(tmp = '1')THEN--() AND
state_n <= DONE;
END IF;
WHEN DONE =>
state_n <= IDLE;
WHEN OTHERS =>
state_n <= IDLE;
END CASE;
END PROCESS;
-----------------------------------bit_cnt ---------------------------------------------------------
PROCESS(clk,rst_n)
BEGIN
IF(rst_n = '0') THEN
bit_cnt <= 0;
ELSIF(clk'EVENT AND clk = '1')THEN
IF((state_c = DATA) AND (sclk_cnt = SCLK_NUM-1)) THEN
IF(bit_cnt = 7)THEN
bit_cnt <= 0;
ELSE
bit_cnt <= bit_cnt + 1;
END IF;
ELSE
bit_cnt <= bit_cnt;
END IF;
END IF;
END PROCESS;
----------------------------------sclk计数器---------------------------------------------------------
PROCESS(clk,rst_n)
BEGIN
IF(rst_n = '0') THEN
sclk_cnt <= 0;
ELSIF(clk'EVENT AND clk = '1')THEN
IF(state_c = DATA) THEN
IF(sclk_cnt = SCLK_NUM-1)THEN
sclk_cnt <= 0;
ELSE
sclk_cnt <= sclk_cnt + 1;
END IF;
ELSE
sclk_cnt <= sclk_cnt;
END IF;
END IF;
END PROCESS;
----------------------------------16分频串行时钟 CPHA=1 CPOL=1-----------------------------------------------------------
PROCESS(clk,rst_n)
BEGIN
IF(rst_n = '0') THEN
IF(CPHA = 0)THEN
sclk <= '0';--空闲低电平
ELSIF(CPHA = 1)THEN
sclk <= '1';
END IF;
ELSIF(clk'EVENT AND clk = '1')THEN
IF((state_c = DATA)AND(sclk_cnt = SCLK_BEFORE-1))THEN
sclk <= NOT sclk;
ELSIF((state_c = DATA)AND(sclk_cnt = SCLK_AFTER-1))THEN
sclk <= NOT sclk;
END IF;
END IF;
END PROCESS;
---------------------------------发送的数据mosi,高位先行------------------------------------------------------------------
PROCESS(clk,rst_n)
BEGIN
IF(rst_n = '0')THEN
tx_data <= "00000000";
ELSIF(clk'EVENT AND clk = '1')THEN
IF(CPOL = 0)THEN
IF((state_c = DATA)AND(sclk_cnt = SCLK_AFTER-1))THEN --后沿输出
tx_data <= din;
END IF;
ELSIF(CPOL = 1)THEN
IF((state_c = DATA)AND(sclk_cnt = SCLK_BEFORE-1))THEN
tx_data <= din;
END IF;
END IF;
END IF;
END PROCESS;
----------------------------------接收的数据miso-----------------------------------------------------------------------------
PROCESS(clk,rst_n)
BEGIN
IF(rst_n = '0')THEN
rx_data <= "00000000";
ELSIF(clk'EVENT AND clk = '1')THEN
IF(CPOL = 0)THEN
IF((state_c = DATA)AND(sclk_cnt = SCLK_BEFORE-1))THEN --前沿采样
rx_data(7-bit_cnt) <= miso;
END IF;
ELSIF(CPOL = 1)THEN
IF((state_c = DATA)AND(sclk_cnt = SCLK_AFTER-1))THEN
rx_data(7-bit_cnt) <= miso;
END IF;
END IF;
END IF;
END PROCESS;
----------------------------------------出bug后加的--(sclk_cnt=15)AND(bit_cnt = 7)出现状态机不跳转---------------------------------
PROCESS(sclk_cnt)BEGIN
IF((sclk_cnt=15))THEN
t<='1';
ELSE
t <= '0';
END IF;
END PROCESS;
PROCESS(bit_cnt)BEGIN
IF(bit_cnt = 7)THEN
t_l<='1';
ELSE
t_l <= '0';
END IF;
END PROCESS;
tmp <= t and t_l;
------------------------------------------------------------------------------------------------------------------------------------
mosi <= tx_data(7-bit_cnt);
cs_n <= NOT req;
dout <= rx_data;
dout_vld <= tmp;
END spi;