摘 要:本文根據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芯片。
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所示。
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