基於OMAPL138的字符驅動_GPIO驅動AD9833(三)之中斷申請IRQ

0. 導語

學習進入到了下一個階段,仍是以AD9833爲例,此次學習是向設備申請中斷,實現觸發,在將來不少場景,好比作用戶級的SPI傳輸完畢數據以後,怎麼知道從設備要發數據呢,則須要一個IO信號通知主設備來讀從設備的數據,那麼就須要一個外部的IO中斷信號,因此呢,對於中斷的處理十分重要,本demo實現這樣的一個功能增長一個GPIO口,這個GPIO口接的是一個按鍵,經過觸發信號,進入中斷服務函數,在中斷服務函數內改變AD9833的波形。以此達到學習實驗目的。html

以前的代碼都是同樣的,在這裏儘可能剝離AD9833驅動和Linux的代碼模板,只寫中斷相關相關程序。linux

效果演示視頻: https://v.youku.com/v_show/id...ios

1. 前篇導讀:

  1. 基於OMAPL138的字符驅動_GPIO驅動AD9833(一)之ioctl
  2. 基於OMAPL138的Linux字符驅動_GPIO驅動AD9833(二)之cdev與read、write
  3. Linux GPIO鍵盤驅動開發記錄_OMAPL138

原理圖:app

2. 申請中斷準備

  • 首先須要兩個頭文件:
  • #include <linux/interrupt.h>
  • #include <linux/irq.h>
  • IO口配置準備

在這次使用中斷中,主要用的是GPIO口,咱們使用電平跳變使之進入到中斷處理程序中,因此做爲IO口,須要配置IO口的方向爲輸入方向。個人OMAPL138中給的IO口操做使用GPIO_TO_PIN這個宏函數進行,在IO口操做上每一個平臺都會給定本身的尋IO口的方法,而後使用linux通用gpio_direction_output進行設定該GPIO口爲輸入方向,如上面的原理圖,本demo的驅動使用的GPIO6[1],因此as follow:gpio_direction_output( GPIO_TO_PIN(6, 1) , 0 );函數

  • 硬件中斷號IRQ

我參考了不少文獻,也找了不少書籍,對於硬件中斷號碼從哪裏獲得一筆帶過,也沒有具體說明,不過,通過一下午的努力,我找到了查找中斷號碼的方法。使用gpio_to_irq這個函數方法能夠獲得irq。我以前找到手冊,看到了手冊裏面說GPIO6 BANK的IRQ爲48號,我嘗試加載到內核裏面,每次初始化的時候都告訴我中斷申請失敗,這個號看來不是datasheet給定的48號,在Linux內核裏面對於硬件IRQ又進行了從新映射。學習

  • 中斷事件

在內核中斷申請的時候,須要指定中斷事件是什麼,邊沿信號,高電平觸發,低電平觸發,在irq.h裏面定義了:spa

IRQ_TYPE_NONE        = 0x00000000,
    IRQ_TYPE_EDGE_RISING    = 0x00000001,
    IRQ_TYPE_EDGE_FALLING    = 0x00000002,
    IRQ_TYPE_EDGE_BOTH    = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING),
    IRQ_TYPE_LEVEL_HIGH    = 0x00000004,
    IRQ_TYPE_LEVEL_LOW    = 0x00000008,
    IRQ_TYPE_LEVEL_MASK    = (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH),
    IRQ_TYPE_SENSE_MASK    = 0x0000000f

咱們須要指定這個事件。.net

  • 中斷的名字

這個使用#cat /proc/interrupts 查看當前內核中斷資源的時候就能夠看到你指定註冊的名字。3d

  • 中斷服務程序

這個咱們本身定一個函數就能夠,而後一下子使用中斷申請的時候將數據傳輸進去就好。咱們在中斷服務函數裏面進行按鍵進行波形切換:code

static int key_count = 0;
static irqreturn_t    ad9833_press_intHandle( int irq, void *dev_id )
{
    printk( DRV_NAME "\t press trigger!\n" );
    if( key_count == 0 )  {
        ad9833->set_wave_type( ad9833, SIN );
        printk( DRV_NAME "\tSet wave is SIN.\n" );
    }else if( key_count == 2 ) {
        ad9833->set_wave_type( ad9833, TRI );
        printk( DRV_NAME "\tSet wave is TRI.\n" );
    }else if( key_count == 4 ) {
        ad9833->set_wave_type( ad9833, SQU );
        printk( DRV_NAME "\tSet wave is SQU.\n" );
    }
    key_count ++;
    if( key_count >= 5 )
        key_count = 0;

    return    IRQ_RETVAL( IRQ_HANDLED );
}

3. 申請中斷準備

使用request_irq函數就好,咱們在初始化函數裏面,申請irq。在申請irq前,爲了更好的管理中斷函數,咱們定義了一個結構體,專門進行irq配置。

struct gpio_irq_desc {

    int irq;
    unsigned long flags;
    char *name;

} press_dev_desc = {

        0,
        IRQ_TYPE_EDGE_FALLING,
        "sw6_push_button"

};

第一個是irq,咱們在向內核申請中斷的時候會使用gpio_to_irq進行irq的賦值,flags就是中斷事件的觸發條件,這裏是降低邊沿觸發,最後一個name就是上面註冊號中斷分配的名字,初始化程序以下:

/*
     * interrupt apply
     * */
    press_dev_desc.irq =  gpio_to_irq(ad9833_gpios[3]);
    ret =    request_irq( press_dev_desc.irq , &ad9833_press_intHandle, press_dev_desc.flags, press_dev_desc.name, (void*)0 );
    if( ret ) {
        printk( DRV_NAME "\terror %d: IRQ = %d number failed!\n",ret,gpio_to_irq(ad9833_gpios[3]) );
        ret = -EBUSY;
        unregister_chrdev_region( devno,1 );
        for( i = 0; i < ARRAY_SIZE(ad9833_gpios); i++)
            gpio_free( ad9833_gpios[i] );
        kfree(ad9833);
        return ret;
    }
    printk( DRV_NAME "\tiqr apply ok!!\n" );

到此咱們就完成了中斷配置。

4. 中斷釋放

使用freqq_irq進行釋放。這個函數應該放在exit驅動的函數裏面。
free_irq( press_dev_desc.irq, (void*)0 );

源代碼下載

連接: https://pan.baidu.com/s/1JgPg... 密碼: 5x84

參考文獻

[1] 創龍電子科技, [OMAPL138的GPIO輸出輸入
](https://wenku.baidu.com/view/... 百度文庫, 2014年5月8日

[2] wh_19910525, [Linux的 標準GPIO及中斷API函數
](https://blog.csdn.net/wh_1991... CSDN博客, 2013年12月25日

[3] wangcong02345, [Linux內核---44.關於中斷號與中斷引腳
](https://blog.csdn.net/wangcon... CSDN博客, 2016年7月9日

[4] GreenHand#, [Linux設備驅動中斷機制
](https://www.cnblogs.com/chen-... CNBLOGS, 2016年12月27日

相關文章
相關標籤/搜索