0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux中斷編程

嵌入式技術(shù) ? 來(lái)源:嵌入式技術(shù) ? 作者:嵌入式技術(shù) ? 2022-09-23 09:01 ? 次閱讀

Linux中斷編程

中斷:是指CPU在運(yùn)行過(guò)程中,出現(xiàn)了某種異常事件,需要CPU先暫停當(dāng)前工作,轉(zhuǎn)而去處理新產(chǎn)生的異常事件,處理完后再返回暫停的事件繼續(xù)往下執(zhí)行。就例如我們正在使用手機(jī)進(jìn)行微信視頻聊天,這時(shí)突然有人打電話過(guò)來(lái),這時(shí)手機(jī)的處理方式是手機(jī)來(lái)來(lái)電鈴聲響起,通知用戶電話來(lái)了。

中斷,就是來(lái)處理未來(lái)時(shí)間內(nèi)可能會(huì)發(fā)生的事件, 中斷事件也稱為異常事件。有了中斷處理,則可大大提高CPU處理效率。

單片機(jī)中,我們也常用中斷方式來(lái)處理一些緊急事件,幫我們實(shí)現(xiàn)快速響應(yīng)一些實(shí)時(shí)性的事件。因此我們?cè)诰帉懼袛喾?wù)函數(shù)時(shí)都是代碼盡可能簡(jiǎn)潔、一定不能處理死循環(huán)、若需要處理的事情比較多則應(yīng)在中斷中設(shè)定標(biāo)志位,然后將邏輯代碼放到主函數(shù)中去實(shí)現(xiàn)。

在Linux內(nèi)核中,我們一般會(huì)將中斷分為頂半部分和底半部分。頂半部分主要是處理耗時(shí)短的代碼(像單片機(jī)中設(shè)置標(biāo)志位),啟動(dòng)底半部分代碼;底半部分主要是處理耗時(shí)比較長(zhǎng)的代碼,完成中斷響應(yīng)后的事件處理。

1. Linux下外部中斷

??要使用外部中斷,則需要完成中斷三要素的配置:中斷號(hào)(irq)、中斷服務(wù)函數(shù)、中斷觸發(fā)方式(電平觸發(fā)、邊沿觸發(fā))。

1.1 相關(guān)接口函數(shù)

  • 獲取中斷號(hào)gpio_to_irq

??在Linux內(nèi)核中提供了方便函數(shù)獲取引腳中斷號(hào)

int gpio_to_irq(unsigned gpio)
函數(shù)功能: 獲取中斷號(hào)
返回值: 成功返回對(duì)應(yīng)GPIO的中斷號(hào)irq
  • 注冊(cè)中斷request_irq
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
函數(shù)功能: 注冊(cè)中斷
形 參: irq --中斷號(hào),gpio_to_irq函數(shù)返回值。
?? ?handler --中斷服務(wù)函數(shù)。
?? ??服務(wù)函數(shù)原型:typedef irqreturn_t (*irq_handler_t)(int, void *);
?? ?flags --中斷觸發(fā)方式。
?? ??#define IRQF_TRIGGER_RISING 0x00000001 //上升沿
?? ??#define IRQF_TRIGGER_FALLING 0x00000002 //下升沿
???? #define IRQF_TRIGGER_HIGH 0x00000004//高電平
????#define IRQF_TRIGGER_LOW 0x00000008//低電平

????#define IRQF_SHARED 0x00000080 //共享中斷
???name --中斷注冊(cè)標(biāo)志。
???dev --傳給中斷服務(wù)函數(shù)的參數(shù)。
返回值: 成功返回0,失敗返回其它值。
  • 中斷服務(wù)函數(shù)
typedef irqreturn_t (*irq_handler_t)(int, void *);
函數(shù)功能: 中斷服務(wù)函數(shù)
形 參: 第一個(gè)參數(shù)為中斷號(hào);第二個(gè)參數(shù)為注冊(cè)函數(shù)傳入的參數(shù)dev
返回值:
?? enum irqreturn {
????IRQ_NONE = (0 << 0), //如果不是本中斷的則返回這個(gè)值,只在共享中斷中使用
????IRQ_HANDLED = (1 << 0), //正確執(zhí)行中斷程序返回這個(gè)值,常用
????IRQ_WAKE_THREAD = (1 << 1), //表示去喚醒中斷處理者的線程
??};

??注意: irqreturn_t (*irq_handler_t)(int, void *);函數(shù)中不能出現(xiàn)帶休眠的函數(shù),如msleep函數(shù);該函數(shù)必須要返回值。

  • 注銷free_irq
free_irq(unsigned int irq, void *dev_id)
函數(shù)功能: 注銷中斷
形 參: irq --中斷號(hào),gpio_to_irq函數(shù)返回值。
???dev --傳給中斷服務(wù)函數(shù)的參數(shù)。需和注冊(cè)時(shí)保持一致

2. 工作隊(duì)列

??中斷處理函數(shù)分為中斷頂半部分和中斷底半部分。頂半部分代碼實(shí)現(xiàn)即為中斷服務(wù)函數(shù),而底半部分代碼則可由工作隊(duì)列完成。

2.1 工作隊(duì)列簡(jiǎn)介

操作系統(tǒng)中,如果我們需要進(jìn)行一項(xiàng)工作處理,往往需要?jiǎng)?chuàng)建一個(gè)任務(wù)來(lái)加入內(nèi)核的調(diào)度隊(duì)列。一個(gè)任務(wù)對(duì)應(yīng)一個(gè)處理函數(shù),如果要進(jìn)行不同的事務(wù)處理,則需要?jiǎng)?chuàng)建多個(gè)不同的任務(wù)。任務(wù)作為CPU調(diào)度的基本單元,任務(wù)數(shù)量越大,則調(diào)度成本越高。工作隊(duì)列(workqueue)機(jī)制簡(jiǎn)化了基礎(chǔ)的任務(wù)創(chuàng)建和處理機(jī)制,一個(gè)workqueue對(duì)應(yīng)一個(gè)實(shí)體task任務(wù)處理,工作隊(duì)列中可以掛載多個(gè)工作實(shí)體,每一個(gè)工作都能對(duì)應(yīng)不同的工作處理函數(shù)。即用戶只需要?jiǎng)?chuàng)建一個(gè)workqueue,則可以完成多個(gè)掛接不同處理函數(shù)的工作隊(duì)列。

工作隊(duì)列還具有將工作推后執(zhí)行機(jī)制,工作隊(duì)列可以把工作推后,交由一個(gè)內(nèi)核線程去執(zhí)行,也就是說(shuō),這個(gè)下半部分可以在進(jìn)程上下文中執(zhí)行。最重要的就是工作隊(duì)列允許被重新調(diào)度甚至是睡眠。

workqueue的處理依賴于task任務(wù)。一個(gè)workqueue隊(duì)列會(huì)創(chuàng)建關(guān)聯(lián)其對(duì)應(yīng)的task任務(wù),一個(gè)workqueue會(huì)掛載多個(gè)工作進(jìn)行處理,每個(gè)工作都有工作處理函數(shù)。當(dāng)workqueue得到調(diào)度,即其關(guān)聯(lián)的task得到運(yùn)行,在每次task的調(diào)度期間,都會(huì)從工作隊(duì)列中按照先后順序取出一個(gè)work來(lái)進(jìn)行處理。workqueue模塊在初始化時(shí),會(huì)創(chuàng)建一個(gè)系統(tǒng)默認(rèn)的工作隊(duì)列,用戶可根據(jù)需要將work添加到該隊(duì)列中去執(zhí)行。

2.2 工作相關(guān)函數(shù)接口

  • 工作結(jié)構(gòu)體struct work_struct
#include 
struct work_struct {
	atomic_long_t data;
	struct list_head entry;
	work_func_t func;  /*工作處理函數(shù)*/
#ifdef CONFIG_LOCKDEP
	struct lockdep_map lockdep_map;
#endif
};

??在工作結(jié)構(gòu)體體中,我們需要關(guān)心的成員是工作處理函數(shù):work_func_t func,簡(jiǎn)單來(lái)說(shuō)即一個(gè)工作會(huì)對(duì)應(yīng)有一個(gè)處理函數(shù)。工作處理函數(shù)原型如下:

#include 
typedef void (*work_func_t)(struct work_struct *work);
  • 初始化工作INIT_WORK
#define INIT_WORK(_work, _func)
函數(shù)功能: 初始化工作,以宏的方式實(shí)現(xiàn)
形 參: _work --工作結(jié)構(gòu)體體指針
???_func --工作處理函數(shù)
  • 工作調(diào)度schedule_work
int schedule_work(struct work_struct *work)

2.3工作隊(duì)列使用步驟

  1. 定義工作結(jié)構(gòu)體struct work_struct,初始化工作INIT_WORK;
  2. 編寫工作處理函數(shù)void (*work_func_t)(struct work_struct *work);
  3. 在合適的地方調(diào)調(diào)度工作(一般在中斷頂半部分);

2.4工作隊(duì)列使用示例

??下面以按鍵為例,實(shí)現(xiàn)中斷方式按鍵檢測(cè),通過(guò)工作隊(duì)列處理底半部分代碼,雜項(xiàng)設(shè)備框架實(shí)現(xiàn)設(shè)備注冊(cè)。

poYBAGMsVOqAM5YjAAC9181SmfI038.png#pic_centerpYYBAGMsVOuAZpP4AAGtQ8N96qc548.png#pic_center
  • K1 – GPX3_2
  • K2 --GPX3_3
  • K3 --GPX3_4
  • K4 --GPX3_5
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
struct work_struct key_work;/*工作結(jié)構(gòu)體*/
struct _KEY
{
	unsigned int gpio;/*按鍵引腳*/
	char name[20];/*按鍵名*/
	int irq;/*中斷號(hào)*/
	int key_num;/*按鍵編號(hào)*/
};
static struct _KEY KEY_GPIO_PIN[]=
{
	{EXYNOS4_GPX3(2),"key1",0,1},
	{EXYNOS4_GPX3(3),"key2",0,2},
	{EXYNOS4_GPX3(4),"key3",0,3},	
	{EXYNOS4_GPX3(5),"key4",0,4},	
};
static struct _KEY *key_p;
static unsigned int key_val;
/*工作服務(wù)函數(shù)*/
void key_work_func(struct work_struct *work)
{
	msleep(30);/*按鍵消抖*/
	if(gpio_get_value(key_p->gpio)==0)
	{
		printk(" key%d 按下n",key_p->key_num);
	}
	else 
	{
		printk(" key%d 松開n",key_p->key_num);
	}
	key_val=key_p->key_num;
}
/*中斷服務(wù)函數(shù)*/
static irqreturn_t key_irq_handler(int irq, void *dev)
{
	key_p=(struct _KEY *)dev;
	schedule_work(&key_work);/*調(diào)度工作*/
	return IRQ_HANDLED;/*中斷正常處理*/
}
static int key_open(struct inode *inode, struct file *file)
{
	printk("設(shè)備打開成功n");
	return 0;
}
static ssize_t key_read(struct file *file, char __user *buf, size_t cnt, loff_t *seek)
{
	int res=copy_to_user(buf,&key_val, 4);
	key_val=0;
	return 4-res;
}
static int key_release(struct inode *inode, struct file *file)
{
	printk("設(shè)備關(guān)閉成功n");
	return 0;
}
/*文件操作集合*/
static struct file_operations key_fops=
{
	.owner= THIS_MODULE, /*當(dāng)前模塊文件操作集合所有者*/
	.open=key_open,/*open函數(shù)接口*/
	.read=key_read,/*read函數(shù)接口*/
	.release=key_release,/*close函數(shù)接口*/
};
/*
字符設(shè)備注冊(cè):主設(shè)備+次設(shè)備號(hào)
主設(shè)備  --用來(lái)區(qū)分類(雜項(xiàng)設(shè)備、輸入設(shè)備)
次設(shè)備號(hào)  --對(duì)應(yīng)哪個(gè)設(shè)備
雜項(xiàng)設(shè)備的主設(shè)備號(hào)固定為:10
*/
static struct miscdevice key_miscdev = {
	.minor	= MISC_DYNAMIC_MINOR,/*次設(shè)備號(hào)255由內(nèi)核分配*/
	.name	= "tiny4412_key",/*設(shè)備節(jié)點(diǎn)名字,會(huì)在/dev下生成*/
	.fops	= &key_fops,/**/
};

static int __init tiny4412_key_module_init(void)
{
	int i=0;
	int res;
    printk("hello,驅(qū)動(dòng)注冊(cè)成功n");
	/*初始化工作*/
	INIT_WORK(&key_work,key_work_func);
	/*注冊(cè)中斷*/
	for(i=0;i(key_gpio_pin)>
poYBAGMsVOuAfzGRAAEtRbFUGc8924.png#pic_center

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11215

    瀏覽量

    208748
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3574

    瀏覽量

    93545
  • 中斷
    +關(guān)注

    關(guān)注

    5

    文章

    895

    瀏覽量

    41353
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux內(nèi)核中斷設(shè)計(jì)與實(shí)現(xiàn)

    裸機(jī)編程中使用中斷比較麻煩,需要配置寄存器、使能IRQ等等。而在Linux驅(qū)動(dòng)編程中,內(nèi)核提供了完善的終端框架,只需要申請(qǐng)中斷,然后注冊(cè)
    發(fā)表于 07-29 08:57 ?766次閱讀

    芯靈思Sinlinx A33開發(fā)板 Linux中斷編程原理說(shuō)明

    。step2 內(nèi)核關(guān)于 CPU 的中斷號(hào)linux 中斷注冊(cè)函數(shù)中的 irq 中斷號(hào)并不是芯片物理上的編號(hào),而是由芯片商在移植 Linux
    發(fā)表于 01-31 17:24

    芯靈思Sinlinx A33開發(fā)板 Linux中斷編程 2:程序框架

    根據(jù)上一個(gè)帖子的分析,想要實(shí)現(xiàn)按鍵中斷,首先得知道引腳對(duì)應(yīng)的中斷號(hào),LRADC0對(duì)應(yīng)的中斷編號(hào)#define SUNXI_IRQ_LRADC (SUNXI_GIC_START + 30)/* 62
    發(fā)表于 02-01 16:28

    芯靈思Sinlinx A33開發(fā)板Linux中斷編程 3-應(yīng)用程序

    應(yīng)用程序代碼參考#include #include #include #include #include #include #include #include #include #include#defineDEV_NAME "/dev/mybtn"int main(int argc, char *args[]){ int fd = 0; int ret = 0; unsigned char recv_buf[1] = {"0"}; fd = open(DEV_NAME, O_RDONLY); //fd = open(DEV_NAME, O_RDONLY|O_NONBLOCK); if(fd < 0) {perror("open"); } while(1) {strcpy(recv_buf, "0000");//讀取按鍵數(shù)據(jù)ret = read(fd, recv_buf, 1);if((ret < 0) && (errno != EAGAIN)) {perror("read");exit(-1);}//輸出按鍵狀態(tài)printf("%s\r\n", recv_buf); } return 0;}
    發(fā)表于 02-11 16:45

    芯靈思SinlinxA33開發(fā)板Linux中斷編程4-最終代碼(1)

    = IRQ_TYPE_EDGE_BOTH; irq = gpio_to_irq( GPIOL(14) );//發(fā)生中斷號(hào)為irq的中斷會(huì)執(zhí)行key_isr函數(shù)。注冊(cè)成功會(huì)在/proc/irq號(hào)/KEY文件夾出現(xiàn)或 cat
    發(fā)表于 02-13 16:09

    Linux 2.6 中斷處理原理簡(jiǎn)介

    Linux 2.6 中斷處理原理簡(jiǎn)介 中斷描述符表(Interrupt Descriptor Table,IDT)是一個(gè)系統(tǒng)表,它與每一個(gè)中斷或異常向量相聯(lián)系,每一個(gè)向量在表中存放的
    發(fā)表于 02-05 10:52 ?792次閱讀

    LINUX網(wǎng)絡(luò)編程

    linux開發(fā)編程教程資料——LINUX網(wǎng)絡(luò)編程,感興趣的小伙伴們可以看一看。
    發(fā)表于 08-23 16:23 ?0次下載

    Linux網(wǎng)絡(luò)編程

    linux開發(fā)編程教程資料——Linux網(wǎng)絡(luò)編程,感興趣的小伙伴們可以看一看。
    發(fā)表于 08-23 16:23 ?0次下載

    嵌入式Linux設(shè)備驅(qū)動(dòng)開發(fā)之中斷編程詳解

    11.5 中斷編程 前面所講述的驅(qū)動(dòng)程序中都沒(méi)有涉及中斷處理,而實(shí)際上,有很多Linux的驅(qū)動(dòng)都是通過(guò)中斷的方式來(lái)進(jìn)行內(nèi)核和硬件的交互。
    發(fā)表于 10-18 17:33 ?0次下載

    你了解linux中斷機(jī)制?

    中斷是指在CPU正常運(yùn)行期間,由于內(nèi)外部事件或由程序預(yù)先安排的事件引起的CPU暫時(shí)停止正在運(yùn)行的程序,轉(zhuǎn)而為該內(nèi)部或外部事件或預(yù)先安排的事件服務(wù)的程序中去,服務(wù)完畢后再返回去繼續(xù)運(yùn)行被暫時(shí)中斷的程序。Linux中通常分為外部
    發(fā)表于 05-05 15:30 ?699次閱讀

    Linux驅(qū)動(dòng)技術(shù)之一內(nèi)核中斷

    在硬件上,中斷源可以通過(guò)中斷控制器向CPU提交中斷,進(jìn)而引發(fā)中斷處理程序的執(zhí)行,不過(guò)這種硬件中斷體系每一種CPU都不一樣,而
    發(fā)表于 05-08 13:49 ?630次閱讀

    嵌入式Linux中斷驅(qū)動(dòng)

    用過(guò)STM32的大概都知道,基本每個(gè)GPIO管腳都支持中斷模式,這樣在檢測(cè)外部插入一個(gè)硬件設(shè)備時(shí),通過(guò)GPIO管腳電平中斷就非常方便。那么AM3354的片子是否支持GPIO管腳電平中斷呢?答案是肯定
    發(fā)表于 11-01 16:57 ?4次下載
    嵌入式<b class='flag-5'>Linux</b><b class='flag-5'>中斷</b>驅(qū)動(dòng)

    Linux中斷情景分析

    在一個(gè)系統(tǒng)中,中斷時(shí)常發(fā)生,而且線程調(diào)度也是由一個(gè)硬件定時(shí)器時(shí)時(shí)刻刻發(fā)出中斷來(lái)支撐的??梢哉f(shuō)中斷就是linux系統(tǒng)的靈魂。
    發(fā)表于 06-23 14:22 ?539次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>中斷</b>情景分析

    什么是LInux 操作系統(tǒng)中斷

    LInux 操作系統(tǒng)中斷 什么是系統(tǒng)中斷 這個(gè)沒(méi)啥可說(shuō)的,大家都知道; CPU 在執(zhí)行任務(wù)途中接收到中斷請(qǐng)求,需要保存現(xiàn)場(chǎng)后去處理中斷請(qǐng)求!
    的頭像 發(fā)表于 11-10 11:29 ?584次閱讀
    什么是<b class='flag-5'>LInux</b> 操作系統(tǒng)<b class='flag-5'>中斷</b>

    Linux應(yīng)用編程的基本概念

    Linux應(yīng)用編程涉及到在Linux環(huán)境下開發(fā)和運(yùn)行應(yīng)用程序的一系列概念。以下是一些涵蓋Linux應(yīng)用編程的基本概念。
    的頭像 發(fā)表于 10-24 17:19 ?168次閱讀