您的位置:首页 > Web前端

SPI的VHDL实现

2010-11-18 18:57 155 查看
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_arith.ALL;
USE ieee.std_logic_unsigned.ALL;
ENTITY spi IS
 PORT
 (
  --全局信号
  NReset   : IN  STD_LOGIC;        --全局复位信号
  Clk    : IN  STD_LOGIC;        --全局时钟
--  ResetWdi  : BUFFER STD_LOGIC;        --看门狗的喂狗信号
  --SPI通讯端口
  SPINcs   : INOUT  STD_LOGIC;        --SPI片选(低有效)
  SPIClk   : INOUT  STD_LOGIC;        --SPI时钟
  SPIMOSI   : INOUT  STD_LOGIC;        --SPI的主出从入
  SPIMISO   : INOUT  STD_LOGIC;        --SPI的主入从出
  --SPI数据寄存器
  SPITxdata  : IN  STD_LOGIC_VECTOR(15 DOWNTO 0);   --待发送数据
  SPIRxdata  : BUFFER STD_LOGIC_VECTOR(15 DOWNTO 0);   --接收数据
  --SPI状态寄存器
  SPIStatus  : BUFFER STD_LOGIC_VECTOR(7 DOWNTO 0);   --第5位为trdy(发送器准备好),第6位rrdy(接收器准备好)
  --SPI控制寄存器
  SPIControl  : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);   --第0位为mode(模式设置,0为主模式,1为从模式),
                   --第1位为clkpolarity(时钟极性,0时为空闲是低,1为空闲是高),
                   --第2位为clkphasic(时钟相位,0时为前沿检测,1为后沿检测),
                   --第3位为datapriority(数据先后,0时为MSB在前,1为LSB在前),
                   --第4位为start(上升沿开始发送数据),
                   --第7位sso(1时始终置cs为1(无效))
  SPILength  : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);   --数据位数寄存器
  --SPI频率设置寄存器
  SPISetClk  : IN  STD_LOGIC_VECTOR(31 DOWNTO 0)   --SPIClk为Clk的SPISetClk分频
 );
END spi;
ARCHITECTURE rtl OF spi IS
 TYPE StateType IS (S0_Wait,S1_Data,S2_Stop);       --状态机定义
 SIGNAL StateIndex  : StateType;         --状态机
 SIGNAL CntCycle  : integer RANGE 0 TO 16383;     --位周期计数器
 SIGNAL CntBit   : integer RANGE 0 TO 15;      --位数计数器
 SIGNAL SPITxdataTmp : STD_LOGIC_VECTOR(15 DOWNTO 0);    --数据锁存
 SIGNAL CycleBit  : integer RANGE 0 TO 16383;     --位周期
 
 SIGNAL SPIClkCut  : STD_LOGIC_VECTOR(31 DOWNTO 0);   --生成SPIClk计数器
 SIGNAL SPIBitCut  : integer RANGE 0 TO 15;     --SPI的数据位数计数
 --看门狗计数
-- SIGNAL CntWdi   : STD_LOGIC_VECTOR(9 DOWNTO 0);
BEGIN
--看门狗的喂狗信号的产生
--CntWdi <= CntWdi + 1 WHEN (Clk'EVENT AND Clk = '1');
--ResetWdi <= CntWdi(9);

--设置SPI的主从模式,若为主模式则设置SPINcs和SPIClk
PROCESS (NReset, Clk)
BEGIN
 IF(NReset = '0') THEN     --复位状态
  SPINcs <= 'Z';
  SPIClk <= 'Z';
  SPIMOSI <= 'Z';
  SPIMISO <= 'Z';
  SPIStatus <= "01100000";
  SPIRxdata <= X"0000";
  StateIndex <= S0_Wait;
  SPIClkCut <= X"00000000";
  SPIBitCut <= 0;
 ELSIF(Clk'EVENT AND Clk = '1') THEN
  IF(SPIControl(0) = '0') THEN   --主模式状态
   SPIMISO <= 'Z';
   CASE StateIndex IS
    WHEN S0_Wait =>
     SPIClk <= SPIControl(1);
     IF(SPIControl(4) = '1') THEN --判断起始标志
      SPINcs <= SPIControl(7);
      IF(SPIControl(3) = '0') THEN  --判断数据MSB还是LSB在前
       SPIMOSI <= SPITxdata(CONV_INTEGER(SPILength) - 1);
      ELSE
       SPIMOSI <= SPITxdata(0);
      END IF;
      SPIRxdata <= X"0000";
      StateIndex <= S1_Data;
      SPIStatus <= "00000000";
     ELSE
      SPINcs <= '1';
      SPIMOSI <= '0';
      StateIndex <= StateIndex;
      SPIStatus <= "01100000";
     END IF;
     SPIBitCut <= 0;
     SPIClkCut <= X"00000000";    
    WHEN S1_Data =>
     SPINcs <= SPIControl(7);
     IF(SPIClkCut  = ('0' & SPISetClk(31 DOWNTO 1)-'1')) THEN --SPIClk前沿
      SPIClk <= NOT SPIClk;
      SPIClkCut <= SPIClkCut + 1;
      IF(SPIControl(2) = '0') THEN   --前沿检测
       SPIMOSI <= SPIMOSI;
       IF(SPIControl(3) = '0') THEN  --判断数据MSB还是LSB在前
        SPIRxdata <= SPIRxdata;
        SPIRxdata(CONV_INTEGER(SPILength) - SPIBitCut - 1) <= SPIMISO;
       ELSE
        SPIRxdata <= SPIRxdata;
        SPIRxdata(SPIBitCut) <= SPIMISO;
       END IF;
      ELSE         --后沿检测
       IF(SPIControl(3) = '0') THEN  --判断数据MSB还是LSB在前
        SPIMOSI <= SPITxdata(CONV_INTEGER(SPILength) - SPIBitCut - 1);
       ELSE
        SPIMOSI <= SPITxdata(SPIBitCut);
       END IF;
       SPIRxdata <= SPIRxdata;
      END IF;
      StateIndex <= StateIndex;
      SPIBitCut <= SPIBitCut;
     ELSIF(SPIClkCut >= (SPISetClk(31 DOWNTO 0) -'1')) THEN  --SPIClk后沿
      SPIClk <= NOT SPIClk;
      SPIClkCut <= X"00000000";
      IF(SPIControl(2) = '0') THEN   --前沿检测
       IF(SPIControl(3) = '0') THEN  --判断数据MSB还是LSB在前
        SPIMOSI <= SPITxdata(CONV_INTEGER(SPILength) - SPIBitCut - 2);
       ELSE
        SPIMOSI <= SPITxdata(SPIBitCut);
       END IF;
       SPIRxdata <= SPIRxdata;      
      ELSE         --后沿检测
       SPIMOSI <= SPIMOSI;
       IF(SPIControl(3) = '0') THEN  --判断数据MSB还是LSB在前
        SPIRxdata <= SPIRxdata;
        SPIRxdata(CONV_INTEGER(SPILength) - SPIBitCut - 1) <= SPIMISO;
       ELSE
        SPIRxdata <= SPIRxdata;
        SPIRxdata(SPIBitCut) <= SPIMISO;
       END IF;
      END IF;
      IF(SPIBitCut >= CONV_INTEGER(SPILength) - 1) THEN
       SPIBitCut <= 0;
       SPIMOSI <= SPIMOSI;
       StateIndex <= S2_Stop;
      ELSE
       SPIBitCut <= SPIBitCut + 1;
       StateIndex <= StateIndex;
      END IF;
     ELSE
      SPIClk <= SPIClk;
      SPIMOSI <= SPIMOSI;
      StateIndex <= StateIndex;
      SPIClkCut <= SPIClkCut + 1;
      SPIBitCut <= SPIBitCut;
      SPIRxdata <= SPIRxdata;
     END IF;
     SPIStatus <= "00000000";
    WHEN S2_Stop =>
     IF(SPIClkCut  = ('0' & SPISetClk(31 DOWNTO 1)-'1')) THEN
      StateIndex <= S0_Wait;
      SPIClkCut <= X"00000000";
     ELSE
      StateIndex <= StateIndex;
      SPIClkCut <= SPIClkCut + 1;
     END IF;
     SPINcs <= SPINcs;
     SPIClk <= SPIClk;
     SPIMOSI <= SPIMOSI;
     SPIStatus <= SPIStatus;
     SPIRxdata <= SPIRxdata;
     SPIBitCut <= 0;
    WHEN OTHERS =>
     SPINcs <= 'Z';
     S
865d
PIClk <= 'Z';
     SPIMOSI <= 'Z';
     SPIStatus <= "01100000";
     SPIRxdata <= X"0000";
     StateIndex <= S0_Wait;
     SPIClkCut <= X"00000000";
     SPIBitCut <= 0;
   END CASE;
  ELSE         --从模式状态
   SPINcs <= 'Z';
   SPIClk <= 'Z';
   SPIMOSI <= 'Z';
  END IF;
 END IF;
END PROCESS;
END rtl;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息