AD按键多,单通道实现易窜键,这时候可以考虑使用双通道实现。
原理:
本质还是单通道的实现方法,由于单条通道的采样不会大于1023,所以将二条通道上面的按键AD值都增加1000,一通道的按键遍历完成后,才轮到二通道的按键进行遍历,这样就实现了双通道按键。
本文使用的平台是RK的3126 Android5.1的SDK,先了解单通道AD按键是如何实现的。
&adc {
status = "okay";
key: key {
compatible = "rockchip,key";
io-channels = <&adc 1>;
vol-up-key {
linux,code = <115>;
label = "volume up";
rockchip,adc_value = <142>;
};
vol-down-key {
linux,code = <114>;
label = "volume down";
rockchip,adc_value = <1>;
};
……};
};
&key {
io-channels = <&adc 2>;
power-key {
gpios = <&gpio1 GPIO_A4 GPIO_ACTIVE_LOW>;
linux,code = <116>;
label = "power";
gpio-key,wakeup;
};
};
DTS里按键的配置,rockchip,adc_value按键设置的AD值,linux,code上报给系统的按键键值。
chan = iio_channel_get(&pdev->dev, NULL);
pdata->chan = chan;
配置采样通道
static int rk_key_adc_iio_read(struct rk_keys_drvdata *data)
{
struct iio_channel *channel = data->chan;
int val, ret;
if (!channel)
return INVALID_ADVALUE;
ret = iio_read_channel_raw(channel, &val);
if (ret < 0)
{
pr_err("read channel() error: %d\n", ret);
return ret;
}
return val;
}
result = rk_key_adc_iio_read(ddata);
获取通道的AD值。
struct rk_keys_button {
u32 type; //TYPE_GPIO, TYPE_ADC
u32 code; // key code
int code_long_press;
const char *desc;//key label
u32 state; //key up & down state
int gpio; //gpio only
int adc_value; //adc only
int adc_state; //adc only
int active_low;//gpio only
int wakeup; //gpio only
int long_press_count;
int pressFlag;
int lednum;
struct timer_list timer;
};
struct rk_keys_button *button = &ddata->button[i];
adc_value是按键的AD值。ddata->button[i]通过DTS的解析进行赋值得到。
#define DRIFT_ADVALUE 70
if(result < button->adc_value + DRIFT_ADVALUE && result > button->adc_value - DRIFT_ADVALUE)
{
}
判断button,如果获取到的ad值处于button->adc_value-70、button->adc_value+70的区间里,则判断按下的按键为当前的button。
在上面单通道的基础来实现双通道按键。
硬件上需要多拉出一个通道,单通道的时候是SARADC_CH1,双通道为SARADC_CH0、SARADC_CH1
&adc {
status = "okay";
key: key {
compatible = "rockchip,key";
io-channels = <&adc 1>;
vol-up-key {
linux,code = <115>;
label = "volume up";
rockchip,adc_value = <142>;
};
vol-down-key {
linux,code = <114>;
label = "volume down";
rockchip,adc_value = <1>;
};
……
/*二通道的按键配置*/
pre-key {
linux,code = <165>;
label = "pre";
rockchip,adc_value = <1003>;
};
next-key {
linux,code = <163>;
label = "next";
rockchip,adc_value = <1499>;
};
……
};
};
&key {
io-channels = <&adc 2>,<&adc 0>;
io-channel-names = "adc2", "adc0";
power-key {
gpios = <&gpio1 GPIO_A4 GPIO_ACTIVE_LOW>;
linux,code = <116>;
label = "power";
gpio-key,wakeup;
};
};
rockchip,adc_value = <1003>和 rockchip,adc_value = <1499>分别是pre-key和next-key配置的AD值,实际上在二通道里检测到的pre-key和next-key按下的AD值是3和499,在这里要增加1000。io-channels = <&adc 2>,<&adc 0>; io-channel-names = “adc2”, “adc0”;增加了ADC0这个通道为二通通道。第二通道的按键配置必须置于第一通道的按键配置下面,至于原因,后面会提到。
chan = iio_channel_get(&pdev->dev, NULL);
if (IS_ERR(chan)) {
dev_info(&pdev->dev, "no io-channels defined\n");
chan = NULL;
}
pdata->chan = chan;
chan = iio_channel_get(&pdev->dev, "adc0");
if (IS_ERR(chan)) {
dev_info(&pdev->dev, "no io-channels defined\n");
chan = NULL;
}
pdata->chan0 = chan;
配置采样通道
static int rk_key_adc_iio_read(struct rk_keys_drvdata *data)
{
struct iio_channel *channel = data->chan;
int val, ret;
if (!channel)
return INVALID_ADVALUE;
ret = iio_read_channel_raw(channel, &val);
if (ret < 0)
{
pr_err("read channel() error: %d\n", ret);
return ret;
}
return val;
}
static int rk_key_adc_iio_read000(struct rk_keys_drvdata *data)
{
struct iio_channel *channel = data->chan0;
int val, ret;
if (!channel)
return INVALID_ADVALUE;
ret = iio_read_channel_raw(channel, &val);
if (ret < 0) {
pr_err("read channel() error: %d\n", ret);
return ret;
}
return val;
}
获取两个通道上的AD值
result = rk_key_adc_iio_read(ddata);
for (i = 0; i < ddata->nbuttons; i++)
{
......
if(button->adc_value>1000)
break;
......
}
获取一通道上AD值,由于DTS里面第二通道 rockchip,adc_value设置的值都大于1000且在DTS都根据rockchip,adc_value从小到大排序来配置,当button->adc_value>1000为true,说明一通道上的按键完成遍历。
result = rk_key_adc_iio_read000(ddata);
for (; i < ddata->nbuttons; i++) {
……
if(result +1000< button->adc_value + DRIFT_ADVALUE && result +1000> button->adc_value - DRIFT_ADVALUE)
{
}
……
}
获取二通道上的AD值。上面一通道遍历完成后,省下来的就全部是二通道的按键。由于二通道按键的 rockchip,adc_value在DTS被故意增加1000以用来区分按键来自不同的通道,所以判断具体是哪个按键的时候,才二通道采样到的AD值也需要增加1000(result
+1000)