一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

Linux|Centos|Ubuntu|系統(tǒng)進(jìn)程|Fedora|注冊(cè)表|Bios|Solaris|Windows7|Windows10|Windows11|windows server|

服務(wù)器之家 - 服務(wù)器系統(tǒng) - Linux - 手把手教你中斷喚醒系統(tǒng)

手把手教你中斷喚醒系統(tǒng)

2021-12-28 23:45嵌入式Linux系統(tǒng)開發(fā)Jasonangel Linux

中斷喚醒系統(tǒng)和普通的驅(qū)動(dòng)區(qū)別在于,多了兩個(gè)函數(shù):suspend 和 resume,在 suspend 函數(shù)中,調(diào)用 enable_irq_wake,表示該中斷號(hào)在系統(tǒng)休眠時(shí)也是 enable 狀態(tài),可以觸發(fā)中斷。

手把手教你中斷喚醒系統(tǒng)

在消費(fèi)類電子中,功耗是很重要的,甚至項(xiàng)目后期一直在調(diào)功耗,看看哪里還可以再省電。由此就有了 Linux 電源管理子系統(tǒng),該子系統(tǒng)包含很多方面:什么時(shí)候可以降幀、什么時(shí)候可以關(guān)掉其他 CPU core、系統(tǒng)運(yùn)行時(shí)如果某外設(shè)很少用需要讓它運(yùn)行時(shí)休眠、系統(tǒng)休眠時(shí)要保證哪些外設(shè)可以喚醒系統(tǒng)。

博主今天要討論的,就是一個(gè)按鍵如何喚醒系統(tǒng),類似于手機(jī)的電源鍵。

這個(gè)功能并不是新功能,所以 Linux 內(nèi)部有一個(gè) demo 可以使用,先教大家如何使用該 demo,然后較大家如何撰寫中斷喚醒系統(tǒng)驅(qū)動(dòng)。

官方 demo

demo 目錄:/kernel4.14/drivers/input/keyboard/gpio_keys.c

該驅(qū)動(dòng)是專門為按鍵準(zhǔn)備的,是一個(gè)身經(jīng)百戰(zhàn)的驅(qū)動(dòng),任何時(shí)候測試按鍵中斷或者中斷喚醒系統(tǒng)都可以用它,很多時(shí)候比自己寫的驅(qū)動(dòng)靠譜。

要想使用該驅(qū)動(dòng),首先在該目錄的 Makefile 中增加:

  1. obj-y += gpio_keys.o

設(shè)備樹中增加:

  1. gpio-keys {
  2. compatible = "gpio-keys";
  3. #address-cells = <1>;
  4. #size-cells = <0>;
  5. autorepeat;
  6. key0 {
  7. label = "GPIO Key Enter";
  8. linux,code = ;
  9. gpios = <&gpio1 18 GPIO_ACTIVE_LOW>;
  10. gpio-key,wakeup;
  11. };
  12. };

compatible 屬性是 “gpio-keys”,gpio_keys.c 文件的674行會(huì)匹配這個(gè)屬性,匹配到了該驅(qū)動(dòng)就會(huì)運(yùn)行。

linux,code 屬性是按鍵值,Linux 對(duì)所有按鍵事件都有編號(hào),所以KEY_ENTER 實(shí)際是一個(gè)數(shù)字,是驅(qū)動(dòng)向上層報(bào)告的一個(gè)按鍵值。

gpios 屬性是標(biāo)明哪一個(gè) GPIO 口,低電平觸發(fā),大家可以自己選一個(gè) GPIO。

gpio-key,wakeup 是代表此GPIO支持中斷喚醒,你也可以寫成:wakeup-source。新老版本而已。

修改就是這么簡單,不過語法要符合各位手中的開發(fā)板平臺(tái)。然后編譯出內(nèi)核和設(shè)備樹文件,下載到板子中。(Linux 內(nèi)核根目錄會(huì)有 .config 文件,確保 CONFIG_PM_SLEEP=y 有打開)

如果驅(qū)動(dòng)加載成功,在 /proc/interrupts 中可以看到:

手把手教你中斷喚醒系統(tǒng)

從左往右第一列是軟件中斷號(hào)(唯一)。

第二列是 CPU,表示該中斷在該CPU上觸發(fā)了多少次,多核會(huì)有多列。

第三列是中斷控制器,imx6ull開發(fā)板根中斷控制器是GPC,外部中斷控制器是gpio-mxc,兩者是級(jí)聯(lián)關(guān)系。

第四列是硬件中斷號(hào),也就是GPIO口編號(hào)。

第五列表示該中斷是邊沿觸發(fā)還是電平觸發(fā)。

第六列是中斷名稱,可以找到一個(gè) GPIO Key Enter,如果驅(qū)動(dòng)加載成功就能看到,如果失敗就看不到。

驗(yàn)證方法

在內(nèi)核中,休眠方式有很多種,可以通過下面命令查看

  1. # cat /sys/power/state

常用的休眠方式有freeze、standby、mem、disk

freeze:凍結(jié)I/O設(shè)備,將它們置于低功耗狀態(tài),使處理器進(jìn)入空閑狀態(tài),喚醒最快,耗電比其它standby, mem, disk方式高

standby:除了凍結(jié)I/O設(shè)備外,還會(huì)暫停系統(tǒng),喚醒較快,耗電比其它 mem, disk方式高

mem:將運(yùn)行狀態(tài)數(shù)據(jù)存到內(nèi)存,并關(guān)閉外設(shè),進(jìn)入等待模式,喚醒較慢,耗電比disk方式高

disk:將運(yùn)行狀態(tài)數(shù)據(jù)存到硬盤,然后關(guān)機(jī),喚醒最慢

示例:

  1. # echo mem > /sys/power/state

系統(tǒng)進(jìn)入睡眠后,基本都會(huì)停掉UI、停掉串口,串口無法操作,如圖:

手把手教你中斷喚醒系統(tǒng)

按下按鍵,系統(tǒng)恢復(fù):

手把手教你中斷喚醒系統(tǒng)

當(dāng)然這里的 log 并不完整,輸入 dmesg 可以看到完整 log:

手把手教你中斷喚醒系統(tǒng)

PM:power manager

具體干了什么,圖中有解釋,分為 suspend 過程和 resume 過程。

其實(shí)一個(gè)中斷讓它支持喚醒系統(tǒng),最主要是多了兩個(gè)函數(shù):suspend、resume。

suspend 函數(shù)在系統(tǒng)整體 suspend 的時(shí)候,會(huì)調(diào)用每個(gè)外設(shè)注冊(cè)的 suspend,我們?cè)谶@個(gè)函數(shù)中調(diào)用 enable_irq_wake,表示該中斷在系統(tǒng)休眠時(shí)是 enable 狀態(tài)。

resume 函數(shù)在系統(tǒng)整體 resume 的時(shí)候,會(huì)調(diào)用每個(gè)外設(shè)注冊(cè)的 resume 函數(shù),在 resume 函數(shù)中調(diào)用 disable_irq_wake ,表示該中斷在系統(tǒng)運(yùn)行時(shí)不需要。兩者成對(duì)使用。

具體參看下面文章,寫的很好:

http://www.wowotech.net/irq_subsystem/irq_handle_procedure.html

大家也可以研究一下 gpio_keys.c,該驅(qū)動(dòng)看起來比較復(fù)雜,但是很完善,畢竟身經(jīng)百戰(zhàn),什么因素都考慮到了,測試就用它!

博主寫的 demo

博主下面給的是簡化版,并且自測OK,分享給大家,以后如果需要可以copy

xxx.c

  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include
  15. #include
  16. #include of.h>
  17. #include
  18. #include
  19. #include
  20. #include
  21. #include
  22. static int gpionum = 0;
  23. static int irqnum = 0;
  24. static irqreturn_t my_handler(int irq, void *dev_id)
  25. {
  26. printk("%s\r\n",__FUNCTION__);
  27. return IRQ_HANDLED;
  28. }
  29. static int gpio_keys_probe(struct platform_device *pdev)
  30. {
  31. int ret = 0;
  32. struct device_node *node = NULL;; /* 設(shè)備節(jié)點(diǎn)*/
  33. node = of_find_compatible_node(NULL,NULL,"atkalpha-key");
  34. if (node == NULL){
  35. printk("%s:atkalpha-key node not find!\r\n",__FUNCTION__);
  36. return -EINVAL;
  37. }
  38. /* 提取 GPIO */
  39. gpionum = of_get_named_gpio(node,"key-gpio", 0);
  40. if (gpionum < 0) {
  41. printk("of_get_named_gpio can't get key\r\n");
  42. }
  43. /* 初始化 key 所使用的 IO,并且設(shè)置成中斷模式 */
  44. gpio_request(gpionum, "key-gpio");
  45. gpio_direction_input(gpionum);
  46. irqnum = gpio_to_irq(gpionum);
  47. ret = request_irq(irqnum,my_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "my-key", NULL);
  48. if(ret < 0){
  49. printk("irq %d request failed!\r\n", irqnum);
  50. return -EFAULT;
  51. }
  52. return 0;
  53. }
  54. static const struct of_device_id gpio_keys_of_match[] = {
  55. { .compatible = "atkalpha-key", },
  56. { },
  57. };
  58. MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
  59. static int gpio_keys_remove(struct platform_device *pdev)
  60. {
  61. return 0;
  62. }
  63. static int gpio_keys_suspend(struct device *dev)
  64. {
  65. printk("%s\r\n",__FUNCTION__);
  66. enable_irq_wake(irqnum);
  67. return 0;
  68. }
  69. static int gpio_keys_resume(struct device *dev)
  70. {
  71. printk("%s\r\n",__FUNCTION__);
  72. disable_irq_wake(irqnum);
  73. return 0;
  74. }
  75. static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
  76. static struct platform_driver gpio_keys_device_driver = {
  77. .probe = gpio_keys_probe,
  78. .remove = gpio_keys_remove,
  79. .driver = {
  80. .name = "my-key",
  81. .pm = &gpio_keys_pm_ops,
  82. .of_match_table = of_match_ptr(gpio_keys_of_match),
  83. }
  84. };
  85. static int __init gpio_keys_init(void)
  86. {
  87. return platform_driver_register(&gpio_keys_device_driver);
  88. }
  89. static void __exit gpio_keys_exit(void)
  90. {
  91. platform_driver_unregister(&gpio_keys_device_driver);
  92. }
  93. module_init(gpio_keys_init);
  94. module_exit(gpio_keys_exit);
  95. MODULE_LICENSE("GPL");
  96. MODULE_AUTHOR("Jason");
  97. MODULE_DESCRIPTION("Keyboard driver for GPIOs");
  98. MODULE_ALIAS("platform:gpio-keys");

xxx.dts

  1. key {
  2. #address-cells = <1>;
  3. #size-cells = <1>;
  4. compatible = "atkalpha-key";
  5. key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>; /* KEY0 */
  6. interrupt-parent = <&gpio1>;
  7. interrupts = <18 irq_type_edge_both="">; /* FALLING RISING */
  8. gpio-key,wakeup;
  9. status = "okay";
  10. };

最后再總結(jié)一下:中斷喚醒系統(tǒng)和普通的驅(qū)動(dòng)區(qū)別在于,多了兩個(gè)函數(shù):suspend 和 resume,在 suspend 函數(shù)中,調(diào)用 enable_irq_wake,表示該中斷號(hào)在系統(tǒng)休眠時(shí)也是 enable 狀態(tài),可以觸發(fā)中斷。在 resume 函數(shù)中,調(diào)用 disable_irq_wake ,恢復(fù)原始的中斷觸發(fā)路徑。

然后使用 SIMPLE_DEV_PM_OPS 宏將 suspend 和 resume 函數(shù)注冊(cè)到 gpio_keys_pm_ops 操作集,最終由 platform 注冊(cè)到系統(tǒng)中。這樣完成后,系統(tǒng)休眠過程中就會(huì)調(diào)用到設(shè)備注冊(cè)的 suspend,系統(tǒng)喚醒過程中就會(huì)調(diào)用設(shè)備注冊(cè)的 resume 函數(shù)。

至于 probe 函數(shù)的書寫,我在 GPIO 子系統(tǒng)和中斷子系統(tǒng)系列文章都講過這些函數(shù)的使用,大家可以去我的網(wǎng)站查看:

http://www.linuxer.vip

note:該 demo 只用來喚醒系統(tǒng),如果你的中斷是在 I2C 等設(shè)備驅(qū)動(dòng)中,喚醒系統(tǒng)后要立刻在中斷處理函數(shù)中進(jìn)行 I2C 通信,寫法不太一樣,但是框架相同。

另外,該驅(qū)動(dòng)的中斷處理函數(shù)中沒做什么東西,因此喚醒后執(zhí)行完中斷處理函數(shù)后又會(huì)睡過去。如果你想要該中斷喚醒系統(tǒng)后讓系統(tǒng)一直處于喚醒狀態(tài),請(qǐng)?jiān)谥袛嗵幚砗瘮?shù)中使用 __pm_stay_awake() 和 __pm_relax()函數(shù)。

原文鏈接:https://mp.weixin.qq.com/s/FooG30_Fr4svQcqbK9y_9g

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 牛牛色婷婷在线视频播放 | 息与子中文字幕完整在线 | 精品国产品香蕉在线观看 | 欧美精品一区二区三区免费播放 | 日韩久久中文字幕 | 国产精品成人麻豆专区 | 色愉拍亚洲偷自拍 | 国产成人精品曰本亚洲78 | 亚洲天堂男人天堂 | 亚洲 日韩 国产 中文视频 | 人成午夜免费大片在线观看 | 国产1区二区 | 日韩视频在线精品视频免费观看 | 互换娇妻爽文100系列小说 | 欧美无专区 | 99久久99热久久精品免 | 国产精品51麻豆cm传媒 | 糖心视频在线观看 | 午夜欧美福利视频 | 日韩精品视频观看 | 国产成人亚洲精品一区二区在线看 | 国产精品怡红院永久免费 | 亚洲精品www久久久久久 | 67194久久 | 白丝超短裙被输出娇喘不停小说 | 2022av小四郎的最新地址 | 亚洲色图色 | 500福利第一导航 | 欧美四虎影院 | 激情文学综合网 | 色婷在线| 楚乔传第二部免费播放电视连续剧 | 欧美人与禽杂交大片 | 色欲麻豆国产福利精品 | 四虎黄色影视库 | 日本人成在线视频免费播放 | 97理伦| 欧美视频一二三区 | tolove第一季动画在线看 | 欧美日韩亚洲区久久综合 | 欧美精品综合一区二区三区 |