linux imx8mm 漏中断问题 & linux遥控器驱动调试流程

前言

工作中遇到了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子系统,完成一次遥控器的按键事件上报。

NEC协议中0与1的辨别方式(图摘自网络)

保存用户码与键值的结构体代码:

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口的复用是否正确,属性值是否设置成了输入。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值