電子工程網(wǎng)

標題: RK3568外部IO中斷示例 [打印本頁(yè)]

作者: 武漢萬(wàn)象奧科    時(shí)間: 2023-11-3 14:22
標題: RK3568外部IO中斷示例
本篇文章以萬(wàn)象奧科HD-RK3568-IOT評估板中GPIO30為例,介紹Linux內核中斷的注冊方法,使用中斷的方式檢測GPIO30是否出現上升沿信號。中斷在linux、設備驅動(dòng)開(kāi)發(fā)里使用的都非常多,可以更加實(shí)時(shí)的檢測GPIO30的狀態(tài)。
Linux內核提供了中斷的注冊接口:
頭文件                        include\linux\interrupt.h
定義文件                    include\linux\interrupt.h
函數原型                    int request_irq(unsigned int irq,  /* 做實(shí)參傳遞給中斷服務(wù)函數第1個(gè)參數 */
                                            Irq_handler_t handler,  /* 中斷服務(wù)函數指針 */
                                            unsigned long flags,
                                            const char *name,
void *dev_id);            /* 做實(shí)參傳遞給中斷服務(wù)函數第2個(gè)參數 */  
函數功能:             向內核注冊一個(gè)中斷服務(wù)函數;
當發(fā)生中斷號為irq的中斷時(shí),會(huì )執行handler指針函數。

函數參數:            
irq:    中斷編號(每個(gè)中斷有唯一的編號)。
handler:     中斷服務(wù)函數指針。
                  原型 typedef irqreturn_t(*irq_handler_t)(int, void *)。
flag:           中斷的標志,用來(lái)描述本中斷的基本特征的。
                  有固定的值,由中斷源的特征決定;
                  比如外中斷有:   上升沿,下降沿觸發(fā)中斷這類(lèi)標志。
name:        中斷名字,注冊后會(huì )出現cat /proc/interrupts
dev_id:      這個(gè)參數是傳遞給中斷服務(wù)函數。
                  對共享中斷來(lái)說(shuō),這個(gè)參數一定有要;
                  當注銷(xiāo)共享中斷中的其中一個(gè)時(shí),用這個(gè)標識要注銷(xiāo)哪一個(gè)。
                  對于有唯一入口的中斷,可以傳遞NULL;
                           但是一般來(lái)說(shuō)都會(huì )傳遞一個(gè)有意義指針,在中斷程序中使用,以方便編程。
         返回值      0       標識成功
         -EINVAL            (無(wú)效參數22) 表示中斷號無(wú)效。
         -EBUSY             (設備或者資源忙16) 表示中斷已經(jīng)被占用。
2)    注銷(xiāo)中斷
void  free_irq(unsigned int irq, void *dev_id)
irq:    要注銷(xiāo)的中斷號
dev_id:      其實(shí)就是注冊時(shí)需要使用的dev參數,在共享中斷必不可少,不能傳遞NULL。
注意:為防止在注銷(xiāo)時(shí)同時(shí)發(fā)生中斷,調用時(shí)候,先禁掉中斷。
3中斷開(kāi)啟與關(guān)閉
       禁止中斷:
void disable_irq_nosync(unsigned int irq);
void disable_irq(unsigned int irq);
參數: irq,要禁止的中斷對應的編號。
注意:在中斷服務(wù)程序中不能使用disable_irq這個(gè)函數,否則內核崩潰,可以使用disable_irq_nosync,
disable_irq: 函數調用后,函數不會(huì )馬上返回,而等待中斷程序執行完成才返回,在中斷調用會(huì )導致死鎖。
使能中斷:
         void enable_irq(unsigned int irq);
       參數: irq, 要使能的中斷對應的編號。
4)    獲取irq中斷號
         Int gpio_to_irq(unsigned int irq);
       參數: irq,要使能的中斷對應的編號
圖 2.1 GPIO0_D6
         GPIO0_D6=0*32+(4-1)-8+6=30
#include
#include
#include
#include
#include

#define GPIO_PIN 30  // 替換為你的GPIO引腳

static unsigned int irq_number;

// GPIO中斷處理函數
static irqreturn_t gpio_irq_handler(int irq, void *dev_id) {
    printk("GPIO中斷觸發(fā)!\n");
    return IRQ_HANDLED;
}
static int __init mymodule_init(void) {
    int ret;
    // 請求GPIO
    ret = gpio_request(GPIO_PIN, "my_gpio");
    if (ret) {
        printk("無(wú)法請求GPIO %d\n", GPIO_PIN);
        return ret;
    }

    // 配置GPIO引腳為輸入
    ret = gpio_direction_input(GPIO_PIN);
    if (ret) {
        printk("無(wú)法配置GPIO %d 為輸入\n", GPIO_PIN);
        gpio_free(GPIO_PIN);
        return ret;
    }

    // 請求GPIO中斷
    irq_number = gpio_to_irq(GPIO_PIN);           
ret = request_irq(irq_number, gpio_irq_handler, IRQF_TRIGGER_RISING, "my_gpio_irq", NULL);
/* IRQF_TRIGGER_RISING  上升沿有效  */
    if (ret) {      
        printk("無(wú)法請求GPIO中斷 %d\n", irq_number);
        gpio_free(GPIO_PIN);
        return ret;
    }
    printk("模塊加載成功\n");
    return 0;
}
static void __exit mymodule_exit(void) {
    // 釋放GPIO中斷
    free_irq(irq_number, NULL);
         
    // 釋放GPIO
    gpio_free(GPIO_PIN);

    printk("模塊卸載成功\n");
}

module_init(mymodule_init);
module_exit(mymodule_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zou");
MODULE_DESCRIPTION("Sample GPIO and Timer Interrupt Kernel Module");
將驅動(dòng)編譯成模塊,insmod加載模塊后。 由于驅動(dòng)檢測GPIO0_D6上升沿有效,當給該引腳提供高電平時(shí),會(huì )觸發(fā)中斷執行中斷處理函數。
圖3.1 觸發(fā)IO中斷






歡迎光臨 電子工程網(wǎng) (http://selenalain.com/) Powered by Discuz! X3.4
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页