嵌入式內核及驅動開發之學習筆記(六) 驅動層中斷實現
由于中斷信號的突發性,CPU要捕獲中斷信號,有兩種方式。一是不斷輪詢是否有中斷發生,這樣有點傻;二是通過中斷機制,過程如下:
中斷源 ---> 中斷信號??--->? 中斷控制器 --->? CPU
中斷源有很多,CPU拿到中斷信號,如何區分是哪一個中斷源產生?那么一定有一個序列,標識不同的中斷源發出的信號,這就是中斷號了。
在ARM裸機開發中,使用中斷前需要進行不少配置,比較繁瑣。而從內核的角度,我們只要明確兩個目標
中斷號
中斷的處理方法
實驗:在驅動中添加中斷機制,按鍵觸發外部中斷,中斷產生后,驅動打印中斷信息。
步驟
定義中斷號
在通過原理圖,芯片手冊查詢,從硬件連接最終定位到中斷號
通過源碼,系統設備樹描述中
每一個設備的節點都要有一個compatible屬性?,用來查找節點(也可以通過節點名或節點路徑查找指定節點);interrupt-parent表示結點繼承至gic。
root@linux:~/linux-3.14-fs4412# vim arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
gpx1: gpx1 {
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
interrupt-parent = <&gic>;
interrupts = <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
<0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
#interrupt-cells = <2>;
};
手動定義設備樹節點,參考上面的系統描述和硬件設備號。定義如下
root@linux:~/linux-3.14-fs4412# vim arch/arm/boot/dts/exynos4412-fs4412.dts
key_int_node{
compatible = "test_key";
interrupt-parent = <&gpx1>;
interrupts = <2 4>;
};
重新編譯設備樹,并更新tftp根目錄下的設備樹文件
make dtbs
cp -raf arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot/
編寫驅動代碼
get_irqno_from_node函數通過設備樹的路徑到設備結點的中斷號;然后request_irq申請中斷,并設置觸發方式是雙邊沿觸發,key_irq_handler指定為中斷處理函數;在key_irq_handler中只有一條打印信息,當中斷產生,觸發這條函數,打印信息;模塊卸載時,通過free_irq釋放掉之前申請的中斷資源。
//key_drv.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
irqreturn_t key_irq_handler(int irqno, void *devid);
static int irqno;
int get_irqno_from_node(void)
{
//從設備樹路徑,查找節點
struct device_node *np = of_find_node_by_path("/key_int_node");
if(np){
printk("find node ok\n");
}else{
printk("find node failed\n");
}
int irqno = irq_of_parse_and_map(np, 0);
printk("irqno = %d\n", irqno);
return irqno;
}
static int __init key_drv_init(void)
{
int ret;
//拿到中斷號
irqno = get_irqno_from_node();
//申請中斷資源
ret = request_irq(irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
"key3_eint10", NULL);
if(ret != 0)
{
printk("request_irq error\n");
return ret;
}
return 0;
}
static void __exit key_drv_exit(void)
{
//釋放中斷資源
free_irq(irqno, NULL);
}
irqreturn_t key_irq_handler(int irqno, void *devid)
{
printk("-------%s-------------\n", __FUNCTION__);
return IRQ_HANDLED;
}
module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");
Makefile文件
ROOTFS_DIR = /nfs/rootfs
ifeq ($(KERNELRELEASE), )
KERNEL_DIR = /mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412
CUR_DIR = $(shell pwd)
all :
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
clean :
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
install:
cp -raf *.ko $(ROOTFS_DIR)/drv_module
else
obj-m += key_drv.o
endif
編譯
Ubuntu環境編譯,目標文件輸出到nfs目錄,nfs共享給開發板執行。
root@linux:/mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412/drivers/mydrivers/chr_drv# make
root@linux:/mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412/drivers/mydrivers/chr_drv# make install
實驗結果
按下按鍵(1->0),觸發一次中斷。松下按鍵(0->1),又觸發一次中斷。
嵌入式
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。