《管理信息化外接晶片读写的验证以为范例.》由会员分享,可在线阅读,更多相关《管理信息化外接晶片读写的验证以为范例.(16页珍藏版)》请在金锄头文库上搜索。
1、ARM9外接晶片讀寫的驗証-以8255為範例外接8255主要目的是透過位址線及資料線做外接晶片讀寫的驗証。ARM9可透過如圖1所示的轉接訊號線擴充其他的晶片功能。圖1. ARM-9的轉接訊號線解碼位址圖2代表ARM-9的外接記憶體解碼位址分佈,共分8個區段(bank)。這些區段分別由nGCS0-nGCS7來解碼,每個區段(bank)共有128 MB的記憶體空間。 Bank0及Bank1分別由快閃記憶體(Flash memory)及隨機讀取記憶體(SDRAM)所佔用。Bank2的解碼致能線nCGS2位於透過ARM-9發展板轉接槽的第34個接腳,如圖1所示。nCGS2解碼位址分佈於0x100000
2、00-0x18000000,如圖2所示。圖2. nGCS2的解碼位址分佈圖3中ARM9的記憶體區段(Bank)的解碼線nGCS2接8255的/CS;(A1, A0)分別接8255的(A1, A0);DATA7-DATA0分別接8255的D7-D0,如圖3所示。所以8255的(PORTA, PORTB, PORTC, CTL)的寫入位址定義如下:PORTA=0x10000000;PORTB=0x10000001;PORTB=0x10000002;CTL=0x10000003;圖3. 8255與ARM-9的連接方法ARM-9的資料線共有32位元(DATA31-DATA0)。然而外接記憶體(或I/O
3、)可規劃為8位元、16位元及32位元共三種模式。究竟選擇那種模式,可透過規劃BWSCON暫存器的內容來決定。BWSCON暫存器的位址為0x48000000。規劃Bank2的外接記憶體(或I/O) 資料線讀寫位元數為8位元,可規劃BWSCON暫存器的(bit9, bit8)為00,如圖4所示。程式規劃的參考方法如下圖4. BWSCON暫存器的bit10-bit0所規劃的功能ARM-9外接記憶體(或I/O)的讀寫時序如圖6所示。圖6中讀寫的各項時間參數(Tacs, Tcos, Tacc, Tacp, Tcoh, Tcah)可由BANKCONx暫存器(x=0,1.5)來調整。BANKCON2暫存器的
4、位址為0x4800000c,如圖5所示。圖5. BANKCON2暫存器的位址圖6. ARM-9外接記憶體(或I/O)的讀寫時序8255驅動程式之建立在Linux核心中,驅動程式扮演特殊的黑盒子角色,它們能駕馭硬體裝置,並且隱藏硬體的實際作業細節,使硬體的回應方式符合一組嚴謹規定的程式介面,讓應用程式能透過一套標準化的系統呼叫來間接操作硬體。以實際的硬體動作來實現系統呼叫所定義的功能,正是驅動程式所扮演的角色。由於系統呼叫這層軟體介面的存在,使得驅動程式與核心的其餘部分可以分開製作,並且在需要時,才在執行期將驅動程式安插到核心裡。這種模組化的設計,不僅降低了Linux驅動程式的設計難度,也使得核
5、心不必為了支援新硬體而頻頻改版。裝置驅動程式大致分為區塊驅動程式、字元驅動程式及網路介面驅動程式。區塊驅動程式是以固定大小長度來傳送轉移資料,且大致是可以隨機存取資料的設備,如硬碟機或光碟機;字元裝置是可被當成一連串位元組(串流)來存取的裝置,也就是說這類裝置的存取方式就像檔案一樣。字元裝置驅動程式的主要任務,正是實現這種行為。這類驅動程式至少會實作四項系統呼叫,分別是open()、close()、read()和write()。我們所熟悉的操控台與序列埠(/dev/console、/dev/ttyS0),就是典型的字元裝置,因為它們都可順利化身成串流。字元裝置必須透過檔案系統節點(filesy
6、stem node)來存取;檔案系統節點俗稱為裝置檔(device file),例如/dev/tttyS0、/dev/console。字元裝置與一般正常檔案之間的最大差異,是一般檔案容許你任意改變存取點(檔案指標),但字元裝置大部分都只是資料通道,只能被循序存取。1 模組程式的基本觀念一個驅動程式必須被撰寫成模組的型態,才能夠具備供使用者載入與移除的特性。因此一個驅動程式必然會具有載入模組函式與移除模組這兩個函式。故此兩個函式就分別載入驅動程式與移除驅動程式的角色。應用程式在啟動之後,從頭到尾都只執行同一件任務。另一方面,模組在被載入核心之後,必須先向核心註冊它自己,以便服務未來的reques
7、t,而其”main”函式這時候就立即結束了。換言之,init_module( ) 函式 (模組的入口) 的任務,是將模組的功能 (函式) 準備好,使這些功能可在事後被調用。模組的第二個入口點是 cleanup_module ( ),它在模組被卸載之前會被叫用一次,其作用就是告訴核心:我要離開了,別再叫我做任何事。圖7描繪模組如何利用函式呼叫與函式指標,將新功能加到運行中的核心。應用程式則是在使用者空間(user space) 內運作。每當應用程式發出系統呼叫,或是發生硬體中斷時,LINUX便會將執行模式從user-space切換到kernel-space。驅動程式碼必須在kernel-spac
8、e內運作。圖7 將模組連結至核心 2主標號(Major number)與次標號(Minor number) 當使用者要存取字元裝置時,必須透過檔案系統裡的代表名稱,這些特殊檔是集中在 /dev/目錄之下。使用指令ls-l /dev得到如圖8的結果。可看出在日期欄之前可以發現兩個以逗號隔開的數值,在逗號左方的數值是該裝置檔的主編號(major number),而逗號右方的數值是次編號(minor number)。主編號代表裝置所配合驅動程式。當核心收到open( )系統呼叫時,就是依據主編號來選擇驅動程式。另一方面,次編號的意義只有驅動程式自己才知道,核心會將使用者給定的次編號轉交給驅動程式,核
9、心本身用不到次編號。一般而言,驅動程式以次編號來辨識同類裝置的個體。圖8主編號與次標號要增加一個新驅動程式到系統,等於指派一個主編號給它。這項指派應該在驅動程式(模組)的初使期,藉由呼叫linux/fs.h 所定義的register_chrdev( )函式來完成:int register_chrdev(unsigned int major, const char *name, struct file_operation *fops);此函數的傳回值代表註冊動作的成功與否。負值表示失敗,0或正值表示成功。major引數是驅動程式想要註冊的主標號;name是裝置的名稱(如果註冊成功,這名稱將會出現
10、在 /proc/devices檔案的內容裡);fops是一個指標,指向一個函式指標陣列(arrary of function pointers),此陣列紀錄了驅動程式各個入口點(作業方法)的位置。在驅動程式向核心完成了註冊之後,驅動程式的各項作業方法(operation)就與給定的主編號產生了關連性。每當有人對字元裝置檔進行某項操作時,核心就能從該裝置檔的主編號找出對應的驅動程式,並透過其file_operations結構來呼叫對應的作業方法。下一個問題是如何給應用程式一個名稱,讓它們能利用此名稱來啟動驅動程式。這個名稱必須安插在 /dev/ 目錄下,而且必須關連到驅動程式的主編號與次編號。在
11、檔案系統製作節點的命令是mknod,你必須有特權身分(root)才能使用此工具。mknod至少需要四個參數,例如:mknod /dev/c8255_driver c 42 0第一個引數是節點名稱,其後的三個引數分別是裝置類型(c代表char device)、主編號、以及次編號。就像任何儲存在磁碟上的普通檔案一樣,mknod所產生的裝置節點會被保存下來,除非刻意用rm命令刪除它們。我們在驅動程式主程式中做以下定義及宣告:#defineCHDRV_MAJOR42char CHDRV_NAME = c8255_driver;而我們系統實作時的驅動程式註冊的動作是在一個init_module程式中實現
12、:int init_module(void)if(register_chrdev(CHDRV_MAJOR, CHDRV_NAME, &c8255_chdrv_fops) printk(kernel: %s: Unable to register character devicen, CHDRV_NAME);return -EIO;.在模組被卸載之前,它必須先釋放主標號,而這個動作可由unregister_chrdev( ) 完成,我們在模組的清理函式裡呼叫它:void cleanup_module(void)unregister_chrdev(CHDRV_MAJOR, CHDRV_NAME);
13、printk(unloaded.n);return;CHDRV_MAJOR引數是要被釋放的主編號,CHDRV_NAME是當初註冊的裝置名稱。這兩個引數必須與當初呼叫register_chrdev( ) 所用的引數一致,否則 unregister_chrdev( ) 將傳回EINVAL。2 檔案作業與file 結構驅動程式內部以一個file結構來代表一個已開啟的裝置,核心透過一個file_operations 結構來存取驅動程式內部的作業函式(method)。這結構定義在linux/fs.h。file_operations 結構包括指向驅動程式的各種系統呼叫,例如read, write, ope
14、n, release.。操作檔案結構的各種系統呼叫,其實際動作就是靠驅動程式內部的作業系統來達成的。file_operations 結構宣告範例如下:static struct file_operations c8255_chdrv_fops = NULL, /*lseek*/read: c8255_chdev_read, /* read */write: c8255_chdev_write, /* write */ NULL, /* readdir */ NULL, /* POLL */ NULL, /* ioctl */ NULL, /* mmap */ open: c8255_chdev
15、_open, /* open */ NULL, /* FLUSH */release: c8255_chdev_release, /* release */ NULL, /* fsync */ NULL, /* fasync */ NULL, /* lock */ NULL, /* readv */ NULL, /* writev */ NULL, /* send page */ NULL, /* get unmapped area */ ;習慣上,我們以變數名稱(例如c8255_chdrv_fops)來表示file_operations結構。在file_operations結構中每一個欄位,都必須指向驅動程式中負責特定作業方法,對於驅動程式不需要的作業項目,其對應欄位需指向NULL。我們在此文中所使用到的作業方法包括有read( )、write( )、open( )及release( ),在此做一個簡單的介紹。1. op