搜尋
首頁運維linux運維linux 中斷號碼是什麼意思

linux 中斷號碼是什麼意思

Mar 20, 2023 am 10:09 AM
linux中斷號

linux中斷號是系統分配給每個中斷來源的代號,以便識別和處理;在採用向量中斷方式的中斷系統中,CPU必須透過它才可以找到中斷服務程式的入口位址,實現程序的轉移。

linux 中斷號碼是什麼意思

本教學操作環境:linux5.9.8系統、Dell G3電腦。

linux 中斷號碼是什麼意思?

中斷號與中斷程式設計:

#1、中斷號

  中斷號是系統指派給每個中斷來源的代號,以便識別和處理。在採用向量中斷方式的中斷系統中,CPU必須透過它才能找到中斷服務程序的入口位址,以實現程式的轉移。

  在ARM裸機中實作中斷需要設定:

 I/O口为中断模式,触发方式,I/O口中断使能
 设置GIC中断使能,分发配置,分发总使能,CPU外部中断接口使能,中断优先级

  在linux核心中實作中斷,只需要知道:

中断号是什么,怎么得到中断号
中断处理方法

 2、取得中斷號的方法:

#
/arm/boot/dts/exynos4412-fs4412.dts

  1)看原理圖,晶片手冊找到中斷來源對應的中斷號SPI Port  No

  

#   linux 中斷號碼是什麼意思

   2)進入裝置樹,在arch/arm/boot/dts /exynos4x12-pinctrl.dtsi

gpx1: gpx1 {
                    gpio-controller;
                    #gpio-cells = <2>;

                    interrupt-controller;  //中断控制器
                    interrupt-parent = <&gic>;  //继承于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>; //子继承的interrupts的长度
            };

  括號中的24、 25等對應於SPI Port No,以上是系統中已經定義好的節點

#在程式設計中,需要定義自己的節點,用來描述按鍵,開啟可編輯的裝置樹檔案:

arch/arm/boot/dts/exynos4412-fs4412.dts,進入檔案。

  3)定義節點,描述目前裝置用的中斷號

1 key_int_node{
2             compatible = "test_key";
3             interrupt-parent = ;  //继承于gpx1
4             interrupts = ;      //2表示第几个中断号,4表示触发方式为下降沿5         };               //interrupts里长度由父母的-cell决定

  再舉個栗子,設定k4 --- GPX3_2(XEINT26) 的節點,中斷號

1 key_int_node{
2              compatible = "test_key";
3              interrupt-parent = <&gpx3>;  //继承于gpx3
4              interrupts = <2 4>;      //2表示第2个中断号,4表示触发方式为下降沿
5          };

    中斷號的定位方法:

    看I/O引腳,GPX1_2,中斷號就是GPX1裡面的第2個

    更新設備樹檔案: cp  -raf arch/arm/boot/dts/exynos4412-fs4412.dtb   /tfboot/

2. :在根目錄的proc/device-tree/目錄下

 

  

 

3、實作中斷處理方法  在驅動程式中透過程式碼取得中斷號,並且申請中斷

  先看一下中斷相關的函數:

1 a,获取到中断号码:
 2     int get_irqno_from_node(void)
 3     {
 4         // 获取到设备树中的节点
 5         struct device_node *np = of_find_node_by_path("/key_int_node");
 6         if(np){
 7             printk("find node ok\n");
 8         }else{
 9             printk("find node failed\n");
10         }
11 
12         // 通过节点去获取到中断号码
13         int irqno = irq_of_parse_and_map(np, 0);
14         printk("irqno = %d\n", irqno);
15         
16         return irqno;
17     }
18 b,申请中断
19 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char * name, void * dev)
20     参数1: irq     设备对应的中断号
21     参数2: handler     中断的处理函数
22             typedef irqreturn_t (*irq_handler_t)(int, void *);
23     参数3:flags     触发方式
24             #define IRQF_TRIGGER_NONE    0x00000000  //内部控制器触发中断的时候的标志
25             #define IRQF_TRIGGER_RISING    0x00000001 //上升沿
26             #define IRQF_TRIGGER_FALLING    0x00000002 //下降沿
27             #define IRQF_TRIGGER_HIGH    0x00000004  // 高点平
28             #define IRQF_TRIGGER_LOW    0x00000008 //低电平触发
29     参数4:name     中断的描述,自定义,主要是给用户查看的
30             /proc/interrupts
31     参数5:dev     传递给参数2中函数指针的值
32     返回值: 正确为0,错误非0
33 
34 
35     参数2的赋值:即中断处理函数
36     irqreturn_t key_irq_handler(int irqno, void *devid)
37     {
38         return IRQ_HANDLED;
39     }
43     
44 c, 释放中断:
45         void free_irq(unsigned int irq, void *dev_id)
46         参数1: 设备对应的中断号
47         参数2:与request_irq中第5个参数保持一致

程式碼實作取得中斷號,並註冊中斷,按下按鍵引發中斷,列印訊息

1 #include <linux/init.h>
 2 #include <linux/module.h>
 3 #include <linux/fs.h>
 4 #include <linux/device.h>
 5 #include <asm/uaccess.h>
 6 #include <asm/io.h>
 7 #include <linux/slab.h>
 8 #include <linux/of.h>
 9 #include <linux/of_irq.h>
10 #include <linux/interrupt.h>
11 
12 int irqno;    //中断号
13 
14 
15 irqreturn_t key_irq_handler(int irqno, void *devid)
16 {
17     printk("----------%s---------",__FUNCTION__);
18     return IRQ_HANDLED;
19 }
20 
21 
22 //获取中断号
23 int get_irqno_from_node(void)
24 {
25     //获取设备树中的节点
26     struct device_node *np = of_find_node_by_path("/key_int_node");
27     if(np){
28         printk("find node success\n");
29     }else{
30         printk("find node failed\n");
31     }
32 
33     //通过节点去获取中断号
34     int irqno = irq_of_parse_and_map(np, 0);
35     printk("iqrno = %d",irqno);
36 
37     return irqno;
38 }
39 
40 
41 
42 static int __init key_drv_init(void)
43 {
44     //演示如何获取到中断号
45     int ret;
46     
47     irqno = get_irqno_from_node();
48 
49     ret = request_irq(irqno, key_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 
50         "key3_eint10", NULL);
51     if(ret != 0)
52     {
53         printk("request_irq error\n");
54         return ret;
55     }
56     
57     return 0;
58 }
59 
60 static void __exit key_drv_exit(void)
61 {
62     free_irq(irqno, NULL);  //free_irq与request_irq的最后一个参数一致
63 }
64 
65 
66 
67 module_init(key_drv_init);
68 module_exit(key_drv_exit);
69 
70 MODULE_LICENSE("GPL");
key_drv.c

key_drv.c

測試效果:

##按鍵按下,列印訊息,但出現了按鍵抖動 

##cat /proc/interrupt

 

  

#4、 中斷程式設計--- 字元裝置驅動框架

// 1,设定一个全局的设备对象
key_dev = kzalloc(sizeof(struct key_desc),  GFP_KERNEL);
// 2,申请主设备号
key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);
// 3,创建设备节点文件
key_dev->cls = class_create(THIS_MODULE, "key_cls");
key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->dev_major,0), NULL, "key0");
// 4,硬件初始化:
        a.地址映射
        b.中断申请
  5、驅動實作將硬體所產生的資料傳遞給使用者

  1)硬體如何取得資料

key: 按下和抬起: 1/0读取key对应的gpio的状态,可以判断按下还是抬起
    
读取key对应gpio的寄存器--数据寄存器 
//读取数据寄存器int value = readl(key_dev->reg_base + 4) & (1<<2);
   2)驅動傳遞資料給使用者

在中断处理中填充数据:
     key_dev->event.code = KEY_ENTER;
     key_dev->event.value = 0;
在xxx_read中奖数据传递给用户
     ret = copy_to_user(buf, &key_dev->event,  count);

#  3 )使用者取得資料

    while(1)
    {
        read(fd, &event, sizeof(struct key_event));        if(event.code == KEY_ENTER)
        {            if(event.value)
            {
                printf("APP__ key enter pressed\n");
            }else{
                printf("APP__ key enter up\n");
            }
        }
    }
  

#6、範例:

##

1 #include <linux/init.h>
  2 #include <linux/module.h>
  3 #include <linux/of.h>
  4 #include <linux/of_irq.h>
  5 #include <linux/interrupt.h>
  6 #include <linux/slab.h>
  7 #include <linux/fs.h>
  8 #include <linux/device.h>
  9 #include <linux/kdev_t.h>
 10 #include <linux/err.h>
 11 #include <linux/device.h>
 12 #include <asm/io.h>
 13 #include <asm/uaccess.h>
 14 
 15 
 16 #define GPXCON_REG 0X11000C20   //不可以从数据寄存器开始映射,要配置寄存器
 17 #define KEY_ENTER  28
 18 
 19 //0、设计一个描述按键的数据的对象
 20 struct key_event{
 21     int code;    //按键类型:home,esc,enter
 22     int value;   //表状态,按下,松开
 23 };
 24 
 25 //1、设计一个全局对象——— 描述key的信息
 26 struct key_desc{
 27     unsigned int dev_major;
 28     int irqno;  //中断号
 29     struct class  *cls;
 30     struct device *dev;
 31     void *reg_base;
 32     struct key_event event;
 33 };
 34 
 35 struct key_desc *key_dev;
 36 
 37 
 38 irqreturn_t key_irq_handler(int irqno, void *devid)
 39 {
 40     printk("----------%s---------",__FUNCTION__);
 41 
 42     int value;
 43     //读取按键状态
 44     value = readl(key_dev->reg_base + 4) & (0x01<<2);
 45     
 46     if(value){
 47         printk("key3 up\n");
 48         key_dev->event.code  = KEY_ENTER;
 49         key_dev->event.value = 0;
 50     }else{
 51         printk("key3 down\n");
 52         key_dev->event.code  = KEY_ENTER;
 53         key_dev->event.value = 1;
 54     }
 55     return IRQ_HANDLED;
 56 }
 57 
 58 
 59 //获取中断号
 60 int get_irqno_from_node(void)
 61 {
 62     int irqno;
 63     //获取设备树中的节点
 64     struct device_node *np = of_find_node_by_path("/key_int_node");
 65     if(np){
 66         printk("find node success\n");
 67     }else{
 68         printk("find node failed\n");
 69     }
 70 
 71     //通过节点去获取中断号
 72     irqno = irq_of_parse_and_map(np, 0);
 73     printk("iqrno = %d",key_dev->irqno);
 74 
 75     return irqno;
 76 }
 77 
 78 ssize_t key_drv_read (struct file * filp, char __user * buf, size_t count, loff_t * fops)
 79 {
 80     //printk("----------%s---------",__FUNCTION__);
 81     int ret;
 82     ret = copy_to_user(buf, &key_dev->event, count);
 83     if(ret > 0)
 84     {
 85         printk("copy_to_user error\n");
 86         return -EFAULT;
 87     }
 88 
 89     //传递给用户数据后,将数据清除,否则APP每次读都是第一次的数据
 90     memset(&key_dev->event, 0, sizeof(key_dev->event));
 91     return count;
 92 }
 93 
 94 ssize_t key_drv_write (struct file *filp, const char __user * buf, size_t count, loff_t * fops)
 95 {
 96     printk("----------%s---------",__FUNCTION__);
 97     return 0;
 98 }
 99 
100 int key_drv_open (struct inode * inode, struct file *filp)
101 {
102     printk("----------%s---------",__FUNCTION__);
103     return 0;
104 }
105 
106 int key_drv_close (struct inode *inode, struct file *filp)
107 {
108     printk("----------%s---------",__FUNCTION__);
109     return 0;
110 }
111 
112 
113 const struct file_operations key_fops = {
114     .open    = key_drv_open,
115     .read    = key_drv_read,
116     .write   = key_drv_write,
117     .release = key_drv_close,
118 
119 };
120 
121 
122 
123 static int __init key_drv_init(void)
124 {
125     //演示如何获取到中断号
126     int ret;
127     
128     //1、设定全局设备对象并分配空间
129     key_dev = kzalloc(sizeof(struct key_desc), GFP_KERNEL);  //GFP_KERNEL表正常分配内存
130                           //kzalloc相比于kmalloc,不仅分配连续空间,还会将内存初始化清零
131 
132     //2、动态申请设备号
133     key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);
134 
135     //3、创建设备节点文件
136     key_dev->cls = class_create(THIS_MODULE, "key_cls");
137     key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->dev_major, 0), NULL, "key0");
138 
139     //4、硬件初始化 -- 地址映射或中断申请    
140     
141     key_dev->reg_base = ioremap(GPXCON_REG,8);
142 
143     key_dev->irqno = get_irqno_from_node();
144     
145     ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 
146         "key3_eint10", NULL);
147     if(ret != 0)
148     {
149         printk("request_irq error\n");
150         return ret;
151     }
152 
153     //a. 硬件如何获取数据
154     
155     
156     
157     return 0;
158 }
159 
160 static void __exit key_drv_exit(void)
161 {
162     iounmap(GPXCON_REG);
163     free_irq(key_dev->irqno, NULL);  //free_irq与request_irq的最后一个参数一致
164     device_destroy(key_dev->cls, MKDEV(key_dev->dev_major, 0));
165     class_destroy(key_dev->cls);
166     unregister_chrdev(key_dev->dev_major, "key_drv");
167     kfree(key_dev);
168 }
169 
170 
171 
172 module_init(key_drv_init);
173 module_exit(key_drv_exit);
174 
175 MODULE_LICENSE("GPL");
key_drv.c
key_drv .c
1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <sys/stat.h>
 7 #include <fcntl.h>
 8 
 9 
10 #define KEY_ENTER  28
11 
12 //0、设计一个描述按键的数据的对象
13 struct key_event{
14     int code;    //按键类型:home,esc,enter
15     int value;   //表状态,按下,松开
16 };
17 
18 
19 int main(int argc, char *argv[])
20 {
21     struct key_event event;
22     int fd;
23     fd = open("/dev/key0", O_RDWR);
24     if(fd < 0)
25     {
26         perror("open");
27         exit(1);
28     }
29 
30     while(1)
31     {
32         read(fd, &event, sizeof(struct key_event));
33 
34         if(event.code == KEY_ENTER)
35         {
36             if(event.value)
37             {
38                 printf("APP__ key enter down\n");
39             }else{
40 
41                 printf("APP__ key enter up\n");
42             }
43         }
44     }
45 
46     close(fd);
47 
48     return 0;
49 }
key_test.c

key_test.c
#
1 ROOTFS_DIR = /home/linux/source/rootfs#根文件系统路径
 2 
 3 APP_NAME = key_test
 4 MODULE_NAME = key_drv
 5 
 6 CROSS_COMPILE = /home/linux/toolchains/gcc-4.6.4/bin/arm-none-linux-gnueabi-
 7 CC = $(CROSS_COMPILE)gcc
 8 
 9 ifeq ($(KERNELRELEASE),)
10 
11 KERNEL_DIR = /home/linux/kernel/linux-3.14-fs4412          #编译过的内核源码的路径
12 CUR_DIR = $(shell pwd)     #当前路径
13 
14 all:
15     make -C $(KERNEL_DIR) M=$(CUR_DIR) modules  #把当前路径编成modules
16     $(CC) $(APP_NAME).c -o $(APP_NAME)
17     @#make -C 进入到内核路径
18     @#M 指定当前路径(模块位置)
19 
20 clean:
21     make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
22 
23 install:
24     sudo cp -raf *.ko $(APP_NAME) $(ROOTFS_DIR)/drv_module     #把当前的所有.ko文件考到根文件系统的drv_module目录
25 
26 else
27 
28 obj-m += $(MODULE_NAME).o    #指定内核要把哪个文件编译成ko
29 
30 endif
Makefile
Makefile

 執行使用者程序,按下按鍵可以看到資訊

 

#    退出使用者程序,按下按鍵,也會列印對應資訊。

 

   檢視裝置與中斷節點資訊:

   再看下CPU情況:

   可以看到key_test應用程式佔了很高的CPU,什麼原因呢?

在應用程式中,是透過while循環,一直read核心的訊息,當有按鍵中斷發生的時候,就會對key_event賦值,在while循環裡判斷,進而列印出來,這樣在使用者空間與核心空間一直來回切換,一直read會十分消耗CPU資源。

 解決思路:當有中斷發生時,才來呼叫read,沒有資料產生,跳出進程調度,進程休眠。

推薦學習:《linux影片教學

以上是linux 中斷號碼是什麼意思的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Linux的構建塊:關鍵組件解釋了Linux的構建塊:關鍵組件解釋了Apr 30, 2025 am 12:26 AM

Linux系統的核心組成部分包括內核、文件系統和用戶空間。 1.內核管理硬件資源並提供基本服務。 2.文件系統負責數據存儲和組織。 3.用戶空間運行用戶程序和服務。

使用維護模式:故障排除和修復Linux使用維護模式:故障排除和修復LinuxApr 29, 2025 am 12:28 AM

維護模式是Linux系統中通過單用戶模式或救援模式進入的特殊運行級別,用於系統維護和修復。 1.進入維護模式使用命令“sudosystemctlisolaterescue.target”。 2.在維護模式中,可以檢查並修復文件系統,使用命令“fsck/dev/sda1”。 3.高級用法包括重置root用戶密碼,需掛載文件系統為讀寫模式並編輯密碼文件。

Linux維護模式:了解目的Linux維護模式:了解目的Apr 28, 2025 am 12:01 AM

維護模式用於系統維護和修復,允許管理員在簡化環境中工作。 1.系統修復:修復損壞的文件系統和啟動加載器。 2.密碼重置:重置root用戶密碼。 3.軟件包管理:安裝、更新或刪除軟件包。通過修改GRUB配置或使用特定鍵進入維護模式,執行維護任務後可安全退出。

Linux操作:網絡和網絡配置Linux操作:網絡和網絡配置Apr 27, 2025 am 12:09 AM

Linux網絡配置可以通過以下步驟完成:1.配置網絡接口,使用ip命令臨時設置或編輯配置文件持久化設置。 2.設置靜態IP,適合需要固定IP的設備。 3.管理防火牆,使用iptables或firewalld工具來控製網絡流量。

Linux中的維護模式:系統管理員指南Linux中的維護模式:系統管理員指南Apr 26, 2025 am 12:20 AM

維護模式在Linux系統管理中扮演關鍵角色,幫助進行系統修復、升級和配置變更。 1.進入維護模式可以通過GRUB菜單選擇或使用命令“sudosystemctlisolaterescue.target”。 2.在維護模式下,可以執行文件系統修復和系統更新等操作。 3.高級用法包括重置root密碼等任務。 4.常見錯誤如無法進入維護模式或掛載文件系統,可通過檢查GRUB配置和使用fsck命令修復。

Linux中的維護模式:何時以及為什麼使用它Linux中的維護模式:何時以及為什麼使用它Apr 25, 2025 am 12:15 AM

使用Linux維護模式的時機和原因:1)系統啟動問題時,2)進行重大系統更新或升級時,3)執行文件系統維護時。維護模式提供安全、控制的環境,確保操作的安全性和效率,減少對用戶的影響,並增強系統的安全性。

Linux:基本命令和操作Linux:基本命令和操作Apr 24, 2025 am 12:20 AM

Linux中不可或缺的命令包括:1.ls:列出目錄內容;2.cd:改變工作目錄;3.mkdir:創建新目錄;4.rm:刪除文件或目錄;5.cp:複製文件或目錄;6.mv:移動或重命名文件或目錄。這些命令通過與內核交互執行操作,幫助用戶高效管理文件和系統。

Linux操作:管理文件,目錄和權限Linux操作:管理文件,目錄和權限Apr 23, 2025 am 12:19 AM

在Linux中,文件和目錄管理使用ls、cd、mkdir、rm、cp、mv命令,權限管理使用chmod、chown、chgrp命令。 1.文件和目錄管理命令如ls-l列出詳細信息,mkdir-p遞歸創建目錄。 2.權限管理命令如chmod755file設置文件權限,chownuserfile改變文件所有者,chgrpgroupfile改變文件所屬組。這些命令基於文件系統結構和用戶、組系統,通過系統調用和元數據實現操作和控制。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具