歡迎您光臨本站 登入註冊首頁

概述

1引言   嵌入式系統是在有限的資源及有限的體積中運行的、高效地實現某種特殊功能的功能集合,常常要面對較弱的CPU處理能力、少量的電力消耗、有限的內存空間、非常小的體積、……

1 引言
    嵌入式系統是在有限的資源及有限的體積中運行的、高效地實現某種特殊功能的功能集合,常常要面對較弱的CPU處理能力、少量的電力消耗、有限的內存空間、非常小的體積、簡潔特定的用戶操作界面。它的目的是在設計時限定好的資源中來實現用戶需要的功能。
    PowerPC823是Motorola公司的PowerQUICC系列嵌入式通信處理器中的一種,以精簡指令集RISC的體系結構為基礎,集成了32位微處理器和多種外設介面,具有強大的通信和網路協議處理能力,廣泛應用於通信和網路產品。功能結構主要包括:嵌入式PowerPC內核,系統介面單元(System Interface Unit,SIU)和通信處理模塊(Communications Processor Module,CPM)。
    本文主要分析了PowerPC823的PCMCIA的介面、行列式掃描鍵盤的原理、外部I/O存儲器的訪問、Linux下字元設備驅動程序和內核模塊的實現、Input機制編程原理等,最後筆者結合Pcmcia介面如何實現鍵盤驅動。

2.Pcmcia介面簡介
    對於控制Pcmcia介面,Pcmcia介面模塊提供有6種類型介面寄存器:Pcmcia介面輸入引腳寄存器(PIPR)、Pcmcia介面狀態變化寄存器(PSCR)、Pcmcia介面使能寄存器(PER)、Pcmcia介面通用控制寄存器B(PGCRB)、Pcmcia基地址寄存器(PBR0-7)和Pcmcia選項寄存器(POR0-7)。這些寄存器都被存儲器映射到內部控制寄存器區內。其中,前4種類型的寄存器既可以用於控制Pcmcia介面模塊的通用I/O引腳(包括8個輸入IP_B[0:7]引腳和2個輸出OP_B[2:3]引腳);而後2種類型寄存器共有8對16個寄存器,這些寄存器專用於Pcmcia控制器。通過對Pcmcia介面模塊的寄存器編程,用戶可以靈活地控制Pcmcia介面模塊。
    在實現的開發板上,根據行列式掃描鍵盤的原理,屏蔽掉Pcmcia控制器,把引腳IP_B[0:7]定義為通用I/O口線,Pcmcia介面有幾個比較關鍵的寄存器,它們分別是PIPR、PSCR、PER、PGCRB(A)。
    PIPR:Pcmcia介面輸入管腳寄存器,用來採樣Pcmcia輸入信號,當Pcmcia控制器停止工作時,PIPR的16-23位可以讀寫作為通用I/O口線的IP_B[0:7]。
    PSCR:Pcmcia介面狀態變化寄存器,跟蹤Pcmcia介面輸入信號狀態的變化。
    PER:Pcmcia介面中斷使能寄存器,不過位116-22和位24-27分別報告給了不同的中斷等級。
    PGCRB(A):Pcmcia介面通用控制寄存器,對產生的中斷指定不同的中斷控制。在我們的開發板上使用了PGCRB。

3.行列式掃描鍵盤的原理
    隨著信息家電、手持設備、無線設備等的迅速發展,相應的硬體和軟體也得到迅速發展,在以MCU為核心的許多應用程序中,都需要有鍵盤的輸入功能以實現人機介面。一般而言,硬體上的實現方法有兩種:第一種直接使用一路I/O口,每個引腳引一個按鍵,在程序中使用輪詢的方式判斷是否有鍵按下,然後就具體的按健執行對應的功能。另一種就是採用陣列式按健鍵盤和MCU的帶有鍵盤中斷的并行I/O口組成。
    針對開發板的設計,利用外接的一塊串口晶元ST16C552,把其8根印表機口的并行輸出口線和4根狀態信號線定義為列,而與Pcmcia介面的IP[0:7]定義為行,在初始化與之相關的寄存器的初始值后(驅動實現中介紹初始化),當有鍵被按下時,與Pcmcia的I/O口相連的那行輸入口線產生中斷,可以讀取用來採樣Pcmcia輸入信號的PIPR寄存器中位的值確定行,此時它所對應的位是低電平。在列的掃描輪詢的程序中通過軟體依次對列的12根輸出口線置“0”,若此時讀取PIPR的值與開始時一致,就可以確定出列,Input機制調用函數把行列所對應的鍵的鍵值作為參數傳遞給內核,在LCD屏上顯示對應的按鍵。

4.外部I/O存儲器的訪問
    CPU常常連接外部設備,在開發板的設計中,外接了擁有一些寄存器的一塊串口晶元ST16C552,它們被稱為外部I/O存儲器。外部I/O存儲器通過匯流排被CPU讀或者寫,在Linux操作系統中,不管是用戶空間還是內核空間,都不能使用物理地址直接訪問。因為Linux使用了MPC的MMU單元,MMU控制物理地址到虛擬地址的轉換,所有對外部I/O存儲器物理地址的操作都必須預先在MMU中註冊,並且返回虛擬地址,通過訪問虛擬地址來實現訪問物理地址,Linux中使用下面的函數來實現物理地址到虛擬地址的轉換及註冊:
void *ioremap(unsigned long address,unsigned long size);
void iounmap(void *addr);
對於不同大小埠的訪問,有不同的訪問函數,在鍵盤驅動中使用了函數void writeb(unsigned value,address)。
writeb(0x00,io_base);
writeb(0xeb,io_base+2);
wmb();
    最後的wmb()是一個write memory barrier宏定義,它保證在它前面的寫操作按順序執行。
    若讀者有興趣可以去讀文件include,總結了對i/O埠訪問、申請和釋放的函數。

5.Linux下字元設備驅動程序和內核模塊機制的簡述
    設備驅動程序是操作系統內核和硬體之間的介面,屬內核的一部分,主要功能如下:

  •  對設備初始化或釋放;
  •  把數據從內核傳送到硬體和從硬體讀取數據;
  •  讀取應用程序傳送給設備的數據和回送應用程序請求的數據;
  •  監測和處理設備出現的異常。

    設備驅動程序為應用程序屏蔽了硬體的細節,這在應用程序看來,硬體設備只是一個設備文件,應用程序可以象操作普通文件一樣對硬體設備進行操作。
    編寫鍵盤設備驅動,需要了解Linux Module(Linux內核)的概念。Linux內核是一個整體的結構,因此向內核添加任何東西或者刪除某些功能,都十分困難。為了解決這個問題,Linux引入了內核模塊機制,從而可以動態地在內核中添加或者刪除模塊。在調入內核之後,Linux Module和內核處於同一地址空間的,它們可以相互調用函數,直接訪問對方的地址,每個Linux模塊必定包括以下兩個函數,從KerneL2.2開始定義有點變化,在鍵盤驅動中定義為:
static int __int pkbd_init(void)這個函數在模塊調入內核(insmod)時被調用,它在內核中註冊一定的功能函數,告訴內核可以做這些事情。
static void __exit pkbd_exit(void)這個函數把pkbd_init()在內核中註冊的功能函數完全卸載掉,如果沒有完全卸載,在此模塊下次調入時,將因為有重名的函數而導致調入失敗。
    然後在在源代碼文件末尾使用下面的語句:
    module_init(pkbd_init);
    module_exit(pkbd_exit);
    這樣做的好處就是每個模塊都可以有自己的初始化和卸載函數的函數名,多個模塊在調試時不會有函數名重複的問題。
    Pcmcia介面的鍵盤驅動程序中,由於採用了Input機制,中間的很多函數模塊由其提供的介面功能完成了。因為鍵盤有個按鍵去抖動的中斷延遲執行過程,需要比較長的時間,實時性要求不高的程序,正好可以使用內核中提供的task queue、tasklet、kernel timer等機制來編寫。現以kernel timer來說明,它是一個雙向鏈表,成員結構定義如下(定義在/linux/timer.h);
struct timer_list{
struct list_head list;
unsigned long expires;
unsigned long data;
void(*function)(unsigned long);
};
    其中:expires的單位是jiffies,表示此timer的expires的時間(是一個絕對時間,但系統的jiffies大於或等於expires時,function被調用);
    function是在此timer expire后被調用的函數;
    data是傳遞給function的參數。
     主要的kernel timer函數:
static inline void init_timer(struct timer_list *timer);
    在使用一個kernel timer前,先調用此函數初始化,一般在pkbd_init()中進行。
extern void add_timer(struct timer_list *timer);
    把一個kernel timer加入到kernel中,同時激活。
extern int del_timer(struct timer_list *timer);
刪除一個kernel timer。必須在pkbd_exit()中釋放前面定義的kernel timer。

6.Input機制編程原理
    Input驅動的核心是input.o模塊,它必需在其他input模塊之前載入,在這兩組模塊之間起通信橋樑的作用。載入的驅動模塊服務於硬體,對input.o模塊產生觸發事件(如按鍵,滑鼠移動),然後從input.o獲得事件並通過各種介面傳遞出去,象按鍵就傳遞給了內核,滑鼠移動就通過模擬的PS/2介面傳遞給GPM等等。
    如帶USB滑鼠和USB鍵盤的通用配置,必須在內核編譯選項中加入下面這些模塊:
input.o
mousedev.o
keybdev.o
usbcore.o
usb-[uo]hci.o
hid.o
    Input機制鍵盤設備驅動編程的主要函數有:
input register_device(&button_dev);input設備結構註冊的調用函數
input_report_key(struct input_dev *dev,int code,int value);EV_KEY是最簡單的事件,主要針對於鍵和按鈕,定義了從0到KEY_MAX的鍵值(可以參見文件linux/input.h),value是個真實值,任何非零值表示鍵被按下,零值表示鍵釋放掉,但只有在value的值與上次不同時輸入的鍵值才激發鍵盤事件。
    除EV_KEY時間之外,還有其他幾類基本事件類型:如EV_REL和EV_ABS它們主要應用在由設備產生的相對和絕對值,如滑鼠的移動就是一個相對值。
    為了更清楚的說明Input機制編程,下面是個最簡單的示常式序,設備只有一個按鈕,對應的I/O口為BUTTON_PORT,當按鈕被按下或者釋放掉,就產生BUTTON_IRQ中斷事件。
    static void button_interrupt(int irq,void *dummy,struct pt_regs *fp)
{input_report_key(&button_dev,BTN_1,inb(BUTTON_PORT)&1);
}
static int __init button_init(void)
{
if(request_irq(BUTTON_IRQ,button_interrupt,0,"button",NULL)){
printk(KERN_ERR"button.c:Can't allocate irq%d ",button_irq);
return -EBUSY;
}
button_dev.evbit[0]=BIT(EV_KEY);
button_dev.keybit[LONG(BTN_0)] =BIT(BTN_0);
input_register_device(&button_dev);
}
static void __exit button_exit(void){
input_unregister_device(&button_dev);
free_irq(BUTTON_IRQ,button_interrupt);
}
module_init(button_init);
module_exit(button_exit);

7.Pcmcia介面的鍵盤驅動實現
    在Pcmcia介面的鍵盤驅動程序中,主要的過程就是在初始化模塊中對硬體相關寄存器的初始化,申請中斷,初始化首先要得到IMMAP寄存器的地址,然後初始化Pcmcia介面寄存器:
immap=(immap_t *)(mfspr(IMMR)&0xFFFF0000);
immap->im_pcmcia.pcmc_pscr = 0;
immap->im_pcmcia.pcmc_per |=0x0000fe00;
immap->im_pcmcia.pcmc_pgcrb = 1 <<19;
    設定鍵盤事件,定義鍵值:
set_bit(EV_KEY,pcmkbd_dev.evbit)
set_bit(KEY_1,pcmkbd_dev.keybit);
    這是定義數字鍵“1”,這樣就可以定義你所需要的鍵了。接下來申請中斷、初始化tasklet和內核定時器、註冊Input鍵盤事件等。
    在程序中,底半部任務隊列處理程序pcmcia_do_tasklet啟動名為pcmcia_timer的內核定時器,這裡利用了Linux提供的計時機制jiffies,jiffies的解析度是10毫秒,在內核中定義為HZ(1秒),這裡設為100毫秒后,pcmcia_timer到期,內核執行pcmcia_timer的處理函數pcmcia_timer_timed_out。在處理函數中主要進行行列掃描。將確定的按鍵鍵值作為input機制提供的函數input_report_key(&pcmkbd_dev,key_value[h][1],!u)的key_value的參數傳遞給內核就可以了。
    同時要在static void __exit pcmkbd_exit(void)模塊中刪除掉內核定時器、I/O埠和申請的中斷。

8 結束語
    嵌入式Linux應用將會越來越廣泛,擁有廣闊的市場前景。作為人機交互的鍵盤功能的實現也是非常重要的,本文利用Input機制原理和內核設備驅動的實現,通過Pcmcia介面實現了鍵盤功能,相信這個方案在嵌入式產品的開發中也很新穎,這種方案必將得到越來越多的應用。


[admin via 研發互助社區 ] 嵌入式Linux下基於PCMCIA介面的鍵盤驅動的實現已經有1874次圍觀

http://cocdig.com/docs/show-post-42132.html