Note06_Key按鍵驅動_中斷方式
-
KEY 硬體原理圖
如下圖所示,按鍵共有4個,K1——K4,對應的中斷號為 XEINT26——29(並非與硬體實際的中斷號對應),其對應的GPIO 引腳為GPX3_2——5。
-
KEY 相關暫存器
1)GPX3CON:GPIO PIN 模式設定暫存器
GPX3_2,對應的中斷模式需設定為0xF,GPX3_2——5 ==》EXT_INT43[5——2]
......
2)EXT_INT43_CON :中斷觸發方式設定暫存器
EXT_INT43[5——2],中斷觸發方式,設定為0x4,上下邊沿都觸發;
......
......
從如下圖,可知EXT_INT43,對應的中斷ID 為64.
-
中斷簡介
1)中斷源分類1:
中斷包含內部中斷和外部中斷:內部中斷:如若中斷由控制器或者SOC 上的完整的裝置產生的;比如 觸控式螢幕、串列埠等中斷方式;
外部中斷:即只連線到GPIO 引腳上,中斷訊號通過SOC引腳從SOC外部得到的中斷,沒有其他外部的裝置類控制其中斷的發生,只能通過設定SFR 來配置中斷模式、觸發方式等;4412外部中斷共計32個:
外部中斷 |
中斷ID |
中斷號 |
中斷 0—15 |
48——63 |
EINT[0:15] |
中斷16—31 |
64 |
EINT[16:31] |
2)中斷源分類2:
共享外部中斷:公共的外接中斷,中斷源ID號: SPI[127:0]
私有中斷:私有外設中斷 中斷源ID號: PPI[15:0]
軟中斷:由軟體設定的中斷源 中斷源ID號: SGI[15:0]
3)中斷處理流程:
首先儲存斷點 ==》查詢中斷入口函式 ==》中斷處理 ==》返回斷點;
- 中斷源觸發中斷;
- 首先確認GIC是否接收到中斷;然後確認是否將中斷轉給CPU;
- 首先確認CPU是否接收到中斷;然後確認接受的中斷號的許可權及優先順序;
3)exynos4412中斷簡介:
中斷控制器 gic 作用是進行中斷時間的接收和轉發;其資源共160箇中斷源(軟中斷16個、私有16個、外部128個),而CPU只識別中斷號,所以中斷處理的第一步就是獲取硬體觸發的中斷源,並轉化為CPU可識別的中斷號,該過程由gic完成。
4)中斷體系結構
略;待補充後補全;
【遺留】exynos 4412晶片如何將中斷和中斷號對應
-
中斷資源註冊函式
1)編寫驅動中斷模組是,利用核心的如下函式介面註冊中斷:
int request_irq(
unsigned int irq, //中斷號
irq_handler_t handler, //中斷處理函式
unsigned long flags, //中斷註冊的觸發方式
const char *name, //中斷的名字
void *dev //給中斷處理函式傳入的引數
);
2)中斷引數解釋:
irq: //中斷號
1> 對於內部中斷號
arch/arm/mach-exynos/include/mach/irqs.h
2> 對於外部中斷對應的中斷號的獲取
a. IRQ_EINT(eint);
b. 在知道gpio編號的情況下,可以通過gpio的編號,得到對應註冊的中斷號
gpio_to_irq(gpionum); //通過gpio編號返回中斷號
handler: //中斷處理函式
typedef irqreturn_t (*irq_handler_t)(int, void *);
中斷處理函式的形參:(發生中斷的中斷號, 註冊中斷時為其傳入的引數)
中斷處理函式返回值:
IRQ_NONE //中斷處理失敗
IRQ_HANDLED //中斷成功處理
flags: //中斷註冊的觸發方式
#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: //中斷的名字
dev: //給中斷處理函式傳入的引數
中斷髮生後,由核心呼叫處理函式時傳給處理函式的第二實參
-
驅動程式程式碼
1)按鍵中斷初始化:
5 // KEY 中斷初始化: 中斷號、按鍵名、按鍵計數
6 struct millkey{
7 int irqnum;
8 char *name;
9 int keycnt;
10 }keys[] = {
11 { IRQ_EINT(26), "KEY1", 0 },
12 { IRQ_EINT(27), "KEY2", 0 },
13 { IRQ_EINT(28), "KEY3", 0 },
14 { IRQ_EINT(29), "KEY4", 0 },
15 };
2)註冊中斷函式:
71 /*
72 ** driver init call func
73 */
74 static int __init demo_init(void)
75 {
76 return register_keys();
77 }
30 /*
31 ** register key irq devices
32 */
33 static int register_keys(void)
34 {
35 int i;
36 int ret;
37
38 for (i = 0; i < ARRAY_SIZE(keys); ++i) {
39 ret = request_irq(
40 keys[i].irqnum,
41 do_key_handler,
42 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
43 keys[i].name,
44 &keys[i] // irq handler's arg
45 );
46
47 if (ret < 0) {
48 goto error0;
49 }
50 }
51
52 return 0;
53
54 error0:
55 while (i--) {
56 free_irq(keys[i].irqnum, &keys[i]);
57 }
58
59 return ret;
60 }
3)中斷處理函式:
17 static irqreturn_t do_key_handler(int irqnum, void *data)
18 {
19 struct millkey *pdev = data;
20
21 printk();
22 pdev->keycnt++;
23
24 printk("%s is %s, keycnt = %d\n", pdev->name,
25 pdev->keycnt%2?"press down":"release up", pdev->keycnt);
26
27 return IRQ_HANDLED;
28 }
4)中斷登出函式:
62 static void unregister_keys(void)
63 {
64 int i;
65
66 for (i = 0; i < ARRAY_SIZE(keys); ++i) {
67 free_irq(keys[i].irqnum, &keys[i]);
68 }
69 }
70
79 module_init(demo_init);
80
81 static void __exit demo_exit(void)
82 {
83 unregister_keys();
84 }
-
測試程式程式碼
中斷是由硬體觸發,故無應用層的測試程式;
-
測試結果
1)插入驅動模組
[[email protected]_interrupt]#
[[email protected]_interrupt]# insmod demo.ko
[[email protected]_interrupt]#
[[email protected]_interrupt]#
[[email protected]_interrupt]#
[[email protected]_interrupt]# find / -name KEY*
/proc/irq/445/KEY4
/proc/irq/444/KEY3
/proc/irq/443/KEY2
/proc/irq/442/KEY1
[[email protected]_interrupt]#
[[email protected]_interrupt]#
2)檢視當前已註冊的中斷,及其發生的情況
[[email protected]_03_interrupt]# cat /proc/interrupts
CPU0 CPU1
28: 63591 472 GIC MCT
67: 0 0 GIC dma-pl330.0
68: 0 0 GIC dma-pl330.1
75: 0 0 GIC abc4412-wdt
......
......
442: 0 0 exynos-eint KEY1
443: 0 0 exynos-eint KEY2
444: 0 0 exynos-eint KEY3
445: 0 0 exynos-eint KEY4
3)按下按鍵,觸發中斷,可看到核心列印的日誌;
中斷設定雙邊沿觸發,因按鍵有抖動,故實際按下1次,但彈道多次觸發列印
[[email protected]_interrupt]#
[[email protected]_interrupt]#
[[email protected]_interrupt]# [ 7945.490000] KEY1 is release up
[ 7945.625000] KEY1 is press down
[ 7945.625000] KEY1 is release up
[ 7946.225000] KEY2 is release up
[ 7946.350000] KEY2 is press down
[ 7946.940000] KEY3 is release up
[ 7947.110000] KEY3 is press down
[ 7947.665000] KEY4 is press down
[ 7947.665000] KEY4 is release up
[ 7947.665000] KEY4 is press down
[ 7947.665000] KEY4 is release up
[ 7947.790000] KEY4 is press down
[[email protected]_interrupt]#
-
總結:
-
遺留問題
ret = request_irq(
40 keys[i].irqnum,
41 do_key_handler,
42 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
43 keys[i].name,
44 &keys[i] // irq handler's arg
45 );
1)如上中斷註冊函式,中斷號 keys[i].irqnum 是如何和核心核心註冊的硬體中斷ID聯絡起來的?可參考如下文件,待分析;
https://blog.csdn.net/zqixiao_09/article/details/50926677
https://blog.csdn.net/zqixiao_09/article/details/50908125?locationNum=5&fps=1
https://blog.csdn.net/zqixiao_09/article/details/50916212
https://www.cnblogs.com/wang_yb/archive/2013/04/19/3030345.html《linux 核心設計與實現閱讀筆記》
2)程式碼沒有消抖,故設定雙邊沿觸發時,會檢測到多次中斷,增加消抖處理機制;
定時器定時檢測消抖、delay(ms)死等延時消抖、中斷電平檢測消抖? 分析優缺點;
- 若應用程式需根據按鍵功能實現需求,則它如何知曉哪個按鍵被按下了呢?