 Linux內核驅動之gpio子系統的使用
							時間:2018-09-27      來(lai)源:未知
							Linux內核驅動之gpio子系統的使用
							時間:2018-09-27      來(lai)源:未知 
							一 概述
linux內核中gpio是簡單,常用的(de)(de)(de)資源(和 interrupt ,dma,timer一樣)驅(qu)動程序,應用程序都能夠(gou)(gou)通(tong)過相應的(de)(de)(de)接(jie)口使(shi)用gpio,gpio使(shi)用0~MAX_INT之間的(de)(de)(de)整數(shu)標識,不能使(shi)用負數(shu),gpio與硬件體系密(mi)切相關的(de)(de)(de),不過linux有(you)一個框架處理(li)gpio,能夠(gou)(gou)使(shi)用統一的(de)(de)(de)接(jie)口來(lai)操作(zuo)gpio.在講gpio核心(gpiolib.c)之前先來(lai)看(kan)看(kan)gpio是怎么使(shi)用的(de)(de)(de)
本文引用地址://fsbing.cn/emb/Column/7549.html
二 內核中gpio的使用
1 測試(shi)gpio端口是否合法
int gpio_is_valid(int number);
2 申請某個gpio端(duan)口當然(ran)在申請之前必須配置該gpio端(duan)口的pinmux,否則會(hui)導致后面的操(cao)作失(shi)敗或者(zhe)無效
int gpio_request(unsigned gpio, const char *label)
3 標(biao)記gpio的使用方向(xiang)包括輸入還(huan)是輸出
/*成(cheng)功返回(hui)零(ling)失敗返回(hui)負的錯(cuo)誤值*/
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
4 獲得gpio引腳的值和設置gpio引腳的值(對于輸出)
int gpio_get_value(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);
5 gpio當作中斷口(kou)使用
int gpio_to_irq(unsigned gpio);
返回的值即中斷編號可(ke)以傳給request_irq()和free_irq()
內核通過調用(yong)該函(han)數將gpio端口轉換(huan)為(wei)中斷,在用(yong)戶空間也有類似方法(fa)
6 導(dao)出gpio端(duan)口到用戶(hu)空間(jian)
int gpio_export(unsigned gpio, bool direction_may_change);
內核可以(yi)(yi)對已(yi)經被gpio_request()申請的gpio端口的導(dao)出(chu)進行明確的管理(li),參數(shu)direction_may_change表示用戶程序是否允(yun)許修改gpio的方向(xiang),假如可以(yi)(yi)則參數(shu)direction_may_change為(wei)真
/* 撤銷GPIO的導出 */
void gpio_unexport();
三 用戶空間gpio的調用
用(yong)戶空間訪(fang)問(wen)gpio,即通過sysfs接(jie)口訪(fang)問(wen)gpio,下面是/sys/class/gpio目錄(lu)下的三(san)種文(wen)件(jian):
--export/unexport文件
--gpioN指代具體(ti)的gpio引腳
--gpio_chipN指代gpio控制器
必須知道以上接口沒有標準device文件和它們的鏈接。
(1) export/unexport文(wen)件接口:
/sys/class/gpio/export,該(gai)接口只能寫不能讀
用戶程序(xu)通過寫入gpio的(de)編號來向內核申(shen)請將某個(ge)gpio的(de)控(kong)制權導出到用戶空間
當(dang)然前提是沒有內核代碼(ma)申請這個gpio端(duan)口
比如 echo 19 > export
上述操作會為(wei)19號(hao)gpio創建一個節點gpio19,此時/sys/class/gpio下邊生成一個
gpio19的目錄
/sys/class/gpio/unexport和導(dao)出(chu)的(de)效果(guo)相(xiang)反(fan)。
比如 echo 19 > unexport
上述(shu)操作將會移除(chu)gpio19這個節(jie)點。
(2) /sys/class/gpio/gpioN
指代某個具體(ti)的gpio端口,里邊有如(ru)下屬性文件
direction 表(biao)示gpio端(duan)口的方向(xiang),讀(du)取(qu)結果(guo)是in或(huo)out。該(gai)文(wen)件也可以(yi)(yi)寫(xie),寫(xie)入out 時該(gai)gpio設為輸出同時電平默認為低。寫(xie)入low或(huo)high則(ze)不(bu)僅(jin)可以(yi)(yi)設置(zhi)(zhi)為輸出還可以(yi)(yi)設置(zhi)(zhi)輸出的電平,當然(ran)如(ru)果(guo)內(nei)(nei)核(he)(he)不(bu)支(zhi)持或(huo)者內(nei)(nei)核(he)(he)代(dai)碼(ma)不(bu)愿意(yi)(yi),將不(bu)會存在這個屬性,比(bi)如(ru)內(nei)(nei)核(he)(he)調用了gpio_export(N,0)表(biao)示內(nei)(nei)核(he)(he)不(bu)愿意(yi)(yi)修改(gai)gpio端(duan)口方向(xiang)屬性
value 表示(shi)gpio引腳(jiao)的電(dian)(dian)平(ping)(ping),0(低電(dian)(dian)平(ping)(ping))1(高(gao)電(dian)(dian)平(ping)(ping)),如(ru)果gpio被配(pei)置為輸出(chu),這個(ge)值是(shi)可寫的,記住(zhu)任何非零的值都(dou)將輸出(chu)高(gao)電(dian)(dian)平(ping)(ping), 如(ru)果某個(ge)引腳(jiao)能并且已經被配(pei)置為中斷,則可以(yi)調用poll(2)函數(shu)監聽該中斷,中斷觸發后poll(2)函數(shu)就會返回。
edge 表示中斷的(de)觸發方式,edge文(wen)件有如(ru)下四(si)個值(zhi):none, rising, falling,both。
none表示引(yin)腳為輸(shu)入,不是中斷(duan)引(yin)腳
rising表示引(yin)腳為中斷輸入(ru),上升沿觸(chu)發
falling表示(shi)引(yin)腳為(wei)中斷輸入(ru),下降(jiang)沿觸發
both表(biao)示引腳為中斷(duan)輸入,邊(bian)沿觸發(fa)
這(zhe)個文件節點只有(you)在引腳被配(pei)置(zhi)為(wei)輸入引腳的時(shi)(shi)候才(cai)存在。 當值是none時(shi)(shi)可以通過如下方(fang)法(fa)將(jiang)變為(wei)中斷引腳
echo "both" > edge;對于是(shi)both,falling還(huan)是(shi)rising依(yi)賴具(ju)體硬(ying)件的(de)中斷(duan)的(de)觸發(fa)方式。此方法即用戶(hu)態gpio轉換為中斷(duan)引腳的(de)方式
active_low 不怎(zen)么明白,也木(mu)有用過
(3)/sys/class/gpio/gpiochipN
gpiochipN表示的(de)就(jiu)是一(yi)(yi)個gpio_chip,用(yong)來管理和控制一(yi)(yi)組gpio端口(kou)的(de)控制器,該(gai)目錄下存在一(yi)(yi)下屬性文件:
base 和N相(xiang)同,表示控制器管(guan)理的小的端口編號(hao)。
lable 診斷使(shi)用的標志(并不總是唯一(yi)的)
ngpio 表示(shi)控制器管理的gpio端口數量(端口范圍是(shi):N ~ N+ngpio-1)
四 用戶態使用gpio監聽中斷
首(shou)先需要將該(gai)gpio配(pei)置為(wei)中斷
echo "rising" > /sys/class/gpio/gpio12/edge
配(pei)置該gpio為(wei)上升沿(yan)觸發中(zhong)斷(duan)
以(yi)下(xia)是偽代碼
int gpio_fd;
struct pollfd fds[1];
system("echo falling > /sys/class/gpio/gpio12/edge");
//也可以使(shi)用上述代(dai)碼來配置gpio的中斷觸發方式
gpio_fd = open("/sys/class/gpio/gpio12/value",O_RDONLY);
if( gpio_fd == -1 )
err_print("gpio open");
fds[0].fd = gpio_fd;
fds[0].events = POLLPRI;
ret = lseek(gpio_fd,0,SEEK_SET);
if( ret == -1 )
err_print("lseek");
ret = read(gpio_fd,&value,1);
if( ret == -1 )
err_print("read");
while(1){
ret = poll(fds,1,-1);
if( ret == -1 )
err_print("poll");
if( fds[0].revents & POLLPRI){
ret = lseek(gpio_fd,0,SEEK_SET);
if( ret == -1 )
err_print("lseek");
ret = read(gpio_fd,&value,1);
if( ret == -1 )
err_print("read");
/*此時(shi)表示已經(jing)監聽(ting)到中斷觸發了(le),該干(gan)事了(le)*/
...............
}
}
記住(zhu)使(shi)用poll()函數,設置事件(jian)監聽類(lei)型為POLLPRI和POLLERR,在poll()返(fan)回后,必須(xu)使(shi)用lseek()移動到文件(jian)開頭并讀取新(xin)的值必須(xu)這樣做,否則poll函數會總是返(fan)回。

