• <code id="zjelh"></code>

          <source id="zjelh"><form id="zjelh"></form></source><acronym id="zjelh"><form id="zjelh"><blockquote id="zjelh"></blockquote></form></acronym>

          1. <acronym id="zjelh"><form id="zjelh"></form></acronym>

            <input id="zjelh"><rt id="zjelh"></rt></input>
            <var id="zjelh"><rt id="zjelh"></rt></var>
            <source id="zjelh"><form id="zjelh"><del id="zjelh"></del></form></source>

            當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > 中斷編程

            中斷編程 時間:2019-07-31      來源:濟南中心,馬老師

            中斷就是CPU正常運行期間,由于內、外部事件引起的CPU暫時停止正在運行的程序,去執行該內部事件或外部事件的引起的服務中去,服務執行完畢后再返回斷點處繼續執行的情形。

            中斷的意義

            極大提高CPU運行效率

            中斷服務程序

            中斷處理程序:在中斷發生時被調用的函數稱為中斷服務函數。

            中斷服務函數的原則:linux是多進程操作系統

                中斷不屬于任何一個進程,因此不能在中斷程序中休眠和調用schedule函數放棄CPU

                實現終端處理函數有一個原則,就是盡可能的處理并返回

            linux中斷頂部和中斷底部

            裸機中并沒有此概念,他們是什么?

            linux中斷頂部、底部概念

            為保證系統實時性,中斷服務程序必須足夠簡短,但實際應用中某些時候發生中斷時必須處理大量的事物,這時候如果都在中斷服務程序中完成,則會嚴重降低中斷的實時性,基于這個原因,linux系統提出了一個概念:把中斷服務程序分為兩部分-頂半部-底半部

            頂半部

            完成盡可能少的比較急的功能,它往往只是簡單的讀取寄存器的中斷狀態,并清除中斷標志后就進行“中斷標記”(也就是把底半部處理程序掛到設備的底半部執行隊列中)的工作。

            特點:響應速度快

            底半部:

            中斷處理的大部分工作都在底半部,它幾乎做了中斷處理程序的所有事情。

            特點:處理相對來說不是非常緊急的事件

            底半部機制主要有:tasklet、工作隊列和軟中斷

            裸機中斷設計形式

            第一種寫法:把發生中斷所需要做的所有的事情全部寫到中斷服務函數體中

            void isr()

            {

              //中斷程序

            }

            第二種寫法:中斷只記錄,標志,要做的事情在主循環中編寫。

            int flag=0;

            void main(void)

            {

              while(1)

              {

                if(flag)

                {

                 flag=0;

                  //中斷需要做的事情

                }

              }

            }

            void isr()

            {

            //只做登記

              flag=1;

            }

            第二種寫法,不會影響到其他中斷響應,保證系統的實時性。

            補充:是否所有的中斷都需要分為兩部分來實現呢?

            不一定!如果發生中斷要做的事情很少不會影響系統的實時性,則就不必分成兩部分實現。

            linux中斷API

            linux中斷有專門的中斷子系統,其實現原理很復雜,但是驅動開發者不需要知道其實現的具體細節,只需要知道如何應用該子系統提供的API函數來編寫中斷相關驅動代碼即可。

            內核使用一個struct irqaction結構描述一個中斷,編寫中斷終極目標就是實現這個結構,當然結構不是我們自己去定義,但是結構中的材料是我們提供的。

             

            struct irq_desc {

                struct irq_data     irq_data;

                ·········//省略

                irq_flow_handler_t  handle_irq;

                struct irqaction    *action;    /* IRQ action list */

                }

            最關注的幾個成員

            interrupt.h \linux-3.5\include\linux

            struct irq_data {

                unsigned int        irq;

                unsigned long       hwirq;

                unsigned int        node;

                unsigned int        state_use_accessors;

                struct irq_chip     *chip;

                struct irq_domain   *domain;

                void            *handler_data;

                void            *chip_data;

                struct msi_desc     *msi_desc;

            #ifdef CONFIG_SMP

                cpumask_var_t       affinity;

            #endif

            };

            struct irqaction {

                irq_handler_t       handler; /*我們要提供的*/

                void            *dev_id;     /*我們要提供的*/

                void __percpu       *percpu_dev_id;

                struct irqaction    *next;

                irq_handler_t       thread_fn;

                struct task_struct  *thread;

                unsigned int        irq;     /*我們要提供的*/

                unsigned int        flags;   /*我們要提供的*/

                unsigned long       thread_flags;

                unsigned long       thread_mask;

                const char      *name;      /*我們要提供的*/

                struct proc_dir_entry   *dir;

            } ____cacheline_internodealigned_in_smp;

             

            //有五個成員您需要我們提供

            request_irq()

            原型

            int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)

            可以跟struct irqaction 結構體中的成員對應。

            功能:向內核注冊一個中斷服務函數,發生中斷號為irq的中斷的時候,會執行handle指針函數。

            參數:

            irq:中斷編號(每個中斷源有唯一編號),這里的中斷編號不是看硬件手冊,與裸機不同。由內核分配。

            handler:中斷服務函數指針,原型typedef irqreturn_t (*irq_handler_t)(int, void *);

            flag:中斷屬性,如快速中斷,共享中斷,如果是外部中斷還有:上升沿,下降沿觸發這類標志。

            name:中斷名字,注冊后會在/proc/irq/``irq號name文件夾出現。

            dev_id:這個參數時傳遞給中斷服務函數。對共享中斷來說,這個參數一定要有,當注銷共享中斷其中一個時,用這個指定標識注銷哪一個。對于有唯一入口的中斷,可以傳遞NULL,但一般來說都會傳遞一個有意義的指針,在中斷程序中使用,以方便編程。

            返回值:0表示成功,返回-EINVAL表示中斷號無效 ,返回-EBUSY表示中斷被占用。

            頭文件:include/linux/interrupt.h

            linux共享中斷

            共享中斷是指多個中斷共享一個中斷線的情況,在中斷到來時,會遍歷共次中斷的所有中斷處理函數,直到某一個中斷服務函數時返回IRQ_HANDLED

            在中斷處理程序頂半部中,應根據中斷相關硬件寄存器中的信息,判斷是否為本設備的中斷,若不是立即返回IRQ_NONE

            request_irq函數參數補充說明

            中斷編號

            在linux系統中總段編號可能和裸機的中斷編號數值不相同。如何確定一個中斷源的中斷編號?

            一般是由芯片廠商寫好所有可中斷號宏定義。在內核源碼中可以找到,如果是外部中斷,內核還提供了通用API函數,可以通過IO管腳編號轉換成它對應的中斷編號

            中斷服務函數類型是typedef irqreturn_t (*irq_handler_t)(int, void *);是一個指向有一個整形參數,一個void類型指針,返回值是irqreturn_t的函數指針。這個數據結構規定了中斷服務函數的原型。返回值類型在內核中定義為:

             

            /**

             * enum irqreturn

             * @IRQ_NONE        interrupt was not from this device

             * @IRQ_HANDLED     interrupt was handled by this device

             * @IRQ_WAKE_THREAD handler requests to wake the handler thread

             */

            enum irqreturn {

                IRQ_NONE        = (0 << 0),

                IRQ_HANDLED     = (1 << 0),

                IRQ_WAKE_THREAD     = (1 << 1),

            };

            第一個參數int類型的參數是中斷號,第二個void*類型指針是共享中斷的標識id,

            這兩個參數在中斷服務被調用的時候傳遞進來的內容實際上就是reauest_irq()在注冊s時候的irq,dev參數。這一點在源碼中有體現,編程的時候要注意,善于利用這個特性編寫程序。

            中斷屬性flag

             

            在include/linux/interrupt.h中定義可用的數值,以IRQF開頭的宏,若設置了IRQF_DISABLED,則表示中斷類型屬于獨占類型的中斷,不是共享中斷,若設置了 IRQF_SHARED,則表示鍍鉻設備共享中斷,若設置了 IRQF_SAMPLE_RANDOM,表示對系統獲取隨機數有好處,(這幾個宏可以通過或的方式組合使用),若是外部中斷還要設置IRQF_TRIGGER_XXX標志,表示選擇外部中斷的觸發電平,內核中相關定義如下:

            #define IRQF_TRIGGER_NONE   0x00000000

            #define IRQF_TRIGGER_RISING 0x00000001

            #define IRQF_TRIGGER_FALLING    0x00000002

            #define IRQF_TRIGGER_HIGH   0x00000004

            #define IRQF_TRIGGER_LOW    0x00000008

            #define IRQF_TRIGGER_MASK   (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \

                             IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)

            #define IRQF_TRIGGER_PROBE  0x00000010

             

            * These flags used only by the kernel as part of the

             * irq handling routines.

             *

             * IRQF_DISABLED - keep irqs disabled when calling the action handler.

             *                 DEPRECATED. This flag is a NOOP and scheduled to be removed

             * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator

             * IRQF_SHARED - allow sharing the irq among several devices

             * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur

             * IRQF_TIMER - Flag to mark this interrupt as timer interrupt

             * IRQF_PERCPU - Interrupt is per cpu

             * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing

             * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is

             *                registered first in an shared interrupt is considered for

             *                performance reasons)

             * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.

             *                Used by threaded interrupts which need to keep the

             *                irq line disabled until the threaded handler has been run.

             * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend

             * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set

             * IRQF_NO_THREAD - Interrupt cannot be threaded

             * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device

             *                resume time.

             */

            #define IRQF_DISABLED       0x00000020

            #define IRQF_SAMPLE_RANDOM  0x00000040

            #define IRQF_SHARED     0x00000080

            #define IRQF_PROBE_SHARED   0x00000100

            #define __IRQF_TIMER        0x00000200

            #define IRQF_PERCPU     0x00000400

            #define IRQF_NOBALANCING    0x00000800

            #define IRQF_IRQPOLL        0x00001000

            #define IRQF_ONESHOT        0x00002000

            #define IRQF_NO_SUSPEND     0x00004000

            #define IRQF_FORCE_RESUME   0x00008000

            #define IRQF_NO_THREAD      0x00010000

            #define IRQF_EARLY_RESUME   0x00020000

             

            #define IRQF_TIMER      (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) 

             

            常用值:IRQF_DISABLED,IRQF_SHARED 這兩個可以用來設置任何中斷,但是不能同時使用

            IRQF_TRIGGER_RISING IRQF_TRIGGER_FALLING 只對外部中斷有用,可以和上面的IRQF_DISABLED IRQF_SHARED之一組合使用

            IRQF_SHARED:添加上這個標志之后,此中斷號還可以注冊

            IRQF_DISABLED:添加上這個標志之后,此中斷號只能執行一次

            中斷名name

             

            中斷名字,在cat /proc/interrupts中可以看到此名稱,同時會出現/proc/irq/

            irq號/name文件夾出現

            中斷設備id識別標志dev

            這個參數會在發生中斷,執行服務函數時,作為實參傳遞給中斷服務函數的第二個參數。傳遞什么內容,完全由開發者決定,只要有利于更好的編寫中斷服務函數的都可以傳遞。

            在飛共享中斷時候可以是NULL,也可以傳遞任何用戶自定的結構地址,在共享中斷時必須傳遞有效參數,用于發生中斷時,用于在注銷中斷時識別具體要注銷中斷服務函數中的具體哪一個子項共享中斷。

            很多書,很多人認為dev這個參數能用于識別在發生中斷時候,是否是本設備產生的中斷,但是實際并不是這樣,要看開發者給這個參數傳遞什么內容,如果傳遞的是一個和中斷狀態有關的硬件寄存器地址,中斷服務程序中可以讀取這個寄存器的內容,從而判斷是否是本設備產生的中斷,如果只是傳遞一個普通的變量地址,并不能通過這個地址區分到底是那個硬件設備產生的中斷

            handled

             

            irqreturn_t (*irq_handler_t)(int, void *);

            返回值:有下面三種情況

             

            /**

             * enum irqreturn

             * @IRQ_NONE        interrupt was not from this device

             * @IRQ_HANDLED     interrupt was handled by this device

             * @IRQ_WAKE_THREAD handler requests to wake the handler thread

             */

            enum irqreturn {

                IRQ_NONE        = (0 << 0),

                IRQ_HANDLED     = (1 << 0),

                IRQ_WAKE_THREAD     = (1 << 1),

            };

            參數:

            第一個參數:中斷函數注冊時的中斷號irq

            第二個參數:注冊的時候最后一個參數dev_id

            中斷服務函數原型:

            irqreturn_t isr_function(int irq,void* dev_id)

            中斷服務函數模板:

            irqreturn_t isr_function(int irq,void* dev_id)

            {

             

             

            return IRQ_HANDLED;

            }

            對于共享中斷:

             

            irqreturn_t isr_function(int irq,void* dev_id)

            {

            //根據dev_id判斷是否是本設備產生的中斷

            if(readreg(dev_id)!=本設備產生中斷)

              return IRQ_NONE;

            //以下是本設備產生中斷的代碼

            return IRQ_HANDLED;

            }

             

            free_irq()

            描述 說明

            函數原型 void free_irq(int irq,void *dev_id)

            函數功能 從內核中斷服務函數鏈表中刪除一個中斷結構

            函數參數 同上

            函數返回值

            函數頭文件 include/linux/interrupt.h

            函數定義文件 kernel\irq\manage.c (用EXPORT_SYMBOL(free_irq)導出給內核模塊使用)

            這個函數跟request_irq函數功能相反,當設備不使用中斷時,使用這個函數把相關中斷在中斷鏈表中的節點釋放掉釋放掉。

            disable_irq,disable_irq_nosync

            描述 說明

            函數原型 void disabled_irq(unsigned int irq)

            函數功能 關閉指定的中斷,如果中斷沒有執行完,等待執行完在關閉,不能再中斷中使用,否則自己關閉自己,引起內核崩潰

            函數原型 void disabled_irq_nosync(unsigned int irq)

            函數功能 關閉中斷,不等待中斷執行完畢,可以在中斷函數中執行

            enable_irq

            描述 說明

            函數原型 void enabled_irq(unsigned int irq)

            函數功能 使能指定中斷

            local_save_flags(flags)

            描述 說明

            宏原型 local_save_flags(flags)

            宏功能 禁止本CPU全部中斷,并保存CPU狀態信息,(現在很多芯片是多核CPU)這個函數需要和local_irq_restore函數配合使用

            宏參數 flags:unsigned long類型用于保存當前CPU狀態信息

            宏返回值

             

            使用示例:

            unsigned long flags;

            local_save_flags(flags);

            ······

            local_irq_restore(flags);

            local_irq_restore(flags)

            描述 說明

            宏原型 local_irq_restore(flags)

            宏功能 與local_save_flags(flags)功能函數相反,配對使用,用來使能由與local_save_flags禁止的中斷

            宏參數 flags:unsigned long類型用于恢復當前CPU狀態信息

            宏返回值

            local_irq_disable()

            禁止本CPU中斷,不能保存當前CPU信息

            local_irq_enable()

            使能由local_irq_disable禁止的中斷,不能還原CPU信息

            linux3.5內核關于CPU中斷號

            linux中斷注冊函數中的irq中斷號并不是芯片物理上的編號,而是芯片廠商在移植linux系統時定在相關架構的頭文件中定義好的,在內核源碼中,名字一般是irqs.h

            irqs.h \linux-3.5\arch\arm\mach-exynos\include\mach

            下面是其中關于外部中斷的一部分內容,還有其他內容這里沒有列舉

             

            /* For EXYNOS4 SoCs */

             

            #define EXYNOS4_IRQ_EINT0       IRQ_SPI(16)

            #define EXYNOS4_IRQ_EINT1       IRQ_SPI(17)

            #define EXYNOS4_IRQ_EINT2       IRQ_SPI(18)

            #define EXYNOS4_IRQ_EINT3       IRQ_SPI(19)

            #define EXYNOS4_IRQ_EINT4       IRQ_SPI(20)

            #define EXYNOS4_IRQ_EINT5       IRQ_SPI(21)

            #define EXYNOS4_IRQ_EINT6       IRQ_SPI(22)

            #define EXYNOS4_IRQ_EINT7       IRQ_SPI(23)

            #define EXYNOS4_IRQ_EINT8       IRQ_SPI(24)

            #define EXYNOS4_IRQ_EINT9       IRQ_SPI(25)

            #define EXYNOS4_IRQ_EINT10      IRQ_SPI(26)

            #define EXYNOS4_IRQ_EINT11      IRQ_SPI(27)

            #define EXYNOS4_IRQ_EINT12      IRQ_SPI(28)

            #define EXYNOS4_IRQ_EINT13      IRQ_SPI(29)

            #define EXYNOS4_IRQ_EINT14      IRQ_SPI(30)

            #define EXYNOS4_IRQ_EINT15      IRQ_SPI(31)

            ·····

            可以看出這個文件是存放在和芯片體系架構相關的文件夾中

            對于外部中斷,可以通過IO口編號轉換成對應的中斷編號。關于IO口在下小節中說明

            static inline int gpio_to_irq(unsigned int gpio)

             

            上一篇:字符設備驅動

            下一篇:ARM終端之A系列

            熱點文章推薦
            華清學員就業榜單
            高薪學員經驗分享
            熱點新聞推薦
            前臺專線:010-82525158 企業培訓洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2018 北京華清遠見科技發展有限公司 版權所有 ,京ICP備16055225號,京公海網安備11010802025203號

            回到頂部

            有位老師想和您聊一聊

            yy4480影院