初入android驅動開發之字元裝置(四-中斷)

來源:互聯網
上載者:User

標籤:roi   ack   分解   mac   自己   nmap   arm架構   null   log   

上一篇講到android驅動開發中,應用是怎樣去操作底層硬體的整個流程,實現了按鍵控制led的亮滅。當然,這是一個非常easy的執行個體,只是略微演變一下,就能夠得到廣泛的應用。

如開發掃描磁頭,應用透過監聽上報的按鍵的鍵值,監聽到,則調用掃描磁頭的模組。成功,則點亮LED燈,並把掃描磁頭解碼後的條碼資訊。通過廣播的形式發出。又扯到其他地方,這裡主要說說中斷。

1. 中斷的一些概念

中斷,是什嗎?

中斷。能夠看成是cpu對特殊事件的一種處理的機制,這類特殊事件一般指緊急事件或者說例外狀況事件。非常easy的一個範例,你拿你手機正在看視頻,來了一個電話。你接完電話,還是停在視頻。本來你的cpu正在運行看視頻這一系列的指令處理。但當接收到電話,會產生一個中斷,cpu依據優先順序推斷。優先順序高於當前則停止當前工作。並儲存,然後運行中斷的處理函數,其中斷這一系列的事件處理完成以後。再運行儲存在暫停隊列中的工作。這是一個外部中斷的範例。

那麼中斷,是指 CPU 在運行程式的過程中,出現了某些突發事件時 CPU 必須暫停運行當前的程式,轉去處理突發事件,處理完成後 CPU 又返回原程式被中斷的位置並繼續運行。依據中斷的來源,中斷可分為內部中斷和外部中斷,內部中斷的中斷源來自 CPU內部(軟體中斷指令、溢出、除法錯誤等,比如,作業系統從使用者態切換到核心態需藉助 CPU 內部的軟體中斷),外部中斷的中斷源來自 CPU 外部,由外設提出請求。

中斷,實現它的機制?

中斷。當外設發出一個中斷訊號,cpu則依據中斷訊號,來進行分析處理,依據中斷訊號所對於的地址。去調用中斷處理函數。所以。中斷處理函數。是值該中斷產生後,cpu應該去緊急啟動並執行事件。

那麼,這裡主要解說一下中斷處理函數的機制。

s5pv210是arm架構的晶片,當中斷的資源很的豐富,這裡有32個外部中斷和其餘的gpio中斷。一般。實際開發中,中斷主要由外設發出。所以,這裡我們基本都是用的外部中斷。採用外部中斷的 CPU 通常為不同的中斷分配不同的中斷號,當檢測到某中斷號的中斷到來後,就自己主動跳轉到與該中斷號相應的地址運行。

不同中斷號的中斷有不同的入口地址。

中斷處理機制,,Linux 將中斷處理常式分解為兩個半部:頂半部(top half)和底半部(bottom half)。

在這兩者重要的差別,頂半部,不可被中斷,而底半部,能夠被新的中斷開啟。那麼,這兩者之前的差別,就認為了它們各自獨特的特性。頂半部,不可被打斷,所以註定它的已耗用時間要很很的高速,所以一般它僅僅是簡單的讀取寄存器的中斷狀態並清楚中斷標誌,然後就把底半部處理常式掛究竟半部運行隊列中。而這樣,中斷處理的大部分工作就落究竟半部了。由於可被打斷,相對來說,時間就比較充足。運行一些耗時的任務。

底半部的三種方式:非強制中斷、tasklet、工作隊列。

這裡有個博文連結。主要將三種機制以及之間的差異。http://blog.chinaunix.net/uid-20768928-id-5077401.html

中斷,當中關鍵的一些函數?

int request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned long irqflags,
const char *devname, void *dev_id)

irq:中斷號,這裡由gpio_to_irq()方法得到。
handler:發生中斷時首先要啟動並執行硬中斷處理函數,這個函數能夠通過返回 IRQ_WAKE_THREADED喚醒中斷線程,也可返回IRQ_HANDLE不運行中斷線程
thread_fn : 中斷線程,類似於中斷下半部,若傳參為null,則和request_irq()一樣
qflags:中斷標誌。備忘:IRQF_SHARED 共用中斷時,dev_id不可為空。由於釋放irq時要區分哪個共用中斷。
devname:中斷名

dev_id: 傳給中斷處理函數的參數。

2.簡單的執行個體:

#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/irq.h>#include <linux/input.h>#include <linux/platform_device.h>#include <linux/miscdevice.h>#include <mach/gpio.h>#include <linux/io.h>#include <mach/hardware.h>#include <linux/delay.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <linux/interrupt.h>#include <linux/gpio.h>#include <linux/wait.h>#include <linux/sched.h>#include <plat/gpio-core.h>#include <plat/gpio-cfg.h>#include <plat/gpio-cfg-helpers.h>static struct class *buttondrv_class;static struct device *buttondrv_class_dev;int major;volatile unsigned long *GPCCON;volatile unsigned long *GPCDAT;//static DECLARE_WAIT_QUEUE_HEAD(button_waitq);static unsigned char key_val;static volatile int ev_press = 0;struct pin_desc{unsigned int pin;unsigned int key_val;};struct pin_desc pins_desc[2] = {{S5PV210_GPH3(7), 0x01},};static irqreturn_t buttons_irq(int irq, void *dev_id){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>buttons_irq\n");struct pin_desc *pindesc = (struct pin_desc *)dev_id;unsigned int pinval;pinval = gpio_get_value(pindesc->pin);printk("irq >>>>>>>>>>>>>>>>>>>>>>>>>>>>pinval =%d \n",pinval);if (pinval){key_val = 0x80 | pindesc->key_val;printk("1111 >>>>>>>>>>>>>>>>>>>>>>>>>>>key_val =%d \n",key_val);}else{key_val = pindesc->key_val;printk("0000 >>>>>>>>>>>>>>>>>>>>>>>>>>>key_val =%d \n",key_val);}    ev_press = 1;               //    wake_up_interruptible(&button_waitq);  return IRQ_RETVAL(IRQ_HANDLED);}static int button_drv_open(struct inode *inode, struct file *file){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_open\n");int ret=-1;s3c_gpio_setpull(S5PV210_GPH3(7), S3C_GPIO_PULL_NONE);ret = request_threaded_irq(gpio_to_irq(S5PV210_GPH3(7)), NULL,buttons_irq,IRQF_TRIGGER_RISING,"s2", &pins_desc[0]);printk("ret=%d irq=%d >>>>>>>>>>>>>>>>>>>>>>>>>\n ",ret,gpio_to_irq(S5PV210_GPH3(7)));return 0;}int button_drv_close(struct inode *inode, struct file *file){free_irq(gpio_to_irq(S5PV210_GPH3(7)), &pins_desc[0]);return 0;}static int button_drv_read(struct file *filp, char __user *buf,                                          size_t count, loff_t *offp){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_read\n");if (count != 1)return -EINVAL;printk("read >>>>>>>>>>>>>>>>>>>>>>>>>>>key_val =%d \n",key_val);//wait_event_interruptible(button_waitq, ev_press);copy_to_user(buf, &key_val, 1);key_val=0;ev_press = 0;return 1;}static struct file_operations button_drv_fops = {    .owner  =   THIS_MODULE,       .open   =   button_drv_open,           .read=button_drv_read,    .release =  button_drv_close,};static int button_drv_init(void){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_init\n");    GPCCON = (volatile unsigned long *)ioremap(0xE0200C60, 8);GPCDAT= GPCCON + 1;if (!GPCCON) {return -EIO;}major = register_chrdev(0, "button_drv", &button_drv_fops); buttondrv_class = class_create(THIS_MODULE, "buttondrv");buttondrv_class_dev = device_create(buttondrv_class, NULL, MKDEV(major, 0), NULL, "button"); return 0;}static void button_drv_exit(void){printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_exit\n");unregister_chrdev(major, "button_drv"); device_unregister(buttondrv_class_dev);class_destroy(buttondrv_class);iounmap(GPCCON);}module_init(button_drv_init);module_exit(button_drv_exit);MODULE_LICENSE("GPL");
關於代碼一些簡單的說明:

static DECLARE_WAIT_QUEUE_HEAD(button_waitq)

wake_up_interruptible(&button_waitq)

wait_event_interruptible(button_waitq, ev_press)

這個是等待隊列的機制,當有中斷的時候。喚醒。把事件增加工作隊列中,處理完事件後。繼續休眠,直到下次中斷。

3.關於一些調試方法:

一般在編寫中斷的程式,最基本的是要看,gpio口的中斷號是否申請成功。這裡主要依據列印語句進行調試了。

若驅動程式不報錯誤了,則可進入android系統下,cat proc/interrupts   ,可查看到你申請成功的中斷。

初入android驅動開發之字元裝置(四-中斷)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.