1. 程式人生 > >基於IMX6的GPIO驅動程式

基於IMX6的GPIO驅動程式

    Linux核心版本:linux-3.0.35
    開發板: IMX6S MY-IMX6-EK200
    編譯環境:Ubuntu12
    主要內容:IMX6S的IO驅動程式編寫(ioctl)
    實現功能:通過應用層程式控制底層IO的讀寫

一、驅動層
1、ioctl函式
    ioctl函式從應用層傳遞給驅動層不同的cmd引數,驅動層根據傳遞的cmd引數,使用switch語句判別,來進行不同的工作。
函式:static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
引數:a、file:檔案描述符;
          b、cmd:command引數,根據自己的設定的cmd引數,進行不同的工作;
          c、arg:應用層和驅動層資料的傳遞。
    因此要寫好一個ioctl的驅動程式,首先要學會如何正確設定cmd引數。
    在驅動程式裡, ioctl() 函式上傳送的變數 cmd 是應用程式用於區別裝置驅動程式請求處理內容的值。cmd除了可區別數字外,還包含有助於處理的幾種相應資訊。 cmd的大小為 32位,共分 4 個域:
          bit31~bit30 2位為 “區別讀寫” 區,作用是區分是讀取命令還是寫入命令。
          bit29~bit15 14位為 “資料大小” 區,表示 ioctl() 中的 arg 變數傳送的記憶體大小。
          bit20~bit08 8位為 “魔數”(也稱為”幻數”)區,這個值用以與其它裝置驅動程式的 ioctl 命令進行區別。
          bit07~bit00 8位為 “區別序號” 區,是區分命令的命令順序序號。
    要按照Linux核心的約定方法為驅動程式選擇ioctl編號,因為如果不按照這個約定進行編寫,就有可能因為cmd引數衝突問題不能正確呼叫ioctl函式。
2、為了合理使用ioctl函式,需要學習cmd引數的設定方法,檢視Linux原始碼可以看到一下內容。


    在include/asm/ioctl.h標頭檔案中,我們可以看到供我們使用的建立cmd引數的方法。_IOC(dir,type,nr,size)是封裝好的引數設定方法,在它的上一層,又封裝了_IOW()和_IOR()進行IO的寫和讀的cmd引數設定方法。程式碼截圖如下:
1
    再看一下/ioctl-number.txt檔案,在這個檔案裡列出了已經使用的幻數。
2
3
    從上面的圖中可以看出,幻數’x’都沒有使用,因此我們在設定cmd引數的時候,幻數的選擇可以用幻數’x’。
    因此,我們就可以定義自己的cmd引數。nr引數可以隨意設定,範圍是0~255。size引數也可以根據需求進行設定。我的cmd引數設定如下:
4

3、ioctl編寫例項。
    從下圖可以看到,當cmd引數為DS_CS1_W時,通過gpio_direction_output()設定IO的方向為輸出。通過__gpio_set_value()向底層寫入1或0,當寫入1時,IO輸出高電平,當寫入0時,IO輸出低電平;當cmd引數為DS_CS1_R時,通過gpio_direction_input()設定IO的方向為輸入。通過__gpio_get_value()讀取IO引腳狀態,並通過copy_to_user()將從底層讀取的狀態傳遞給應用層程式。其他引腳設定同理。
5
4、編譯驅動程式
    寫好驅動層程式,使用Makefile,進行編譯。編譯好的**.ko檔案拷貝到開發板,通過insmod指令進行載入即可。

二、應用層
1、應用層設定的cmd引數要和驅動層的cmd引數一致。
2、應用層的程式就好寫多了,可以自己進行任意封裝,可以使用如下的方式進行IO操作:
6
7
    注意:應用層的ioctl函式的cmd引數是傳遞給驅動層用來區分不同操作的。arg引數是驅動層和應用層交換的資料,例如當寫GPIO,arg=1時,應用層給驅動層傳遞1,驅動層控制GPIO為高電平;當讀GPIO時,應用層通過驅動層傳遞過來的arg引數的值來判別GPIO的高低電平。
3、使用linux-arm-gcc交叉編譯應用程式,將編譯好的可執行檔案拷貝到開發板即可執行。

三、測試
    驅動程式和應用測試程式均已測試通過,更為詳細的內容可檢視原始碼,原始碼下載地址:點選下載