Linux驅(qū)動(dòng)開發(fā)_ 內(nèi)核中斷處理、定時(shí)器、阻塞與非阻塞IO
任務(wù)1: 復(fù)習(xí): 內(nèi)核中斷處理(按鍵為例)

裸機(jī)的中斷(STM32為例):
1. ?中斷線
2. ?中斷號(hào)(設(shè)置優(yōu)先級(jí)、使能)
3. ?中斷服務(wù)函數(shù)
4. ?建立中斷向量表(是中斷入口函數(shù)地址)
linux操作系統(tǒng)下中斷:
1. ?編寫中斷服務(wù)函數(shù)
2. ?注冊(cè)中斷 request_irq
3. ?注銷中斷 free_irq
4. ?獲取中斷號(hào)(通過GPIO口編號(hào)進(jìn)行獲取)
5. ?產(chǎn)生中斷的屬性: 邊沿觸發(fā)。
6. ?中斷向量表(在linux內(nèi)核不需要寫,它是在UBOOT階段建立的)
Linux系統(tǒng)下中斷處理
1. ?內(nèi)核中斷服務(wù)函數(shù)里不能出現(xiàn)會(huì)導(dǎo)致系統(tǒng)休眠的函數(shù)。比如: mdelay
2. ?內(nèi)核中斷處理分為上文和下文(真正做事情的地方)。
3. ?內(nèi)核中斷下文一般使用工作隊(duì)列或者內(nèi)核的微線程實(shí)現(xiàn)。
4. ?內(nèi)核中斷上文一般就調(diào)度工作隊(duì)列或者內(nèi)核微線程。
注明:工作隊(duì)列和內(nèi)核微線程里可以使用休眠函數(shù)。
查看內(nèi)核所有中斷的信息: [root@tiny4412 ]#cat /proc/interrupts
任務(wù)2: 復(fù)習(xí): 工作隊(duì)列
工作隊(duì)列是將任務(wù)推后執(zhí)行的一種機(jī)制,什么時(shí)候執(zhí)行? CPU空閑的時(shí)候執(zhí)行。
工作: 就是一個(gè)結(jié)構(gòu)體,結(jié)構(gòu)體里保存了工作對(duì)應(yīng)的函數(shù)(函數(shù)指針)。
隊(duì)列: 是一個(gè)鏈表形式,每一個(gè)鏈表的節(jié)點(diǎn)就是一個(gè)工作結(jié)構(gòu)體。
這個(gè)隊(duì)列由內(nèi)核的一個(gè)線程輪詢執(zhí)行,當(dāng)內(nèi)核執(zhí)行了工作之后,該工作結(jié)構(gòu)體就會(huì)從鏈表節(jié)點(diǎn)里刪除掉。
注意事項(xiàng): 如果之前加入的工作已經(jīng)在工作隊(duì)列里,還沒有被執(zhí)行,這個(gè)時(shí)候不能再重復(fù)添加。
在Linux內(nèi)核里有默認(rèn)的工作隊(duì)列: 共享工作隊(duì)列。 也可以自己去創(chuàng)建自己的隊(duì)列。
練習(xí):
1. ?將上課代碼全部寫一遍: 作業(yè)、中斷、工作隊(duì)列
2. ?試著使用內(nèi)核定時(shí)器給按鍵進(jìn)行消抖。
任務(wù)3: 內(nèi)核定時(shí)器
內(nèi)核定時(shí)器特性:
1. ?基于軟件層的定時(shí)器,定時(shí)器的定時(shí)器不是特別精準(zhǔn)。
2. ?內(nèi)核定時(shí)器的使用: 注冊(cè)和注銷。
3. ?內(nèi)核定時(shí)器是可以無限注冊(cè),內(nèi)部是通過鏈表實(shí)現(xiàn)---->隊(duì)列。
鏈表的每一個(gè)節(jié)點(diǎn)就是一個(gè)定時(shí)任務(wù),這個(gè)節(jié)點(diǎn)本身就是一個(gè)定時(shí)任務(wù)結(jié)構(gòu)體,在結(jié)構(gòu)體里就有一個(gè)函數(shù)指針。
4. ?定時(shí)器是基于 jiffies(節(jié)拍總數(shù)) 來實(shí)現(xiàn)定時(shí)。
計(jì)算一個(gè)節(jié)拍是多少時(shí)間? jiffies 1秒鐘(1000ms)增加HZ(200)次 , jiffies+1的時(shí)間:5m
int cnt=0;
void timer(void) //硬件中斷
{
cnt++; //5ms一次 1000000
}
void main(void)
{
int time=cnt+200;
while(cnt==time){}
printf("1234");
}
s64 ktime_to_us(const ktime_t kt); //轉(zhuǎn)換為 us 單位
s64 ktime_to_ms(const ktime_t kt); //轉(zhuǎn)換為 ms 單位
my_time=ktime_get(); //獲取當(dāng)前時(shí)間
紅外線編碼驅(qū)動(dòng)、超聲波測(cè)距之類的模塊。
任務(wù)4: 等待隊(duì)列
等待隊(duì)列: 在驅(qū)動(dòng)里阻塞進(jìn)程的一種方式,可以將進(jìn)程加入到等待隊(duì)列里休眠。
使用等待隊(duì)列:
1. ?定義一個(gè)等待隊(duì)列頭(靜態(tài))。
2. ?在指定位置將進(jìn)程休眠(掛起)。
3. ?在指定位置將進(jìn)程喚醒。
等待隊(duì)列休眠的原理:
任務(wù)5: 阻塞與非阻塞IO
在應(yīng)用可以通過哪些方法(系統(tǒng)調(diào)用)得知驅(qū)動(dòng)層資源已經(jīng)獲取成功?
有這3個(gè)函數(shù)接口: epoll、poll、select -----多路復(fù)用IO解決方法。
案例: 網(wǎng)絡(luò)編程里可以通過以上函數(shù)得知是否收到數(shù)據(jù)。
5.1 Poll函數(shù)學(xué)習(xí)
應(yīng)用層的函數(shù)接口:
#include
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd {
int fd; /*文件描述符 */
short events; /*監(jiān)控的事件 */
short revents; /*驅(qū)動(dòng)層返回的事件 */
};
函數(shù)參數(shù):
struct pollfd *fds :保存我們將要監(jiān)控的文件描述符所有信息。
nfds_t nfds :監(jiān)控的數(shù)量(有多少個(gè)文件描述符)。
int timeout : >0表示休眠的正常時(shí)間單位。=0表示不休眠。<0表示永久休眠。
說明: 時(shí)間單位是ms
返回值: 表示產(chǎn)生事件文件描述符數(shù)量。
說明: epoll、poll、select 這3個(gè)函數(shù)共用一個(gè)poll驅(qū)動(dòng)。
static unsigned int tiny4412_poll(struct file *file, struct poll_table_struct *poll_table)
{
unsigned int mask = 0; /*返回值: 掩碼*/
poll_wait(file,&key_wait,poll_table);
if(tiny4412_key_val)mask=POLLIN;
return mask;
}
5.2 異步通知
如何通知? 發(fā)送信號(hào),發(fā)送信號(hào)需要進(jìn)程PID號(hào)。
應(yīng)用層如何接收或者發(fā)送信號(hào)?
1. ?C語言代碼里可以通過signal函數(shù)來捕獲信號(hào):
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
參數(shù):
int signum: 將要捕獲信號(hào)。
sighandler_t handler: 處理信號(hào)的方法(函數(shù)指針)。
2. ?如何發(fā)送信號(hào)?
#include
#include
int kill(pid_t pid, int sig);
也可以通過命令:kill [-s signal|-p] [--] pid...
用法1: kill -s <信號(hào)名稱>
用法2: kill -<信號(hào)名稱>
3. ?有哪些信號(hào)發(fā)送呢?
[root@wbyq key_interrupt_drv]# kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
讓驅(qū)動(dòng)層代碼給進(jìn)程發(fā)送信號(hào)需要哪些條件?
1. ?驅(qū)動(dòng)層必須得支持異步通知的功能。
2. ?驅(qū)動(dòng)層得知道進(jìn)程的PID號(hào)。
驅(qū)動(dòng)層怎么給進(jìn)程發(fā)送信號(hào)?
設(shè)置文件的狀態(tài)信息:
#include
#include
int fcntl(int fd, int cmd, ... /* arg */ );
練習(xí):
1. ?將等待隊(duì)列、poll函數(shù)驅(qū)動(dòng)、異步IO驅(qū)動(dòng)寫一次。
2. ?poll函數(shù)支持多路復(fù)用: 將按鍵驅(qū)動(dòng)拆分成4個(gè)驅(qū)動(dòng),在應(yīng)用層使用一個(gè)poll函數(shù)同時(shí)監(jiān)控4個(gè)按鍵驅(qū)動(dòng),并讀出按鍵值。
Linux 任務(wù)調(diào)度
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。