前言
作業中遇到了linux中遙控器驅動無法觸發足夠數量的中斷,導致無法正常解碼和作業,
環境:安卓 linux內核版本4.14.98
編譯體系:ninja
核心板:NXP imx8mm evk
NXP的imx8系列SOC應用在嵌入式產品上性能絕對是非常強大的,中斷觸發能力、中斷處理能力能滿足絕大部分需求,本不該出現中斷未能及時觸發或者中斷處理不及時導致遺失下一次中斷的問題,但是在作業中遇到了遙控器中斷被丟失,導致無法遙控器NEC資訊解碼失敗,無法接收到遙控器信號,
============================================
此貼首先直接指出解決方法,然后詳細描述遙控器驅動的移植與除錯程序,
核心問題描述:移植遙控器驅動后,硬體上用示波器能看到符合NEC協議的脈沖信號,但是驅動里加了DEBUG資訊并沒有解碼成功,在中斷處理函式中加了計數,發現實際觸發的中斷次數小于收到的次數,
漏中斷原因:CPU頻繁進入深度idle狀態
解決方法:修改設備樹中idle-states中的中相關引數,NXP官方提供的代碼4.14.98版本的設備樹如下:
cpus {
idle-states {
entry-method = "psci";
CPU_SLEEP: cpu-sleep {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x0010033>;
local-timer-stop;
entry-latency-us = <1000>;
exit-latency-us = <700>;
min-residency-us = <2700>;
wakeup-latency-us = <1500>;
};
};
};
修改下面四個與idle時間相關的引數如下:
entry-latency-us = <25000>;
exit-latency-us = <10000>;
min-residency-us = <30000>;
wakeup-latency-us = <15000>;
======================================================
正文
linux遙控器使用的實作方式:

說是遙控器驅動,實際上是紅外接收頭的驅動,遙控器發出38khz的載波,如上圖所示,當紅外接收頭接收到紅外信號,決議收到的信號,轉換成1.8V的高低電平信號,發送給處理器,處理器通過中斷的方式收集信號,當收集的信號組成了一個完整的用戶碼之后,在鍵值表中查找對應的鍵值,上報給input子系統,完成按鍵功能,
linux遙控器驅動移植流程:
STEP 0:
添加設備樹關于紅外遙控器(gpio方式觸發,NEC協議規范)節點:
設備樹添加的代碼如下:
pinctrl_gpiorc: ir_recv {
fsl,pins = <
//MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x14f
MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x1d6
>;
};
ir_recv: ir-receiver {
compatible = "gpio-ir-receiver";
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpiorc>;
gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
linux,rc-map-name = "rc-lme2510";
};
注意:gpio的復用模式,要根據你的硬體設定,注意硬體上是否需要內部上拉或者下拉,高有效還是低有效,linux,rc-map-name為遙控器的鍵值map,
STEP 1:
打開遙控相關的編譯選項;
在defconfig檔案中打開以下宏:
CONFIG_LIRC=y
CONFIG_IR_NEC_DECODER=y
CONFIG_IR_GPIO_CIR=y
CONFIG_RC_CORE=y
遙控器相關的代碼目錄:
kernel\driver\media\rc
該目錄下的檔案為remote control subsystem的代碼,也就是rc子系統,gpio中斷處理的檔案為gpio-ir-recv.c ,中斷函式函式中統計每次脈沖的持續時間,NEC協議中0.56ms高電平后接0.56ms低電平為邏輯0,后接1.6ms低電平則為邏輯1,中斷函式統計資料,在收到NEC的引導碼之后將資料存盤到fifo中進行解碼,按一次遙控器,符合NEC標準的資料由一個引導碼,兩位元組用戶碼,一位元組資料碼,一位元組用于校驗的資料反碼組成,一共是一共是33位,也就是高低電平跳變68次,應當接收到68次中斷,長按遙控器會發出repeat碼,具體NEC協議細節網上有許多資料,
NEC的解碼操作的原始碼在ir-nec-decoder.c中,核心函式為ir_nec_decode,此函式中的各個case判斷接收到了什么樣的NEC電平,是否完整收到了一條NEC碼,完整用戶資料將存放在scancode變數中,在STATE_TRAILER_SPACE這個case中通過rc_keydown函式,在map中的rc_map_table結構體中遍歷鍵值,當用戶碼與鍵值匹配上后講鍵值上報到input子系統,完成一次遙控器的按鍵事件上報,

保存用戶碼與鍵值的結構體代碼:
static struct rc_map_table asus_pc39[] = {
{ 0x0801, KEY_RADIO }, /* radio */
{ 0x083c, KEY_MENU }, /* dvd/menu */
{ 0x0815, KEY_VOLUMEUP },
{ 0x0826, KEY_VOLUMEDOWN },
{ 0x0808, KEY_UP },
{ 0x0804, KEY_DOWN },
{ 0x0818, KEY_LEFT },
{ 0x0810, KEY_RIGHT },
{ 0x081e, KEY_TV }, /* tv */
{ 0x0822, KEY_EXIT }, /* back */
{ 0x0835, KEY_CHANNELUP }, /* channel / program + */
{ 0x0824, KEY_CHANNELDOWN }, /* channel / program - */
{ 0x0825, KEY_ENTER }, /* enter */
};
除錯思路:
首先確認硬體是否有問題,直接在點信號進入soc之前用示波器抓取電平資訊,如果沒有收到正確的NEC協議的電信號,直接交給硬體工程師去排查,

軟體可能存在的問題和一些提醒:
一:在驅動的probe中加列印資訊,確認驅動是否被編譯并且加載到系統中了,如果probe失敗了,查看設備樹中的屬性是否與驅動中的不匹配,
二:在中斷處理函式中做統計,比對是否接收到了所有的中斷,如果沒有,查看是否需要修改系統屬性,增強系統性能,避免陷入idle狀態的時間過長,
三:可以在ir_nec_decode函式中講每個脈沖的觸發時間與持續時間打出來,講解碼狀態也打出來,配合示波器對比硬體輸入與軟體接收之間的區別,
四:確認硬體的上下拉狀態,確認gpio口的復用是否正確,屬性值是否設定成了輸入,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/240568.html
標籤:其他
