摘 要:本文根据SPI同步串行接口的通信协议,介绍了在CPLD中利用VHDL语言实现PC/104总线扩展SPI接口的设计原理和编程思想。通过该方法的介绍,使得那些没有SPI接口功能的处理器和控制器能够扩展SPI接口,以便同外部设备进行数据交换。并给出了VHDL语言的源代码程序。
关键词:SPI接口;CPLD;PC/104总线;接口设计;VHDL
0 引言
近年来,带有SPI总线接口的器件越来越多,该器件可以共用SPI总线,十分方便的组成多个带有SPI总线接口的系统。尽管这种总线结构没有并行总线那样大的吞吐能力,但由于连接线和连接引脚少,因此其构成的系统价格降低,器件间总线连接简单,结构紧凑,而且在总线上增加器件不影响系统的正常工作,系统修改和可扩张性好。
PC/104与标准台式PC(PC/AT)体系无论是硬件还是软件上都完全兼容。在形态上,PC/104是十分紧凑的、自栈式、模块化结构。如今利用PC/104总线来制作各种各样的设备越拉越多,在使用的过程中,经常要用到具有SPI总线接口的器件。本文将介绍一种基于CPLD来实现PC/104总线扩展SPI接口的设计方案。
1 SPI总线接口及时序
SPI(Serial Peripheral Interface)总线接口是一种同步串行数据接口。 这一通讯接口采用单独的三根信号线(SCLK、MOSI、MISO)传送数据及同步时钟,可以实现全双工通信,由CS片选线实现多机通信或扩展多片SPI芯片。


SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI主模块和与之通信的外设间时钟相位和极性应该一致。SPI 接口时序如图1、图2所示。
2 设计方案
本文以PC/104总线与多个SPI接口模块为例,说明基于CPLD的SPI总线接口设计方案。通过CPLD整合时序实现PC/104总线与SPI总线的转换,满足SPI总线的时序要求。
利用CPLD具有以下优点:①采用CPLD可以根据需要定义输入输出脚,方便PCB板布局和走线;②采用CPLD时不必担心设计中所采用器件的种类、数量,可以任意定义所需各种器件,从而优化电路性能;③采用CPLD可以通过软件对电路进行仿真,方便电路调试;④采用CPLD可以在线修改其内部逻辑,升级或修改可不改动外部电路。
CPLD芯片选用ALTERA公司的EPM7064SLC84-10,该芯片具有基于EEPROM的第二代MAX结构,支持通过JTAG引脚实现在系统编程。拥有64个宏单元,4个逻辑阵列块,1250个可用门单元,支持5V/3.3V多电压IO接口,可提供68个用户IO引脚
2.1 系统的结构设计
系统的基本功能是通过CPLD 来实现PC/104总线与SPI总线的数据交换。系统的结构框图如图3所示。系统主要由两部分组成:一是PC/104总线与CPLD的接口;另一是SPI接口。为了能在PC/104总线制定的时刻读/写SPI接口的数据,使用PC/104总线的读写信号、同步时钟、数据总线和地址总线。
2.2 SPI接口的设计结构
基于CPLD设计的SPI接口其目的在于为PC/104处理器扩展SPI接口的功能。能够实现PC/104总线与SPI总线之间的通信。为了满足扩展SPI接口功能,基于CPLD的SPI接口必须具有以下功能:①与PC/104总线的接口功能;②多位外部从机选择功能;③时钟极性和相位选择不同,有四种传输模式功能;④SPI数据传送完成标志。 在SPI接口中,芯片EPM7128SLC-84的I/O接口被定义为SPI接口的控制线、数据线和地址线等。SPI接口的结构框图如图4所示。在我们设计的速率校准装置的SPI接口中,状态端RDY和片选端CS已经够用。如果外部有更多的SPI接口模块,我们可以通过软件的编程与设置,扩展更多的状态端RDY和片选端CS,并共用时钟线和数据线,实现扩展具有SPI接口的外部设备。
图
3 时序
PC/104总线对SPI总线的访问很简单,只需对SPI接口模块内的数据寄存器(30AH)、控制寄存器(304H)以及状态寄存器(300H)进行读写。其中控制寄存器功能有中断使能位、MOSI高阻位、时钟极性与相位以及片选信号;状态寄存器可以读取RDY的状态以及中断标志。下面以读和写两种时序来说明PC/104总线对SPI接口访问时SPI接口的时序图。
在对SPI接口写数据时,它的工作过程是先向控制寄存器内写入控制字,以确定工作方式。然后再向数据寄存器写入要发送的数据,工作时序图5所示。
在对SPI接口读数据时,同样需要向控制寄存器写入控制字,以确定其工作方式,并使MOSI处于高阻状态。然后向数据寄存器内写入任意值,其目的是产生同步时钟脉冲以及移位寄存器开始工作,以使外部MISO信号传送到移位寄存器内。当IRQ为高电平,说明数据接收完成,即可读取移位寄存器内的数据即为SPI接口发送的数据,工作时序图6所示。

图5 SPI接口写工作时序图

图6 SPI接口读工作时序图
4 软件编程
软件的编程主要分为移位寄存器的移位、数据寄存器的读写、系统时钟的分频、时钟的相位极性确定等几大部分。如下为它们的VHDL语言源代码,由于篇幅原因,结构体内的定义语句没有给出。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_signed.all;
entity spi_top is
port( clk, wr_n, rd_n, misoi : in std_logic;
irq, mosio, scko : out std_logic;
addr : in std_logic_vector(9 downto 0);
data : inout std_logic_vector(7 downto 0);
rdy : in std_logic_vector(2 downto 0);
slv_sel : out std_logic_vector(2 downto 0) );
end spi_top;
architecture spi of spi_top is
begin
data <= shift_reg when addr=SPIFT_ADDR and rd_n='0' else
stat_reg when addr=SPISR_ADDR and rd_n='0' else
"ZZZZZZZZ";
mosio <= shift_dataout when open_drain ='0' else 'Z';
sr_proc : process(clk)
begin
if(clk'event and clk='1')then
if(spi_go='1')then shift_reg<=data_reg;
elsif(shift_clk='1')then
shift_reg <= shift_reg(6 downto 0) & shift_datain;
end if;
end if;
end process;
neg_proc : process(clk)
begin
if (clk'event and clk='1') then
if (shift_clk_negedge='1') then
shift_negative_edge <= shift_negative_edge_nxt;
elsif (spi_go='1') then
shift_negative_edge <= shift_reg(7);
end if;
end if;
end process;
shift_negative_edge_nxt <= shift_reg(7) when phase='1' else misoi ;
shift_dataout <= shift_negative_edge when phase='1' else shift_reg(7);
shift_datain <= shift_negative_edge when phase='0' else misoi;
tr_proc : process(clk)
begin
if (clk'event and clk='1') then
if (tx_start='1') then tx_run <= '1';
elsif (tx_end='1') then tx_run <= '0';
end if;
end if;
end process;
bc_proc : process (clk)
begin
if (clk'event and clk='1') then
if (tx_start='1') then bit_ctr <= bit_counter;
elsif (shift_clk='1') then bit_ctr <= bit_ctr-1;
end if;
end if;
end process;
tx_end <= '1' when bit_ctr=001 and shift_clk='1' and tx_run='1' else '0';
tx_start <= '1' when spi_go='1' else '0';
elr_proc : process (clk)
begin
if (clk'event and clk='1') then
if (tx_end ='1')then irq_flag <='1';
elsif (tx_run='1')then irq_flag <='0';
end if;
end if;
end process;
dvd_proc : process (clk)
begin-
if (clk'event and clk='1') then
if (not (tx_run='1' ) or tx_end='1') then
dvd_ctr <= "00000", dvd2 <= '0';
else
if (dvd_ctr=00000) then dvd_ctr <= clock_div;
if(tx_start_r1 ='0')then dvd2 <= not dvd2;
end if;
else dvd_ctr <= dvd_ctr-1;
end if;
end if;
end if;
end process;
dvd_zero <= '1' when dvd_ctr=00000 else '0';
shift_clk <= dvd_zero and dvd2 and tx_run and not tx_start_r1;
shift_clk_negedge <= dvd_zero and not dvd2 and tx_run;
scko <= dvd2 xor polck;
wr_data : process(wr_n,tx_run)
begin
if(tx_run='1')then spi_go<='0';
elsif (wr_n'event and wr_n='1' ) then
if( addr=spift_addr) then
data_reg <= data, spi_go <='1';
end if;
end if;
end process;
wr_ctl : process(wr_n)
begin
if (wr_n'event and wr_n='1') then
if addr=spic_addr then ctl_reg <= data;
end if;
end if;
end process;
slv_sel(2 downto 0)<= ctl_reg(2 downto 0);
irq_en <= ctl_reg(7), open_drain <= ctl_reg(6);
phase <= ctl_reg(5), polck <= ctl_reg(4);
irq <= irq_flag and ctl_reg(7);
stat_proc:process(rdy,irq_flag)
begin
stat_reg <= irq_flag & "0000" & rdy(2 downto 0);
end process;
end spi;
5结论
随着SPI通信方式的广泛应用,但对于很多并行总线与之通信成了很大的障碍,本文提出的解决方案具有非常好的可移植性和产品开发能力。本系统既可以作为一个单独的系统运行,又可以作为一个通信模块植入一个大系统中,而其中的SPI接口又是一个可移植SPI接口。利用CPLD的逻辑可编程性,还可以在其剩下的资源中再开发所需要的逻辑器件,既能降低硬件成本又能大大减少系统主板的面积,使电路的设计更具灵活性。该设计已经被应用到转台速率校准装置中,在该设计中共有两个SPI模块,同时还利用了CPLD控制继电器等其它电路,在历次试验中其性能指标及稳定性均达到了要求。
参考文献
[1] Xilinx Limited. CoolRunner-II Serial Peripheral Interface Master. 2002
[2] 北京华夏龙科技有限公司.HXL/486II 技术手册.
[3] Altera. MAX 7000 Programmable Logic Device Family Data Sheet.1995
[4] 赵俊超 集成电路设计VHDL教程. —北京:北京希望电子出版社2002,8
|