IR驱动开发

概述

红外遥控的发射电路是采用红外发光二极管来发出经过调制的红外光波;红外接收电路由红外接收二极管、 三极管或硅光电池组成,它们将红外发射器发射的红外光转换为相应的电信号,再送后置放大器。鉴于家用电器的品种多样化和用户的使用特点,生产厂家对进行了严格的规范编码,这些编码各不相同,从而形成不同的编码方式,统一称为红外遥控器编码传输协议。到目前为止,红外遥控协议已多达十种, 如: RC5、SIRCS、Sy、RECS80、Denon、NEC、Motorola、Japanese、SAMSWNG 和 Daewoo 等。我国家用电器的红外遥控器的生产厂家,其编码方式多数是按上述的各种协议进行编码的,而用得较多的有 NEC 协议。目前 RK 平台也只支持 NEC 编码的红外协议。

_images/ir_introduction.png

RK 平台上红外实现原理简介

PWM 有三种工作模式, reference mode, one-shot mode 和 continuousmode. 红外遥控器就采用 reference mode,这种模式下 PWM 可以捕获输入高低电平的宽度,并产生中断, CPU接收到中断后去相应的寄存器读取。

_images/pwm_mode.png

按下遥控的时候,红外接收头会产生一系列的高低电平, PWM 就会产生相应的中断, CPU 读取相应的寄存器就知道这些高低电平的时间,根据协议就可以解码出红外的用户码和键值码出来。 下图是 NEC 红外编码协议的简单示意图,详细的协议附在最后。

_images/nec_protocol1.png _images/nec_protocol2.png

DTS配置

&pwm3 {
    status = "okay";
pinctrl-names = "default";//为IR rx模式,不要配置为gpio模式
    interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH 0>;
    compatible = "rockchip,remotectl-pwm";
    remote_pwm_id = <3>;
    handle_cpu_id = <1>;
    ir_key1 {
       rockchip,usercode = <0x4040>;
       rockchip,key_table =
           <0xf2  KEY_REPLY>,
           <0xba  KEY_BACK>,
           <0xf4  KEY_UP>,
           <0xf1  KEY_DOWN>,
           <0xef  KEY_LEFT>,
           <0xee  KEY_RIGHT>,
           <0xbd  KEY_HOME>,
           <0xea  KEY_VOLUMEUP>,
           <0xe3  KEY_VOLUMEDOWN>,
           <0xe2  KEY_SEARCH>,
           <0xb2  KEY_POWER>,
           <0xbc  KEY_MUTE>,
           <0xec  KEY_MENU>,
           <0xbf  0x190>,
           <0xe0  0x191>,
           <0xe1  0x192>,
           <0xe9  183>,
           <0xe6  248>,
           <0xe8  185>,
           <0xe7  186>,
           <0xf0  388>,
           <0xbe  0x175>;
    };
    ir_key2 {
       rockchip,usercode = <0xff00>;
       rockchip,key_table =
           <0xf9  KEY_HOME>,
           <0xbf  KEY_BACK>,
           <0xfb  KEY_MENU>,
           <0xaa  KEY_REPLY>,
           <0xb9  KEY_UP>,
           <0xe9  KEY_DOWN>,
           <0xb8  KEY_LEFT>,
           <0xea  KEY_RIGHT>,
           <0xeb  KEY_VOLUMEDOWN>,
           <0xef  KEY_VOLUMEUP>,
           <0xf7  KEY_MUTE>,
           <0xe7  KEY_POWER>,
           <0xfc  KEY_POWER>,
           <0xa9  KEY_VOLUMEDOWN>,
           <0xa8  KEY_VOLUMEDOWN>,
           <0xe0  KEY_VOLUMEDOWN>,
           <0xa5  KEY_VOLUMEDOWN>,
           <0xab  183>,
           <0xb7  388>,
           <0xe8  388>,
           <0xf8  184>,
           <0xaf  185>,
           <0xed  KEY_VOLUMEDOWN>,
           <0xee  186>,
           <0xb3  KEY_VOLUMEDOWN>,
           <0xf1  KEY_VOLUMEDOWN>,
           <0xf2  KEY_VOLUMEDOWN>,
           <0xf3  KEY_SEARCH>,
           <0xb4  KEY_VOLUMEDOWN>,
           <0xbe  KEY_SEARCH>;
    };
    ir_key3 {
       rockchip,usercode = <0x1dcc>;
       rockchip,key_table =
           <0xee  KEY_REPLY>,
           <0xf0  KEY_BACK>,
           <0xf8  KEY_UP>,
           <0xbb  KEY_DOWN>,
           <0xef  KEY_LEFT>,
           <0xed  KEY_RIGHT>,
           <0xfc  KEY_HOME>,
           <0xf1  KEY_VOLUMEUP>,
           <0xfd  KEY_VOLUMEDOWN>,
           <0xb7  KEY_SEARCH>,
           <0xff  KEY_POWER>,
           <0xf3  KEY_MUTE>,
           <0xbf  KEY_MENU>,
           <0xf9  0x191>,
           <0xf5  0x192>,
           <0xb3  388>,
           <0xbe  KEY_1>,
           <0xba  KEY_2>,
           <0xb2  KEY_3>,
           <0xbd  KEY_4>,
           <0xf9  KEY_5>,
           <0xb1  KEY_6>,
           <0xfc  KEY_7>,
           <0xf8  KEY_8>,
           <0xb0  KEY_9>,
           <0xb6  KEY_0>,
           <0xb5  KEY_BACKSPACE>;
    };
};

字母和符号键都是 linux 的标准键值,在可以在 include/dt-bindings/input/input.h 中查找。

驱动位置

/kernel/drivers/input/remotectl/rockchip_pwm_remotectl.c

debug

1、打开打印键值的调试开关 echo 1 > sys/module/rockchip_pwm_remotectl/parameters/code_print

按遥控器的按键,记录下对应的键值 例如按向下键,有如下打印 [19634.735833] GET USERCODE=0x4040 [19634.762463] RMC_GETDATA=e9 则,该遥控器的 usercode 是 0x4040,向下键的键值就是 0xe9,如此反复,直到打印完遥控器上的所有键值。

2、有时候需要配合 echo 1 > /sys/module/rockchip_pwm_remotectl/parameters/code_print 一起打印,然后看出错的时候,是哪一个或者几个 bit 引起的,有时候放宽一点判断的条件即可,一般是通过修改上下限来达到,具体可以参考代码里面 bit 值的判断地方。

3、getevent 有时候无法确定是内核按键判断出错,还是 android 层没有响应某个按键, 可以在串口下输入getevent 调试命令,该命令会打出驱动上报的所有 input 事件,如果按遥控器有打印,并且键值正确,那说明是 android 响应的问题。

shell@rk3399:/ # getevent
 add device 1: /dev/input/event0
 name: "ff680000.pwm"
 /dev/input/event0: 0001 006c 00000001
 /dev/input/event0: 0000 0000 00000000
 /dev/input/event0: 0001 006c 00000000
 /dev/input/event0: 0000 0000 00000000

以上是在调试平台输入 getevent 的效果,最前面会列出所有的 input 设备,按的时候会上报事件,其中 0x6c 是上报的 linux 键值,后面的 1 代表按下,如果是 0 则代表弹起。