并口通信是最常用基礎功能,實現ARM9與FPGA的并口通信有兩種方式,一種頗為巧妙,利用SMC(Static Memory Controllor),其中的使能點都通過寄存器可以輕松控制;另一種方式就是通過GPIO來完成。
由于我拿到板子硬件的DRAM_CSN0、DRAM_WEN和DRAM_RDN在前期PCB設計時沒有充分考慮過SMC可能被使用,故使用接插件上其他引腳進行代替,使用了圖1中畫圈的三根引腳SPI0_MOSI、SPI0_SCK、SPI0_CS。因為這三根引腳可以復用為GPIO,所以在并口調試中將這三根引腳當作GPIO來使用。
圖1
圖2
圖3
表1
原SPI功能 | GPIO | FPGA引腳 | 功能 |
SPI0_MOSI | PA1 | W21 | 寫使能 |
SPI0_SCK | PA2 | W22 | 讀使能 |
SPI0_CS | PA3 | W20 | 片選 |
硬件連接對應情況如圖2、圖3和表1所示。到此,你應該已經了解了實現通信需要關注的引腳了吧。
工程步驟:
1??????重設Pin Planner
根據當前硬件的實際連接情況,對Quartus中的Pin Planner進行更新,將信號i_rd_cpu、i_wr_cpu、i_select對應的location改為PIN_W22、PIN_W21、PIN_W20。如圖4所示。
圖4
2??????對PIOA的寄存器組重新初始化
在最初的驅動程序中包括了對GPIO的初始化,經過試驗觀察PIO可讀寄存器的內容發現寄存器的配置不能滿足本任務的完成,使用已有的初始化會干擾到使能信號的操作,于是要對GPIO進行重新初始化,對寄存器進行配置。
2.1???????PIO_PER寄存器
圖5
該寄存器是用來啟用PIOA各個引腳的GPIO模式,如圖5所示,每一位都對應控制著一根GPIO管腳,通過給P1、P2、P3置1激活了PA1、PA2、PA3的GPIO模式,同時也等于關閉了復用外圍A、B的模式。
2.2???????PIO_OER寄存器
圖6
該寄存器有默認的設置,觀察發現最低4位默認為1100。本項目需要用到GPIO的輸出模式,所以需要對該寄存器進行重新配置,給P1,P2,P3置1,開啟引腳的輸出功能。
2.3???????PIO_PUDR寄存器
圖7
通過觀察PIO_PUSR寄存器可以發現默認的上拉寄存器是全部開啟的,上拉寄存器的啟用會影響GPIO的正常輸出,所以通過PIO_PUDR寄存器將上拉寄存器關閉,為之后正常操控GPIO提供基礎。
數據的寫入:
1???????概況
PIO_SODR和PIO_CODR這兩個寄存器可以將指定位的GPIO電平置1置0。由于這里設計的讀寫使能為低電平有效,在程序中首先將涉及的信號均拉高,相當于對信號進行一個復位。之后就可以進行數據的發送工作。
圖8
圖9
圖8為連續發送0x1122,0x3344,0x5566等多個數據時的情況,在寫使能的上升沿對數據總線和地址總線上的信息進行取樣;圖9中顯示當寫使能信號上升沿的時刻,數據總線上的信息為0x5566,地址總線上的信息為0x0005,即將0x5566存儲到RAM的0x0005地址中。(上圖SignalTap采樣時鐘為125MHz)
在一個發送周期中,經歷以下過程:
0:地址總線上出現地址信息;
1:片選信號拉低;
2:寫使能信號拉低;
3:數據放到數據總線上;
4:寫使能拉高,同時在上升沿時刻對數據取樣;
5:片選信號拉高。
在DATASHEET的SMC一章中有對并口的發送時序進行描述,當前實驗結果也符合數據手冊中通過SMC實現并口通信的說明,如圖10、圖11所示??梢?,其實兩種方式大同小異,實現的結果相同。
圖10
圖11
2???????ARM中數據的發送
通過FPGA_WriteData函數完成數據的發送工作,其中使用了PIO寄存器中的PIO_CODR,PIO_SODR,PIO_ODSR三個寄存器,分別實現使能拉低,使能拉高,和標志位判斷的功能。
#define?WREG(x)?(*((volatile unsigned short *)(x)))?語句中,(volatileunsigned short *)(x)將x定義為了一個地址指針,再通過*取內容,這樣就可以將數據寫到這個地址上,在之后的程序中只要直接調用WREG()就可以方便的向地址寫數據。
3???????FPGA中數據的存儲
reg uprise_wr_dly;
always @(posedgei_clk,negedge i_rst_n)
begin
if(!i_rst_n)
uprise_wr_dly <= 1'b0;
else
uprise_wr_dly <= i_wr_cpu_pre;
end
reg wr;
always @(posedgei_clk,negedge i_rst_n)
begin
if(!i_rst_n)
wr <= 1'b0;
else if((i_wr_cpu_pre == 1'b1) && (uprise_wr_dly ==1'b0))
wr <= 1'b1;
else
wr <= wr;
end
以上程序制作了一個比寫使能信號延后一個clock的信號,再通過兩個信號的組合判斷實現了寫使能上升沿信號的處理。這在FPGA的程序中是很常見的處理方式。
最后通過RAM程序中的接口程序,將已經處理好的數據總線信號、地址總線信號和使能信號、時鐘信號添加進接口當中,功能便實現了。
數據的讀?。?/p>
數據讀取時的使能信號同樣使用了PIO_CODR和PIO_SODR這兩個關鍵的寄存器,按照時序控制這兩個寄存器的值即可。
數據讀取的情況如圖12所示:
圖12
通過對FPGA編程將數據0x3456放到數據總線上,在ARM的程序中對數據總線所在的地址進行讀取,就可以將數據讀出。這里將讀出的數據存儲到了PIOC寄存器中,你也可以把它放到變量中來觀察,驗證對錯。在IAR里查看PIOC的只讀寄存器PIOC_ODSR就可以看到數據已經被存放到了寄存器當中。
關于涉及到的寄存器、寄存器的控制方式、使能信號的時序以及相關軟件的使用和編程思路,讀取與寫入是大致一樣的,這里不再重復描述。
評論
查看更多