開發平台
* 芯靈思SinlinxA33開發闆
淘寶店鋪: https://sinlinx.taobao.com/
嵌入式linux 開發闆交流 QQ:641395230
Linux 中斷程式設計分為中斷頂半部,中斷底半部
中斷頂半部: 做緊急,耗時短的事情,同時還啟動中斷底半部。
中斷底半部: 做耗時的事件,這個事件在執行過程可以被中斷。
中斷底半部實作方法: tasklet,工作隊列,軟中斷等機制實作。實際上是把耗時事件推後執行,不在中斷程式執行。
什麼是tasklet?
Tasklet 一詞的原意是“小片任務”的意思,這裡是指一小段可執行的代碼,且通常以函數的形式出現。這個 tasklet 綁定的函數在一個時刻隻能在一個 CPU 上運作 ,tasklet(小任務)機制是中斷處理下半部分最常用的一種方法,其使用也是非常簡單的。一個使用 tasklet 的中斷程式首先會通過執行中斷處理程式來快速完成上半部分的工作,接着通過調用 tasklet 使得下半部分的工作得以完成。可以看到,下半部分被上半部分所調用,至于下半部分何時執行則屬于核心的工作。
tasklet 機制核心資料結構
Interrupt.h linux-3.5\include\Linux
struct tasklet_struct
{
struct tasklet_struct *next; // tasklet_struct 結構連結清單
unsigned long state; //目前這個 tasklet 是否已經被排程
atomic_t count;
void (*func)(unsigned long); //指向 tasklet 綁定的函數的指針
unsigned long data; //傳遞給tasklet 綁定的函數的參數
};
tasklet 相關 API
- 初始化相關
- 1) 靜态初始化
作用:定義一個名字為 name 的 tasklet_struct 結構變量,并且初始化這個結構。 所定義的這個 tasklet 是可以被排程,預設是處于被使能狀态。DECLARE_TASKLET(name, func, data)
- 1) 靜态初始化
* 2 ) 靜态初始化 `DECLARE_TASKLET_DISABLED(name, func, data)`
作用:定義一個名字為 name 的 tasklet_struct 結構變量,并且初始化這個結構。所定義的這個 tasklet 是不能被排程,預設是處于被禁能狀态。 要排程這個 tasklet 需要先使能。
* 3 )動态初始化
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)
作用:初始化一個 tasklet_struct 結構變量,初始化的結構預設是處于激活狀态,可以被排程。
tasklet_disable使能函數
1. void tasklet_disable(struct tasklet_struct *t)
作用:函數激活給定的 tasklet被 tasklet_schedule 排程
2. void tasklet_enable (struct tasklet_struct *t)
作用:函數禁止給定的 tasklet被 tasklet_schedule 排程
tasklet 排程函數
void tasklet_schedule (struct tasklet_struct *t)
作用:調用 tasklet_schedule 函數去通知核心幫我們排程所綁定的函數
void tasklet_kill(struct tasklet_struct *t);
作用:取消排程函數
程式設計步驟
Step1 定義并靜态初始化tasklet_struct 結構變量
Step2 編寫tasklet服務函數
Step3 在适當的地地方進行排程
Step4 在适當的地地方取消排程
芯靈思SinlinxA33開發闆
淘寶店鋪: [ https://sinlinx.taobao.com/]()
驅動代碼:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
void tasklet_fun(unsigned long data);
//Step1 定義并靜态初始化tasklet_struct 結構變量
DECLARE_TASKLET(mytasklet, tasklet_fun, 651);
//Step2 tasklet服務函數
void tasklet_fun(unsigned long data)
{
static unsigned long count = 0;
printk("count:%lu,%s is call! data:%lu\r\n",count++,__FUNCTION__,data);
tasklet_schedule(&mytasklet); //在工作函數中重新排程自己,這樣會循環調用tasklet_fun
}
static int __init mytasklet_init(void)
{
//Step3 開始排程 mytasklet
tasklet_schedule(&mytasklet);
printk("%s is call!\r\n",__FUNCTION__);
return 0;
}
static void __exit mytasklet_exit(void) //Module exit function specified by module_exit()
{
//Step4 删除 tasklet
tasklet_kill(&mytasklet);
}
module_init(mytasklet_init);
module_exit(mytasklet_exit);
MODULE_LICENSE("GPL");
Makefile 代碼
KERN_DIR = /work/lichee/linux-3.4
all:
make -C $(KERN_DIR) M=`pwd` modules
arm-none-linux-gnueabi-gcc btntest.c -o btntest
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += tasklet_drv.o