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;
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;
相关文章推荐
- 用Java SPI实现可插拔
- SPI从机双工通信实现-基于Zenq 7000
- "阻塞--中断"驱动模型在i2c在子系统、uart驱动、spi子系统中的实现
- 硬件SPI实现
- Dubbo源代码实现四:Dubbo中的扩展点与SPI
- 用STM32F103RCT6+0.96寸OLED模块(ssd1306 12864 SPI)+4×4矩阵键盘实现贪吃蛇游戏的实验
- I2C串行总线协议的VHDL实现
- Dubbo源码分析 ---- 基于SPI的扩展实现机制
- Dubbo内核实现之SPI简单介绍
- [MSP430] 变态版3线SPI总线实现(DS1302时钟芯片用)
- 基于Linux的S3C6410模拟SPI的外围设备驱动程序、Makefile及测试程序的实现
- STM32 SPI接口的简单实现
- 用GPIO模拟SPI协议的实现[转]
- AT917S256 的SPI通信实现
- FPGA的SPI从机模块实现
- motan源码解读之--SPI(Service Provider Interface)实现方式浅析
- VHDL实现矩阵键盘检测
- CPLD 八段数码管时钟显示的VHDL实现
- 2.1 jdk-spi的实现原理
- FPGA通过SPI对ADC配置简介(四)-------Verilog实现4线SPI配置