<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 觸摸屏驅動程序(輸入子系統(tǒng))

          觸摸屏驅動程序(輸入子系統(tǒng))

          作者: 時間:2016-11-21 來源:網(wǎng)絡 收藏
          #include "linux/errno.h"
          #include"linux/kernel.h"
          #include"linux/module.h"
          #include"linux/slab.h"
          #include"linux/input.h"
          #include"linux/init.h"
          #include"linux/serio.h"
          #include"linux/delay.h"
          #include"linux/platform_device.h"
          #include"linux/clk.h"
          #include"asm/io.h"
          #include"asm/irq.h"
          #include"asm/plat-s3c24xx/ts.h"
          #include"asm/arch/regs-adc.h"
          #include"asm/arch/regs-gpio.h"
          struct s3c_ts_regs {
          unsigned long adccon;
          unsigned long adctsc;
          unsigned long adcdly;
          unsigned long adcdat0;
          unsigned long adcdat1;
          unsigned long adcupdn;
          };
          static struct input_dev *s3c_ts_dev;
          static volatile struct s3c_ts_regs *s3c_ts_regs;
          static struct timer_list ts_timer;
          //等到觸控筆按下模式
          static void enter_wait_pen_down_mode(void)
          {
          s3c_ts_regs->adctsc = 0xd3;
          }
          //等到觸控筆松開模式
          static void enter_wait_pen_up_mode(void)
          {
          s3c_ts_regs->adctsc = 0x1d3;
          }
          //進入X/Y方向ADC同時轉換模式
          static void enter_measure_xy_mode(void)
          {
          s3c_ts_regs->adctsc = (1<<3)|(1<<2);
          }
          //啟動ADC轉換
          static void start_adc(void)
          {
          s3c_ts_regs->adccon |= (1<<0);
          }
          static int s3c_filter_ts(int x[], int y[])
          {
          #define ERR_LIMIT 10
          int avr_x, avr_y;
          int det_x, det_y;
          avr_x = (x[0] + x[1])/2;
          avr_y = (y[0] + y[1])/2;
          det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);
          det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);
          if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
          return 0;
          avr_x = (x[1] + x[2])/2;
          avr_y = (y[1] + y[2])/2;
          det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);
          det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]);
          if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
          return 0;
          return 1;
          }
          static void s3c_ts_timer_function(unsigned long data)
          {
          if (s3c_ts_regs->adcdat0 & (1<<15))
          {
          // 已經(jīng)松開
          input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
          input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
          input_sync(s3c_ts_dev);
          enter_wait_pen_down_mode();
          }
          else
          {
          // 測量X/Y坐標
          enter_measure_xy_mode();
          start_adc();
          }
          }
          //觸控筆按下、抬起中斷服務函數(shù)
          static irqreturn_t pen_down_up_irq(int irq, void *dev_id)
          {
          if (s3c_ts_regs->adcdat0 & (1<<15))
          {
          //printk("pen upn");
          input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
          input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
          input_sync(s3c_ts_dev);
          enter_wait_pen_down_mode();
          }
          else
          {
          //printk("pen downn");
          //enter_wait_pen_up_mode();
          enter_measure_xy_mode();
          start_adc();
          }
          return IRQ_HANDLED;
          }
          static irqreturn_t adc_irq(int irq, void *dev_id)
          {
          static int cnt = 0;
          static int x[4], y[4];
          int adcdat0, adcdat1;
          // 優(yōu)化措施2: 如果ADC完成時, 發(fā)現(xiàn)觸摸筆已經(jīng)松開, 則丟棄此次結果
          adcdat0 = s3c_ts_regs->adcdat0;
          adcdat1 = s3c_ts_regs->adcdat1;
          if (s3c_ts_regs->adcdat0 & (1<<15))
          {
          // 已經(jīng)松開
          cnt = 0;
          input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
          input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
          input_sync(s3c_ts_dev);
          enter_wait_pen_down_mode();
          }
          else
          {
          // printk("adc_irq cnt = %d, x = %d, y = %dn", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);
          // 優(yōu)化措施3: 多次測量求平均值
          x[cnt] = adcdat0 & 0x3ff;
          y[cnt] = adcdat1 & 0x3ff;
          ++cnt;
          if (cnt == 4)
          {
          // 優(yōu)化措施4: 軟件過濾
          if (s3c_filter_ts(x, y))
          {
          //printk("x = %d, y = %dn", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4);
          input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);
          input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);
          input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);
          input_report_key(s3c_ts_dev, BTN_TOUCH, 1);
          input_sync(s3c_ts_dev);
          }
          cnt = 0;
          enter_wait_pen_up_mode();
          // 啟動定時器處理長按/滑動的情況
          mod_timer(&ts_timer, jiffies + HZ/100);
          }
          else
          {
          enter_measure_xy_mode();
          start_adc();
          }
          }
          return IRQ_HANDLED;
          }
          static int s3c_ts_init(void)
          {
          struct clk* clk;
          // 1. 分配一個input_dev結構體
          s3c_ts_dev = input_allocate_device();
          // 2. 設置
          // 2.1 能產(chǎn)生哪類事件
          set_bit(EV_KEY, s3c_ts_dev->evbit); //按鍵類事件
          set_bit(EV_ABS, s3c_ts_dev->evbit); //絕對位移類事件
          // 2.2 能產(chǎn)生這類事件里的哪些事件
          set_bit(BTN_TOUCH, s3c_ts_dev->keybit);
          input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
          input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
          input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);//按壓力度:1表示按下、0松開
          // 3. 注冊
          input_register_device(s3c_ts_dev);
          // 4. 硬件相關的操作
          //4.1 使能時鐘(CLKCON[15])
          clk = clk_get(NULL, "adc");
          clk_enable(clk);
          // 4.2 設置S3C2440的ADC/TS寄存器
          s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));
          //bit[14] : 1-A/D converter prescaler enable
          * bit[13:6]: A/D converter prescaler value,
          * 49, ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz
          * bit[0]: A/D conversion starts by enable. 先設為0
          //
          s3c_ts_regs->adccon = (1<<14)|(49<<6);
          request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);
          request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);
          // 優(yōu)化措施1:
          // 設置ADCDLY為最大值, 這使得電壓穩(wěn)定后再發(fā)出IRQ_TC中斷
          s3c_ts_regs->adcdly = 0xffff;
          //優(yōu)化措施5: 使用定時器處理長按,滑動的情況
          init_timer(&ts_timer);
          ts_timer.function = s3c_ts_timer_function;
          add_timer(&ts_timer);
          enter_wait_pen_down_mode();
          return 0;
          }
          static void s3c_ts_exit(void)
          {
          free_irq(IRQ_TC, NULL);
          free_irq(IRQ_ADC, NULL);
          iounmap(s3c_ts_regs);
          input_unregister_device(s3c_ts_dev);
          input_free_device(s3c_ts_dev);
          del_timer(&ts_timer);
          }
          module_init(s3c_ts_init);
          module_exit(s3c_ts_exit);
          MODULE_LICENSE("GPL");
          ================================================================
          解析:
          加載驅動以后運行s3c_ts_init函數(shù),程序進入等待觸控筆按下模式enter_wait_pen_down_mode(),當有觸控筆按下時進入按下中斷服務函數(shù)中運行,即pen_down_up_irq中,進入中斷服務函數(shù)后立即判斷觸控筆是否依然按下,如果這個時候觸控筆已經(jīng)松開則上報事件;若此時觸控筆依然按下則進入X/Y雙方向同時進行ADC轉換模式,并啟動ADC轉換。當ADC轉換完成以后進入ADC中斷服務程序,從adcdat0、adcdat1獲取到x方向、y方向的ADC數(shù)據(jù),再判斷觸控筆是否離開,如果已經(jīng)離開則進行上報數(shù)據(jù);否則保存此次ADC轉換數(shù)據(jù)再判斷ADC采集到的數(shù)據(jù)有沒有到4次,如果累計到4次則進行軟件濾波后上報事件,進入等待觸控筆離開模式enter_wait_pen_up_mode,同時啟動定時器開始計時處理連續(xù)按壓事件;如果不夠4次則再次進入X/Y雙方向同時進行ADC轉換模式,并啟動ADC轉換。當定時時間到了以后進入定時中斷服務函數(shù)里,判斷觸控筆是否離開,如果觸控筆松開則上報事件,進入等待觸控筆按下模式,否則再次進入X/Y雙方向同時進行ADC轉換模式,并啟動ADC轉換。依次!
          測試2th~7th:
          1. make menuconfig 去掉原來的觸摸屏驅動程序
          -> Device Drivers
          -> Input device support
          -> Generic input layer
          -> Touchscreens
          <> S3C2410/S3C2440 touchscreens
          make uImage
          使用新內核啟動
          2. insmod s3c_ts.ko
          按下/松開觸摸筆
          測試2th~7th:
          1. ls /dev/event*
          2. insmod s3c_ts.ko
          3. ls /dev/event*
          4. hexdump /dev/event0
          微秒 type code value
          0000000 29a4 0000 8625 0008 0003 0000 0172 0000
          0000010 29a4 0000 8631 0008 0003 0001 027c 0000
          0000020 29a4 0000 8634 0008 0003 0018 0001 0000
          0000030 29a4 0000 8638 0008 0001 014a 0001 0000
          0000040 29a4 0000 863c 0008 0000 0000 0000 0000
          0000050 29a4 0000 c85e 0008 0003 0000 0171 0000
          0000060 29a4 0000 c874 0008 0003 0001 027d 0000
          0000070 29a4 0000 c87b 0008 0000 0000 0000 0000
          0000080 29a4 0000 ed37 0008 0003 0018 0000 0000
          0000090 29a4 0000 ed48 0008 0001 014a 0000 0000
          00000a0 29a4 0000 ed4a 0008 0000 0000 0000 0000
          lcd和觸摸屏聯(lián)合使用參考”tslib編譯使用方法“
          //暫時忽略下面三行命令
          //sudo apt-get install autoconf
          //sudo apt-get install automake
          //sudo apt-get install libtool
          編譯:
          tar xzf tslib-1.4.tar.gz
          cd tslib
          ./autogen.sh
          mkdir tmp
          echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache
          ./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp
          make
          make install //安裝到tmp目錄
          安裝:
          cd tmp
          再把tmp目錄下的4個文件全都拷貝到開發(fā)板的根目錄下
          cp * /home/book/workspace/JZ2440_TestFile/system/first_fs-rfd
          (采用網(wǎng)絡文件系統(tǒng)啟動時開發(fā)板的根目錄,但是此時并沒有拷貝到開發(fā)板的flash上面,如果要拷貝到開發(fā)板的flash上面可以不用網(wǎng)絡文件系統(tǒng)啟動,采用手動掛載的方式把文件系統(tǒng)掛載到開發(fā)板的mnt目錄下,在從mnt目錄下把tmp里的文件拷貝到開發(fā)板的根目錄下面,這樣就算真正的在開發(fā)板的flash上面了。)
          使用:
          先安裝s3c_ts.ko, lcd.ko
          1.
          修改 /etc/ts.conf第1行(去掉#號和第一個空格):
          # module_raw input
          改為:
          module_raw input
          2.設置環(huán)境變量
          export TSLIB_TSDEVICE=/dev/event0
          export TSLIB_CALIBFILE=/etc/pointercal
          export TSLIB_CONFFILE=/etc/ts.conf
          export TSLIB_PLUGINDIR=/lib/ts
          export TSLIB_CONSOLEDEVICE=none
          export TSLIB_FBDEVICE=/dev/fb0
          使用以下兩個命令進行測試:
          ts_calibrate
          ts_test




          評論


          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();