简述多个AD按键使用双通道实现

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)

你可能感兴趣的:(驱动)