關(guān)鍵詞:android按鍵矩陣按鍵 AD按鍵
平臺(tái)信息:
內(nèi)核:linux2.6/linux3.0
系統(tǒng):android/android4.0
平臺(tái):S5PV310(samsungexynos4210)
一、硬件部分:
1、矩陣按鍵、IO按鍵、AD按鍵
這個(gè)知識(shí)相對(duì)來(lái)說(shuō)比較簡(jiǎn)單,不過(guò)上次真有一個(gè)網(wǎng)友不太清楚這個(gè)。所以這個(gè)基礎(chǔ)部分我們?cè)谶@里也說(shuō)一下。
(1)、矩陣按鍵
記得上大學(xué)時(shí)學(xué)單片機(jī)時(shí),這個(gè)矩陣按鍵還是個(gè)重點(diǎn)呢,上面的圖還是AT89S52的片子,工作原理比較簡(jiǎn)單,通過(guò)行、列來(lái)確定是那個(gè)按鍵按下,比如說(shuō)上圖標(biāo)號(hào)為1的鍵按下,IO(P1.7,P1.3)有電平變化,程序可以通過(guò)這里來(lái)判斷是那一個(gè)鍵按下的,同理標(biāo)號(hào)為2的按鍵按下IO(P1.4,P1.0)有電平變化。
這樣做程序上要從兩個(gè)IO來(lái)判斷是那個(gè)鍵按下,多了一個(gè)步驟,但是在硬件上有一個(gè)優(yōu)勢(shì),就是如果按鍵比較多的時(shí)候比較節(jié)省IO口,比如說(shuō)上面4x4= 16,8個(gè)IO可以做16個(gè)按鍵,8x8=64,16個(gè)IO可以做64個(gè)按鍵。
優(yōu)點(diǎn):可以用少的IO來(lái)做多個(gè)按鍵,判斷按鍵比較準(zhǔn)確;
缺點(diǎn):程序上相對(duì)IO按鍵來(lái)說(shuō)多了一步。
(2)、IO按鍵
這個(gè)就比較簡(jiǎn)單了,用一個(gè)IO口的高低電平來(lái)判斷按鍵是否按下。
優(yōu)點(diǎn):程序、硬件電路都比較簡(jiǎn)單,判斷按鍵比較準(zhǔn)確;
缺點(diǎn):IO有限、按鍵多時(shí)不太合適。比如矩陣按鍵16個(gè)IO可以表示64個(gè)按鍵,IO的話只有16個(gè)。
(3)、AD按鍵
這個(gè)在之前在做電視的時(shí)候用的比較多一點(diǎn)。
AD按鍵就是通過(guò)一個(gè)ADC接口,如下圖所示,給一個(gè)VCC電壓,比如說(shuō)S1接地時(shí)AD接口得到的模擬電壓值為ADC=0;當(dāng)S2按下時(shí),ADC= VCC/(R1+R2)*R2;這樣就可以得到不同的ADC值,程序中在這里判斷是那個(gè)按鍵按下。
優(yōu)點(diǎn):程序、硬件電路都比較簡(jiǎn)單,一個(gè)IO可以做多個(gè)按鍵;
缺點(diǎn):AD按鍵有時(shí)候判斷不準(zhǔn)確,所以在程序中要多加檢測(cè)AD值的次數(shù)。
2、S5PV310的矩陣按鍵
硬件原理圖如下:
硬件接口說(shuō)明:vol+,vol-,back,home,menu為1*5的矩陣鍵盤(pán),芯片接口信息如下:
行 | XGNSS_GPIO_3/KP_COL3 XGNSS_GPIO_4/KP_COL4 XGNSS_GPIO_5/KP_COL5 XGNSS_GPIO_6/KP_COL6 XGNSS_GPIO_7/KP_COL7 |
列 | XEINT17/KP_ROW1 |
我們這里1*5=5也沒(méi)有節(jié)省多少I(mǎi)O呀?情況是這樣的,我們的原理圖是從三星開(kāi)發(fā)板上參考過(guò)來(lái)的,開(kāi)發(fā)板上按鍵本來(lái)多一點(diǎn),可是我們用不了那么多,人家那樣做比較合理??墒俏覀儭巴祽小保布喜挥酶模浖弦膊挥酶?,從這一點(diǎn)也可以看出我們國(guó)內(nèi)做技術(shù)這個(gè)行業(yè)的有點(diǎn)……不太深入呀,整天老板在催,可是我們?cè)诩?xì)節(jié)上做不太好呀。三星在IO矩陣也有專用接口,所以就“奢侈”一次,用1*5的矩陣來(lái)實(shí)現(xiàn)5個(gè)按鍵。
3、S5PV310的矩陣按鍵接口
看一下芯片上的專用接口,如下圖,全用的話有點(diǎn)多。
關(guān)于專用接口的寄存器,這些寄存器我們后面要用得到的,按鍵的行、列信息會(huì)在這里面暫存的。
以S5PV310為例,驅(qū)動(dòng)代碼:samsung-keypad.c
軟件部分:
總體流程圖如下,這個(gè)是在觸摸屏基礎(chǔ)上改過(guò)來(lái)的,感覺(jué)流程都是這個(gè)樣子的。中斷觸發(fā),中斷處理。
一、矩陣鍵行、列設(shè)定,和上報(bào)鍵值設(shè)定
在android-kernel-samsung-dev/arch/arm/mach-exynos/mach-smdkv310.c中
[cpp]viewplaincopy- staticuint32_tsmdkv310_keymap[]__initdata={
- KEY(0,3,KEY_1),KEY(0,4,KEY_2),KEY(0,5,KEY_3),
- KEY(0,6,KEY_4),KEY(0,7,KEY_5),
- KEY(1,3,KEY_A),KEY(1,4,KEY_C),KEY(1,5,KEY_E),
- KEY(1,6,KEY_B),KEY(1,7,KEY_D)//(1)、鍵值初始化;
- };
- staticstructmatrix_keymap_datasmdkv310_keymap_data__initdata={
- .keymap=smdkv310_keymap,
- .keymap_size=ARRAY_SIZE(smdkv310_keymap),
- };
- staticstructsamsung_keypad_platdatasmdkv310_keypad_data__initdata={
- .keymap_data=&smdkv310_keymap_data,
- .rows=2,//(2)、行、列設(shè)定,8行、2列,其實(shí)我們只用了5行、1列;
- .cols=8,
- };
- staticvoid__initsmdkv310_machine_init(void)
- {
- samsung_keypad_set_platdata(&smdkv310_keypad_data);//(3)、平臺(tái)設(shè)備初始化;
- }
(1)、KEY(row, col,keycode)
KEY這個(gè)宏在android-kernel-samsung-dev/include/linux/input/Matrix_keypad.h中實(shí)現(xiàn):
[cpp]viewplaincopy- #defineMATRIX_MAX_ROWS32
- #defineMATRIX_MAX_COLS32
- #defineKEY(row,col,val)((((row)&(MATRIX_MAX_ROWS-1))<<24)|
- (((col)&(MATRIX_MAX_COLS-1))<<16)|
- ((val)&0xffff))
keycode的值在android-kernel-samsung-dev/include/linux/input.h中有定義,如下:
[cpp]viewplaincopy- #defineKEY_RESERVED0
- #defineKEY_ESC1
- #defineKEY_12
- #defineKEY_23
- #defineKEY_34
- #defineKEY_45
- #defineKEY_56
- #defineKEY_67
- #defineKEY_78
- #defineKEY_89
- #defineKEY_910
- #defineKEY_011
- #defineKEY_MINUS12
- #defineKEY_EQUAL13
- #defineKEY_BACKSPACE14
- #defineKEY_TAB15
- #defineKEY_Q16
- #defineKEY_W17
- #defineKEY_E18
- #defineKEY_R19
- #defineKEY_T20
- #defineKEY_Y21
- #defineKEY_U22
(2)、行列設(shè)定;
[cpp]viewplaincopy- .rows=2,
- .cols=8,
(3)、平臺(tái)設(shè)備初始化;
[cpp]viewplaincopy- samsung_keypad_set_platdata(&smdkv310_keypad_data)。
二、上面設(shè)定的keycode鍵值和上層相對(duì)應(yīng)
4.0.3_r1/device/samsung/smdkv310/samsung-keypad.kl中
[cpp]viewplaincopy- key2DPAD_UPWAKE_DROPPED
- key3DPAD_CENTERWAKE_DROPPED
- key4DPAD_DOWNWAKE_DROPPED
- key5DPAD_RIGHTWAKE_DROPPED
- key6DPAD_LEFTWAKE_DROPPED
- key18VOLUME_DOWNWAKE
- key30HOMEWAKE_DROPPED
- key32MENUWAKE_DROPPED
- key46VOLUME_UPWAKE
- key48BACKWAKE_DROPPED
- key10POWERWAKE
總體對(duì)應(yīng)圖:
以KEY_A為例,KEY_A30最終和上層的keypad.kl中的30 HOME相對(duì)應(yīng)
三、矩陣鍵盤(pán)驅(qū)動(dòng)程序分析
android-kernel-samsung-dev/drivers/input/keyboard/samsung-keypad.c
1、probe函數(shù)分析:
[cpp]viewplaincopy- staticint__devinitsamsung_keypad_probe(structplatform_device*pdev)
- {
- conststructsamsung_keypad_platdata*pdata;
- conststructmatrix_keymap_data*keymap_data;
- structsamsung_keypad*keypad;
- structresource*res;
- structinput_dev*input_dev;
- unsignedintrow_shift;
- unsignedintkeymap_size;
- interror;
- ………………
- keymap_size=(pdata->rows<<row_shift)*sizeof(keypad->keycodes[0]);
- keypad=kzalloc(sizeof(*keypad)+keymap_size,GFP_KERNEL);
- input_dev=input_allocate_device();
- if(!keypad||!input_dev){
- error=-ENOMEM;
- gotoerr_free_mem;
- }
- res=platform_get_resource(pdev,IORESOURCE_MEM,0);
- if(!res){
- error=-ENODEV;
- gotoerr_free_mem;
- }
- keypad->base=ioremap(res->start,resource_size(res));
- if(!keypad->base){
- error=-EBUSY;
- gotoerr_free_mem;
- }
- …………
- //(1)、input參數(shù)初始化;
- keypad->input_dev=input_dev;
- keypad->row_shift=row_shift;
- keypad->rows=pdata->rows;
- keypad->cols=pdata->cols;
- init_waitqueue_head(&keypad->wait);
- input_dev->name=pdev->name;
- input_dev->id.bustype=BUS_HOST;
- input_dev->dev.parent=&pdev->dev;
- input_set_drvdata(input_dev,keypad);
- //(2)、打開(kāi)、關(guān)閉函數(shù);
- input_dev->open=samsung_keypad_open;
- input_dev->close=samsung_keypad_close;
- input_dev->evbit[0]=BIT_MASK(EV_KEY);
- if(!pdata->no_autorepeat)
- input_dev->evbit[0]|=BIT_MASK(EV_REP);
- input_set_capability(input_dev,EV_MSC,MSC_SCAN);
- input_dev->keycode=keypad->keycodes;
- input_dev->keycodesize=sizeof(keypad->keycodes[0]);
- input_dev->keycodemax=pdata->rows<<row_shift;
- matrix_keypad_build_keymap(keymap_data,row_shift,
- input_dev->keycode,input_dev->keybit);
- keypad->irq=platform_get_irq(pdev,0);
- if(keypad->irq<0){
- error=keypad->irq;
- gotoerr_put_clk;
- }
- //(3)、中斷函數(shù)注冊(cè);
- error=request_threaded_irq(keypad->irq,NULL,samsung_keypad_irq,
- IRQF_ONESHOT,dev_name(&pdev->dev),keypad);
- if(error){
- dev_err(&pdev->dev,"failedtoregisterkeypadinterruptn");
- gotoerr_put_clk;
- }
- //(4)、input驅(qū)動(dòng)注冊(cè)。
- error=input_register_device(keypad->input_dev);
- if(error)
- gotoerr_free_irq;
- device_init_wakeup(&pdev->dev,pdata->wakeup);
- platform_set_drvdata(pdev,keypad);
- return0;
- ………………
- }
(1)、input參數(shù)初始化;
(2)、打開(kāi)、關(guān)閉函數(shù);
[cpp]viewplaincopy- input_dev->open=samsung_keypad_open;
- staticintsamsung_keypad_open(structinput_dev*input_dev)
- {
- structsamsung_keypad*keypad=input_get_drvdata(input_dev);
- samsung_keypad_start(keypad);
- return0;
- }
- 其實(shí)open函數(shù)調(diào)用samsung_keypad_start()函數(shù),對(duì)按鍵的寄存器一些操作,如下面寄存器列表中的。
- staticvoidsamsung_keypad_start(structsamsung_keypad*keypad)
- {
- unsignedintval;
- keypad->stopped=false;
- clk_enable(keypad->clk);
- val=readl(keypad->base+SAMSUNG_KEYIFCON);
- val|=SAMSUNG_KEYIFCON_INT_F_EN|SAMSUNG_KEYIFCON_INT_R_EN;
- writel(val,keypad->base+SAMSUNG_KEYIFCON);
- writel(0,keypad->base+SAMSUNG_KEYIFCOL);
- }
(3)、中斷函數(shù)注冊(cè);
[cpp]viewplaincopy- error=request_threaded_irq(keypad->irq,NULL,samsung_keypad_irq,IRQF_ONESHOT,dev_name(&pdev->dev),keypad);
request_threaded_irq這個(gè)函數(shù)也許我們比較陌生,可是看下下面一個(gè)函數(shù)也許就不難理解了:
[cpp]viewplaincopy- staticinlineint__must_check
- request_irq(unsignedintirq,irq_handler_thandler,unsignedlongflags,
- constchar*name,void*dev)
- {
- returnrequest_threaded_irq(irq,handler,NULL,flags,name,dev);
- }
(4)、input驅(qū)動(dòng)注冊(cè),input驅(qū)動(dòng)比較重要,觸摸屏、按鍵、gsensor、battery等都是通過(guò)input子系統(tǒng)上報(bào)的。
2、中斷函數(shù):samsung_keypad_irq分析,當(dāng)有按鍵按下時(shí),調(diào)用這個(gè)函數(shù)
[cpp]viewplaincopy- staticirqreturn_tsamsung_keypad_irq(intirq,void*dev_id)
- {
- structsamsung_keypad*keypad=dev_id;
- unsignedintrow_state[SAMSUNG_MAX_COLS];
- unsignedintval;
- boolkey_down;
- do{
- val=readl(keypad->base+SAMSUNG_KEYIFSTSCLR);
- //(1)、清除中斷;
- writel(~0x0,keypad->base+SAMSUNG_KEYIFSTSCLR);
- //(2)、掃描行列值,寫(xiě)入寄存器;
- samsung_keypad_scan(keypad,row_state);
- //(3)、鍵值上報(bào),這是函數(shù)的主要部分了;
- key_down=samsung_keypad_report(keypad,row_state);
- //(4)、延時(shí)去抖動(dòng);
- if(key_down)
- wait_event_timeout(keypad->wait,keypad->stopped,
- msecs_to_jiffies(50));
- }while(key_down&&!keypad->stopped);
- returnIRQ_HANDLED;
- }
(1)、清除中斷;
(2)、掃描行列值,寫(xiě)入寄存器(后面分析);
(3)、鍵值上報(bào),這是函數(shù)的主要部分了(后面分析);
(4)、延時(shí)去抖動(dòng),如果有按鍵按下,有一個(gè)段時(shí)間的延時(shí),看是否真正有按鍵,這就是所說(shuō)的去抖動(dòng);
3、當(dāng)按鍵按下時(shí),行列值的掃描函數(shù)samsung_keypad_scan執(zhí)行,寫(xiě)入相應(yīng)行列寄存器
上圖我們知道,對(duì)于矩陣鍵盤(pán),主控有專門(mén)的接口,也有相應(yīng)的寄存器,
[cpp]viewplaincopy- staticvoidsamsung_keypad_scan(structsamsung_keypad*keypad,
- unsignedint*row_state)
- {
- structdevice*dev=keypad->input_dev->dev.parent;
- unsignedintcol;
- unsignedintval;
- for(col=0;col<keypad->cols;col++){
- if(samsung_keypad_is_s5pv210(dev)){
- val=S5PV210_KEYIFCOLEN_MASK;
- val&=~(1<<col)<<8;
- }else{
- val=SAMSUNG_KEYIFCOL_MASK;
- val&=~(1<<col);
- }
- writel(val,keypad->base+SAMSUNG_KEYIFCOL);
- mdelay(1);
- val=readl(keypad->base+SAMSUNG_KEYIFROW);
- row_state[col]=~val&((1<<keypad->rows)-1);
- }
- writel(0,keypad->base+SAMSUNG_KEYIFCOL);
- }
4、通過(guò)掃描鍵值寫(xiě)入相應(yīng)寄存器,然后通過(guò)
[cpp]viewplaincopy- staticboolsamsung_keypad_report(structsamsung_keypad*keypad,
- unsignedint*row_state)
- {
- structinput_dev*input_dev=keypad->input_dev;
- unsignedintchanged;
- unsignedintpressed;
- unsignedintkey_down=0;
- unsignedintval;
- unsignedintcol,row;
- for(col=0;col<keypad->cols;col++){
- changed=row_state[col]^keypad->row_state[col];
- key_down|=row_state[col];
- if(!changed)
- continue;
- for(row=0;row<keypad->rows;row++){
- if(!(changed&(1<<row)))
- continue;
- pressed=row_state[col]&(1<<row);
- dev_dbg(&keypad->input_dev->dev,
- "key%s,row:%d,col:%dn",
- pressed?"pressed":"released",row,col);
- //(1)、得到按鍵在矩陣中的位置;
- val=MATRIX_SCAN_CODE(row,col,keypad->row_shift);
- printk("key%s,row:%d,col:%dn",pressed?"pressed":"released",row,col);
- printk("testbyxu_binforval=%d,key=%dn",val,keypad->keycodes[val]);
- input_event(input_dev,EV_MSC,MSC_SCAN,val);
- //(2)、上報(bào)鍵值keypad->keycodes[val];
- input_report_key(input_dev,
- keypad->keycodes[val],pressed);
- }
- //(3)、input上報(bào)后同步;
- input_sync(keypad->input_dev);
- }
- memcpy(keypad->row_state,row_state,sizeof(keypad->row_state));
- returnkey_down;
- }
(1)、#defineMATRIX_SCAN_CODE(row, col, row_shift) (((row)<<(row_shift)) + (col))
row_shift = 3
如:row = 1; col = 6; row_shift= 3
val = MATRIX_SCAN_CODE(row,col,keypad->row_shift) = ((1)<<(3)+(6)) = 14;
就相當(dāng)于:(1,6)這個(gè)數(shù)組里面的值:48
printk("key %s, row: %d,col:%dn",pressed ? "pressed" : "released", row, col);
printk("test by xu_bin forval =%d,key = %dn",val,keypad->keycodes[val]);
(2)、上報(bào)鍵值keypad->keycodes[val],這個(gè)值是對(duì)于我們這個(gè)驅(qū)動(dòng)來(lái)說(shuō)的最終值;
(3)、input上報(bào)后同步,這個(gè)和input子系統(tǒng)相關(guān)。
這樣就完成了驅(qū)動(dòng)部分的上報(bào)。
愛(ài)華網(wǎng)本文地址 » http://www.klfzs.com/a/25101017/339477.html
愛(ài)華網(wǎng)



