pci卡設計心得

admin @ 2014-03-26 , reply:0


         其實從開始我對pci卡是一竅不通的,硬體還好說,軟體驅動程序更是一頭霧水,由於我的pci卡是要在windows98操作系統下應用的,所以必須編寫 pci卡的驅動程序,支持windows98下pnp硬體的驅動程序一般可以編程vxd。如果想為了以後的2k平台兼容就最好編wdm,因為 windows2k不支持vxd,而且以後的發展wdm肯定要代替vxd了。不過由於我找到的資料基本上都是介紹vxd的,感覺vxd的技術好像更成熟一點,編的人更多一點,所以偷了一下懶(慚愧),就沒有去研究wdm,就選擇了vxd。

我的pci卡其實很簡單,僅僅在本地端接了一個遙測信號的處理系統。

先說說硬體吧,其實按照正常的pci卡開發過程,仔細閱讀pci規範是很重要的,但是由於時間比較短,我也沒有很大的耐性看那些破規範,也就稍稍了解了一下。現在市場上有許多的專用的pci規範介面晶元,這些晶元提供的pci介面完全符合規範,具體符合的規範版本可以參看具體的晶元所以即使開發者不是很了解規範的具體細則,也可成功的設計pci卡。也就是可以達到傻瓜及設計。在連線上只要將對應的引腳連在匯流排上就可以了,在連線時要注意pci規範中提到了信號用的反射波信號,所以驅動的信號只用了要求電壓的一半,另一半靠反射來提升。所以對信號線的長度有要求:64位卡的32位信號具備的最大連線長度是 1500mil,64位擴展信號的附加信號的連線長度最大為2000mil,pci clk的長度為2500mil+/-100mil,如果不夠長度可以多繞幾圈。
還有一個要注意的是pci信號中prsnt1和prsnt2,開始我對這兩個信號一直不是很清楚,清華bbs上的精華區說得也是含糊,後來師兄 devilface告訴我的prsnt1和prsnt2兩者必須有一個接gnd,否則系統肯定找不到卡,主板就是靠這兩個信號來判斷這個插槽上是否有卡,而其接法同pci卡使用的功率有關具體的含義如下(0 表示懸空,1表示接地):
prsnt1 prsnt2 含義
0 0 no card
0 1 15w
1 0 25w
1 1 7.5w
另外pci卡上最好在從槽上引的電源上多加幾個電容,所有電源都必須退藕一般規範推薦pci卡做4層板,但是我只做了2層,其實無所謂,只要2層布得開,沒必要布4層,不過我布線的時候還是費了一點功夫,用specctra布了5,6次,為研究室節省開支嘛!(要是導師看見了該多感動呀!)
pci規範規定了5v和3.3v兩種電氣規範,我們一般的機器上都是5v規範的插槽當然也不乏3.3v的。所以我做的是5v的卡,不要以為5v的插槽上就得不到3.3v,一樣可以提供3.3v的。

前面提到了pci介面晶元,現在pci介面晶元技術已經比較成熟了,介紹一點我知道的:
AMCC:早期有5920,後來5933風靡國內,早期的PCI介面都是用這做的amcc最近又推出了5935,估計改了一些5933的bug,我看它的文檔幾乎與 5933一致.
plx :pci介面晶元的老大了.
9030,9052,9050:slave晶元
9050,9052面向isa卡轉pci的市場.
9030為嵌入式專門設計.他們的文檔不過100頁左右.不難
價錢便宜.不過170~190.
9054,9080,9060
9060是最早的32位master的pci控制晶元.
9080取代9060;9054可能更成熟一些.(?)
iop480.
好東西呀!帶sdram介面和嵌入cpu,只是開發起來困難比較大. 自己直接去plx的網站看看.www.plxtech.com,我就知道這麼點,大家可以補充。

我用的是9052,還是那句話,用的人多,技術成熟,遇到問題了可以到bbs發問。我就喜歡撿現成的,不服你就說嘛!!!!

9052的機理比較簡單,它內部提供了兩種配置寄存器。一種叫做pci configuration registers ,這就是我們常說的pci配置空間另外一個叫 local configuration registers,它提供了配置本地端的一些信息。這裡提到了本地端,說一說。其實9052就相當於一個橋,連接pci卡的本地端的晶元到pci匯流排上,將pci指令例如讀寫某個寄存器、內存、io翻譯到本地端。9052本地端提供了地址線26根(27:2)和數據線32根,還有LBE4根,可以翻譯成不同的地址線,太麻煩了我就不詳細說了,反正我用的LOCAL端是8位數據,在這種模式下LBE1和LBE0提供地址線[1:0]。PCI配置寄存器提供了6個基地址寄存器,這些基地址都是在系統中的物理地址其中BASE1 和BASE2 都是用來訪問LOCAL 配置寄存器的基地址,BASE1是映射到內存的基地址,BASE2是映射到IO的基地址。所以可以通過內存和IO來訪問LOCAL 配置寄存器。
BASE2~5四個空間提供了訪問本地端所接的4個晶元(當然可以少於4個),它們將本地端的晶元通過本地端地址(在LOCAL配置寄存器中設)翻譯成 PCI的地址,也就是將本地的晶元映射到系統的內存或io口。是不是很簡單呀?這樣使用你的程序操作這一段內存(或io)實際上就是對本地的晶元操作了。我使用的是內存映射,本地端的晶元地址例如是0x0cc000,將此地址放入local配置寄存器的相應位置(由於有四個空間,可以選擇任意一個空間來對應此晶元),我用的是space0,還要配置此空間的大小,這樣在pci匯流排端系統會根據這個大小分配相應的內存空間(或io)供9052使用來映射 local 上接的晶元。而系統分配的內存空間的信息會寫入pci配置寄存器中,只要讀出來就可以了。9052工作時還需要一個配置晶元eeprom,plx公司推薦了93cs46,這個eeprom比較好買,在中發一層就有。eeprom會在pci卡上電的時候配置9052,主要配置了pci卡的vendorID和 deviceID,這是系統用來標識pci卡的,很重要,你的程序就靠這個標識來找到pci卡。還配置了local端的4個space的local基地址和大小,以及每個space的其它一些參數(這裡不說了)。eeprom的內容很重要的,如果沒寫對很容易就出問題我開始老調不出來就是因為eeprom 中的配置寫錯了,鬱悶了好長一段時間喲!其實硬體本身很容易連,只要對應的腳相連就可以了,注意本地晶元如果不申請匯流排控制的話,9052的lhold信號一定要接gnd,還有如果本地晶元沒有提供irdy#信號,9052的對應腳也必須接地否則你一讀此晶元,系統就會死機,永遠等待那個irdy#信號有效才讀取數據。

再說軟體驅動,我說過我編的是vxd,用vtools編的,可以用vc++直接編譯成vxd文件,至於為什麼必須用vxd驅動我想就不用說了。我的vxd 的主要任務就是在系統中找到我的pci卡,並讀出本地晶元所映射的內存物理地址,在windows系統中,用戶程序不能直接訪問物理地址,只能使用線性地址,所以vxd還有做的一件事就是將物理地址轉換成線性地址供win app使用。 vxd查找pci卡就是靠搜索vendorID和deviceID,它是通過依次搜索匯流排號和設備號(具體什麼意思我也說不清,反正知道就行了),看是否有符合指定的vendorID和deviceID,如果符合則認為找到了pci卡的配置空間,因為配置空間的第一個雙字就是vendorID和 deviceID.然後向下面的地址依次讀就可以讀出pci卡的配置空間其他信息,包括space0映射的內存基地址。讀出此地址來再進行物理地址到線性地址的轉換,就可以完全供win app使用了(可以通過指針訪問),來讀取9052 local上掛的晶元了。
具體的查找方式主要通過vxd程序中首先向io地址0xcf8寫入最高位為1的雙字0x80000000,這個數的第16到23位代表了匯流排號,第11到15位代表了設備號,第8到14 位代表了功能號,然後就可以讀取io地址0xcfc的雙字,如果有效的話說明此pci配置空間地址上掛了一個pci卡,從0xcfc讀出的數則為此pci 卡配置空間的第一個雙字,即vendorID和deviceID,我是將vendorID和deviceID一起使用的,即判斷讀出的雙字是否等於我在 9052配置eeprom中標定的數,如果是則說明找到了我的pci卡,如果不是則繼續找。向0xcf8寫入的數+0x800,在繼續
讀0xcfc,依次下去,直到找到。如果當此數加到0x80ffff00時還沒找到(即匯流排號搜索完畢),則表明沒法找到,那就要找找自己的原因了,可能是板子的配置錯了。
找到了pci卡的配置空間后,讀出space0的基地址,然後進行物理地址到線性地址的轉換,我又偷了懶,vtools提供的example中有實現此功能的vxd源代碼,直接用vc++編譯成vxd就可以共win app使用了。所以實際上我的app程序使用了兩個vxd,一個用來專門找卡,一個用來地址轉換。
至於app如何調用vxd,可以參看vc的參考書,一般都有介紹。
下面將一下如何安裝vxd到系統中,我編的vxd都是動態載入的(pnp一般都用動態載入vxd)要編寫一個inf文件以便系統將vxd安裝進去。我用的是windriver生成的inf文件模板,然後再按照需要進行修改,自然加上我的大名了。編完了inf文件后,就可以安裝了。一般情況如果你插上pci 卡windows啟動后就會發現新硬體,你只要按照以前安裝硬體的步驟進行就可以了只是在選擇安裝文件時選擇自己編寫的inf文件就可以了。我覺得一般的安裝過程就是將vxd文件拷入系統的文件夾,即windows目錄下,以便當app載入vxd時,系統可以找到vxd程序,進行動態載入。
下面是我的inf文件

[Version]
Signature=$CHICAGO$ ;必須這麼寫
Class=PLX ;可以自己改
Provider=%SHENLI% ;製作者

[Manufacturer]
%Manufacture%=SECTION0

[SECTION0]
%my_card%=my.install,PCI\VEN_10b5&DEV_9050 ;my.install表示了安裝過程所要做的事,

[my.install]
CopyFiles=CopyFiles_PLX10b5 ;主要做拷貝文件和註冊表添加
AddReg=AddReg_PLX10b5


[CopyFiles_PLX10b5]
Vxd8_25.vxd

[AddReg_PLX10b5]
HKR,,DevLoader,0,Vxd8_25.vxd


[Strings]
Manufacture="BUAA202" ;這些信息會在安裝時顯示
my_card="PLX9052"


下面提供了vxd中查詢pci卡的代碼,這個代碼是參考清華bbs驅動版精華區huyuguang大蝦的大作,他提供了更詳細的代碼
有興趣可以參考。

BOOL findpci(DWORD DeviceVendor,PCIINF *pciinf)//我的卡的DeviceVendor=0x905210b5
{
DWORD io_cf8;
DWORD io_cfc;
int i;
DWORD buf[16];

io_cf8=0x80000000;
for(;;)
{
DWORD_OUT(0xcf8,io_cf8);//向0xcf8輸出雙字 io_cf8
io_cfc=DWORD_IN(0xcfc); //從0xcfc讀入雙字
if(io_cfc==DeviceVendor)//find pci9052
{
for(i=0;i<16;i++)
{
DWORD_OUT(0xcf8,io_cf8+4*i);
buf[i]=DWORD_IN(0xcfc);
}
pciinf->VendorID=(WORD)(buf[0]&0xffff);
pciinf->DeviceID=(WORD)((buf[0]&0xffff0000)/0x10000);
pciinf->Command=(WORD)(buf[1]&0xffff);
pciinf->Status=(WORD)((buf[1]&0xffff0000)/0x10000);
pciinf->RevisionID=(UCHAR)(buf[2]&0xff);
pciinf->CacheLineSize=(UCHAR)(buf[3]&0xff);
pciinf->LatencyTimer=(UCHAR)((buf[3]&0xff00)/0x100);
pciinf->HeaderType=(UCHAR)((buf[3]&0xff0000)/0x10000);
pciinf->BIST=(UCHAR)((buf[3]&0xff000000)/0x1000000);
pciinf->BaseAddresses[0]=buf[4];
pciinf->BaseAddresses[1]=buf[5];
pciinf->BaseAddresses[2]=buf[6];
pciinf->BaseAddresses[3]=buf[7];
pciinf->BaseAddresses[4]=buf[8];
pciinf->BaseAddresses[5]=buf[9];
pciinf->SubsystemVendorID=(USHORT)(buf[11]&0xffff);
pciinf->SubsystemID=(USHORT)((buf[12]&0xffff0000)/0x10000);
pciinf->InterruptLine=(UCHAR)(buf[15]&0xff);
pciinf->InterruptPin=(UCHAR)((buf[15]&0xff00)/0x100);
pciinf->MinimumGrant=(UCHAR)((buf[15]&0xff0000)/0x10000);
pciinf->MaximumLatency=(UCHAR)((buf[15]&0xff000000)/0x1000000);
break;
}
else
io_cf8+=0x800;
if(io_cf8>=0x80ffff00)
return 1;
}
return 0;
}

以上都是我這次製作卡的一些心得,還有很多不清楚的地方,寫出來只是想讓感興趣的pci門外漢了解一下,但願能有所幫助。肯定有很多錯誤,希望各位大蝦指正,但求不會誤人子弟。pci大蝦見笑了。




[admin via 研發互助社區 ] pci卡設計心得已經有7130次圍觀

http://www.cocdig.com/docs/show-post-45180.html