DRV_05_GPIO按鍵驅(qū)動(dòng)分析與使用

資料下載

由于無法通過瀏覽器直接訪問,需要使用git工具進(jìn)行下載:

git clone https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git

您可以觀看百問網(wǎng)的驅(qū)動(dòng)大全視頻,以獲取更多相關(guān)信息。

GPIO按鍵驅(qū)動(dòng)分析與使用參考資料:

Linux 5.x內(nèi)核 Documentationdevicetreebindingsinputgpio-keys.txt driversinputkeyboardgpio_keys.c Linux 4.x內(nèi)核 Documentationdevicetreebindingsinputgpio-keys.txt driversinputkeyboardgpio_keys.c

設(shè)備樹示例: IMX6ULL:Linux-4.9.88/arch/arm/boot/dts/100ask_imx6ull-14×14.dts STM32MP157:Linux-5.4/arch/arm/boot/dts/stm32mp15xx-100ask.dtsi QEMU:linux-4.9.88/arch/arm/boot/dts/100ask_imx6ull_qemu.dts

  1. 驅(qū)動(dòng)程序框架

DRV_05_GPIO按鍵驅(qū)動(dòng)分析與使用

  1. 設(shè)備樹示例

2.1 設(shè)備樹講解屬性:

必備:compatible = “gpio-keys”; 可選:autorepeat:表示自動(dòng)重復(fù),按下按鍵不松開,驅(qū)動(dòng)會(huì)自動(dòng)重復(fù)上報(bào)按鍵值 對(duì)于每一個(gè)GPIO按鍵,都是一個(gè)子節(jié)點(diǎn),有這些屬性: gpios:使用哪個(gè)GPIO interrupts:對(duì)應(yīng)的中斷 linux,code:對(duì)應(yīng)的按鍵值 注意:gpios和interrupts至少要保留一個(gè),不能都省略 debounce-interval:消除抖動(dòng)的間隔,單位:ms,默認(rèn)是5ms

2.2 100ASK_IMX6ULL

gpio-keys {     compatible = "gpio-keys";     pinctrl-names = "default";     user1 {         label = "User1 Button";         gpios = ;         gpio-key,wakeup;         linux,code = <key_1>;     };     user2 {         label = "User2 Button";         gpios = ;         gpio-key,wakeup;         linux,code = <key_2>;     }; };

2.3 100ASK_STM32MP157

joystick {     compatible = "gpio-keys";     #size-cells = ;     button-0 {         label = "usr_button0";         linux,code = <key_a>;         interrupt-parent = ;         interrupts = ;     };     button-1 {         label = "usr_button1";         linux,code = <key_enter>;         interrupt-parent = ;         interrupts = ;     }; };

2.4 QEMU

gpio-keys@0 {     compatible = "gpio-keys";     pinctrl-names = "default";     pinctrl-0 = ;     status = "okay";     Key0 {         label = "Key 0";         gpios = ;         linux,code = <key_1>;     }; }; gpio-keys@1 {     compatible = "gpio-keys";     pinctrl-names = "default";     pinctrl-0 = ;     status = "okay";     Key0 {         label = "Key 1";         gpios = ;         linux,code = <key_2>;     }; };
  1. gpio_keys.c驅(qū)動(dòng)程序分析

3.1 套路

根據(jù)設(shè)備樹獲得硬件信息:哪個(gè)GPIO、對(duì)于什么按鍵分配/設(shè)置/注冊(cè)input_dev結(jié)構(gòu)體 request_irq:在中斷處理函數(shù)中確定按鍵值、上報(bào)按鍵值 有兩種IRQ函數(shù) gpio_keys_gpio_isr:設(shè)備樹中的用gpios來描述用到的引腳 gpio_keys_irq_isr:設(shè)備樹中的用interrupts來描述用到的引腳

3.2 gpio_keys_gpio_isr分析

理想狀況是:按下、松開按鍵,各產(chǎn)生一次中斷,也只產(chǎn)生一次中斷。 但是對(duì)于機(jī)械開關(guān),它的金屬?gòu)椘瑫?huì)反復(fù)震動(dòng)。GPIO電平會(huì)反復(fù)變化,最后才穩(wěn)定。一般是幾十毫秒才會(huì)穩(wěn)定。 如果不處理抖動(dòng)的話,用戶只操作一次按鍵,會(huì)發(fā)生多次中斷,驅(qū)動(dòng)程序可能會(huì)上報(bào)多個(gè)數(shù)據(jù)。

DRV_05_GPIO按鍵驅(qū)動(dòng)分析與使用

怎么處理按鍵抖動(dòng)?

在按鍵中斷程序中,可以循環(huán)判斷幾十亳秒,發(fā)現(xiàn)電平穩(wěn)定之后再上報(bào) 使用定時(shí)器 顯然第1種方法太耗時(shí),違背“中斷要盡快處理”的原則,你的系統(tǒng)會(huì)很卡。

怎么使用定時(shí)器?看下圖:

DRV_05_GPIO按鍵驅(qū)動(dòng)分析與使用

核心在于:在GPIO中斷中并不立刻記錄按鍵值,而是修改定時(shí)器超時(shí)時(shí)間,10ms后再處理。 如果10ms內(nèi)又發(fā)生了GPIO中斷,那就認(rèn)為是抖動(dòng),這時(shí)再次修改超時(shí)時(shí)間為10ms。 只有10ms之內(nèi)再無GPIO中斷發(fā)生,那么定時(shí)器的函數(shù)才會(huì)被調(diào)用。 在定時(shí)器函數(shù)中上報(bào)按鍵值。

3.3 gpio_keys_irq_isr分析

有個(gè)變量key_pressed,用來表示當(dāng)前按鍵狀態(tài):初始值是false,表示按鍵沒有被按下。

發(fā)生中斷 上報(bào)”按下的值”:input_Event(input, EV_KEY, button->code, 1); input_sync(input); 如果不延遲(!bdata->release_delay) 馬上上報(bào)”松開的值”:input_event(input, EV_KEY, button->code, 0); input_sync(input); 如果延遲(bdata->release_delay) 啟動(dòng)定時(shí)器,過若干毫秒再上報(bào)”松開的值” 所以,使用gpio_keys_irq_isr時(shí),一次中斷就會(huì)導(dǎo)致上報(bào)2個(gè)事件:按下、松開 缺點(diǎn):無法準(zhǔn)確判斷一個(gè)按鍵確實(shí)已經(jīng)被松開了

  1. QEMU上機(jī)實(shí)驗(yàn)

IMX6ULL、STM32MP157的出廠系統(tǒng)都已經(jīng)配置的GPIO按鍵。 可以執(zhí)行以下命令確認(rèn)設(shè)備節(jié)點(diǎn):

cat /proc/bus/input/devices

然后執(zhí)行hexdump /dev/input/event?(?表示某個(gè)數(shù)值),并且操作按鍵來觀察輸出信息。

也可以在QEMU上做實(shí)驗(yàn):原理圖如下:

DRV_05_GPIO按鍵驅(qū)動(dòng)分析與使用

4.1 設(shè)置工具

ubuntu中執(zhí)行:

export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabihf- export PATH=$PATH:/home/book/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin

4.2 配置內(nèi)核

QEMU的內(nèi)核里已經(jīng)配置了GPIO按鍵的設(shè)備樹,只需要編譯出gpio_keys驅(qū)動(dòng)程序即可。 配置內(nèi)核:執(zhí)行make menuconfig

-> Device Drivers   -> Input device support     -> Generic input layer       -> Keyboards         <m>   GPIO Buttons

4.3 編譯驅(qū)動(dòng)

book@100ask:~/100ask_imx6ull-qemu$ cd linux-4.9.88 book@100ask:~/100ask_imx6ull-qemu/linux-4.9.88$ make modules

成功的話,可以得到:

drivers/input/keyboard/gpio_keys.ko

復(fù)制到如下目錄:

$ cp drivers/input/keyboard/gpio_keys.ko ~/nfs_rootfs/

4.4 啟動(dòng)QEMU

在Ubuntu中執(zhí)行:

$ cd ubuntu-18.04_imx6ul_qemu_system $ ./qemu-imx6ull-gui.sh

4.5 掛載NFS、實(shí)驗(yàn)

在QEMU中執(zhí)行:

$ mount -t nfs -o nolock,vers=3 10.0.2.2:/home/book/nfs_rootfs /mnt $ insmod /mnt/gpio_keys.ko $ cat /proc/bus/input/devices   // 確認(rèn)設(shè)備節(jié)點(diǎn) $ hexdump /dev/input/event3

在QEMU的GUI界面操作:

DRV_05_GPIO按鍵驅(qū)動(dòng)分析與使用

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊11 分享