历史上的今天
返回首页

历史上的今天

今天是:2024年10月11日(星期五)

正在发生

2018年10月11日 | OK6410触摸屏驱动

2018-10-11 来源:eefocus

ts.c源码:

#include "linux/module.h"

#include "linux/init.h"

#include "linux/fs.h"

#include "linux/interrupt.h"

#include "linux/irq.h"

#include "linux/sched.h"

#include "linux/pm.h"

#include "linux/sysctl.h"

#include "linux/proc_fs.h"

#include "linux/delay.h"

#include "linux/platform_device.h"

#include "linux/input.h"

#include "linux/io.h"

#include "linux/clk.h"

#include "linux/delay.h"

static struct timer_list ts_timer;

static struct input_dev *ts_dev;

struct adc_regs {

    unsigned long adccon;

    unsigned long adctsc;

    unsigned long adcdly;

    unsigned long adcdat0;

    unsigned long adcdat1;

    unsigned long adcupdn;

    unsigned long adcclrint;

    unsigned long reserved;

    unsigned long adcclrintpndnup;

};

static struct adc_regs *adc_regs;

static void enter_wait_for_pen_down(void)

{

    adc_regs->adctsc = 0xd3;

}

static void enter_wait_for_pen_up(void)

{

    adc_regs->adctsc = 0x1d3;

}

static void enter_measure_xy_mode(void)

{

    adc_regs->adctsc = ((1<<7) | (1<<6) | (1<<4) | (1<<3) | (1<<2));

}

static void start_adc(void)

{

    adc_regs->adccon |= (1<<0);

}

static irqreturn_t ts_pen_down_up_isr(int irq, void *dev_id)

{

    unsigned long data0, data1;

    int down;

    data0 = adc_regs->adcdat0;

    data1 = adc_regs->adcdat1;

    down = (!(data0 & (1<<15))) && (!(data1 & (1<<15)));

    

    if (!down)

    {

        //printk("pen up\n");

        enter_wait_for_pen_down();

        // 调用evdev_event: 保存,唤醒 

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);

        input_sync(ts_dev);

    }

    else

    {

        //printk("pen down\n");

        //enter_wait_for_pen_up();

        // 进入"自动测量x/y座标模式" 

        enter_measure_xy_mode();

        

        // 启动ADC 

        start_adc();

    }

    adc_regs->adcupdn   = 0;

    adc_regs->adcclrint = 0;

    adc_regs->adcclrintpndnup = 0;

    return IRQ_HANDLED;

}

static irqreturn_t adc_isr(int irq, void *dev_id)

{

    // 为何不在这里立刻处理ADC到结果?

    // 因为6410的ADC有个缺点: 

    // 当ADC刚完成时, 必须等待若干ms, 

    // 才能读取adcdat0,adcdata1来判断

    // 当前的触摸屏是被按下还是松开

    // 启动定时器, 是为了不在中断处理函数里等待 

    mod_timer(&ts_timer, jiffies + HZ/100);

    enter_wait_for_pen_up();

    adc_regs->adcupdn   = 0;

    adc_regs->adcclrint = 0;

    adc_regs->adcclrintpndnup = 0;

    return IRQ_HANDLED;

}

static irqreturn_t adc_isr_ok_old(int irq, void *dev_id)

{

    int x,y;

    int adcdat0,adcdat1;

    int down;

#if 1 // in auto xy mode, after adc interrupt, have to wait several ms to test up/down  

    udelay(1000);

    udelay(1000);

    udelay(1000);

    udelay(1000);

#endif

    adcdat0 = adc_regs->adcdat0;

    adcdat1 = adc_regs->adcdat1;

    x = adcdat0 & 0xfff;

    y = adcdat1 & 0xfff;

    

    down = (!(adcdat0 & (1<<15))) && (!(adcdat1 & (1<<15)));

    //printk("adcdat0 = 0x%x, adc_dat1 = 0x%x\n", adcdat0, adcdat1);

    if (down)

    {

        //printk("enter_wait_for_pen_up\n");

        enter_wait_for_pen_up();

        //printk("x = %d, y = %d\n", x, y);

        input_event(ts_dev, EV_ABS, ABS_X, x);

        input_event(ts_dev, EV_ABS, ABS_Y, y);

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 1);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 1);

        input_sync(ts_dev);

        // 启动定时器 

        mod_timer(&ts_timer, jiffies + HZ/100);

    }

    else

    {

        //printk("enter_wait_for_pen_down\n");

        enter_wait_for_pen_down();

        

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);

        input_sync(ts_dev);

    }

    adc_regs->adcupdn   = 0;

    adc_regs->adcclrint = 0;

    adc_regs->adcclrintpndnup = 0;

    return IRQ_HANDLED;

}

static void ts_timer_function_ok_old(unsigned long data)

{

    // 如果触摸笔已经松开, 就没必要再次启动ADC 

    // 否则, 启动ADC 

    unsigned long data0, data1;

    int down;

    data0 = adc_regs->adcdat0;

    data1 = adc_regs->adcdat1;

    down = (!(data0 & (1<<15))) && (!(data1 & (1<<15)));

    

    if (down)

    {

        enter_measure_xy_mode();

        start_adc();

    }

    else

    {

        enter_wait_for_pen_down();

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);

        input_sync(ts_dev);

    }

}

static void ts_timer_function(unsigned long data)

{

    // 如果触摸笔已经松开, 就没必要再次启动ADC 

    // 否则, 启动ADC 

    unsigned long data0, data1;

    int down;

    int x, y;

    data0 = adc_regs->adcdat0;

    data1 = adc_regs->adcdat1;

    down = (!(data0 & (1<<15))) && (!(data1 & (1<<15)));

    if (down)

    {

        x = data0 & 0xfff;

        y = data1 & 0xfff;

        input_event(ts_dev, EV_ABS, ABS_X, x);

        input_event(ts_dev, EV_ABS, ABS_Y, y);

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 1);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 1);

        input_sync(ts_dev);

        

        enter_measure_xy_mode();

        start_adc();

    }

    else

    {

        enter_wait_for_pen_down();

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);

        input_sync(ts_dev);

    }

}

static int ts_init(void)

{

    struct clk *clk;

    // 1. 分配input_dev 

    ts_dev = input_allocate_device();

    

    // 2. 设置 

    // 2.1 能产生哪类事件 

    set_bit(EV_KEY, ts_dev->evbit);

    set_bit(EV_ABS, ts_dev->evbit);

    

    // 2.2 能产生这类事件里的哪些事件 

    set_bit(BTN_TOUCH, ts_dev->keybit);

    input_set_abs_params(ts_dev, ABS_X, 0, 0xfff, 0, 0);

    input_set_abs_params(ts_dev, ABS_Y, 0, 0xfff, 0, 0);

    input_set_abs_params(ts_dev, ABS_PRESSURE, 0, 1, 0, 0);

    

    // 3. 注册 

    input_register_device(ts_dev);

    

    // 4. 硬件相关 

    adc_regs = ioremap(0x7E00B000, sizeof(struct adc_regs));

    clk = clk_get(NULL, "adc");

    clk_enable(clk);  // PCLK_GATE[12]设为1 

    // bit[16]   : 1 = 12-bit A/D conversion

    // bit[14]   : 1 - enable A/D converter prescaler enable

    // bit[13:6] : A/D converter prescaler value,

    //             PCLK=66500000, adcclk=pclk/(n+1)

    //             取值13, adclk=66.5MHz/14=4.75

     

    adc_regs->adccon = (1<<16) | (1<<14) | (65<<6);

    adc_regs->adcdly = 0xffff;

    adc_regs->adcclrintpndnup = 0;

    request_irq(IRQ_TC, ts_pen_down_up_isr, IRQF_SHARED, "pen_down_up", 1);

    request_irq(IRQ_ADC, adc_isr, IRQF_SHARED, "adc", 1);

    init_timer(&ts_timer);

    ts_timer.expires  = 0;

    ts_timer.function = ts_timer_function;

    add_timer(&ts_timer);

    // 进入"wait for interrupt mode", 等待触摸笔按下或松开的模式 

    enter_wait_for_pen_down();

    return 0;

}

static void ts_exit(void)

{

    del_timer(&ts_timer);

    free_irq(IRQ_TC, 1);

    free_irq(IRQ_ADC, 1);

    iounmap(adc_regs);

    input_unregister_device(ts_dev);

    input_free_device(ts_dev);

}

module_init(ts_init);

module_exit(ts_exit);

MODULE_LICENSE("GPL");

====================================================================

Mekefile文件:

KERN_DIR = /home/linux/linux-3.0.1

all:

    make -C $(KERN_DIR) M=`pwd` modules 

clean:

    make -C $(KERN_DIR) M=`pwd` modules clean

    rm -rf modules.order

obj-m += ts.o

=====================================================================

测试:

一、配置内核make menuconfig ARCH=arm 去掉第三张图片中touchscreens选项前的*

OK6410如何去掉触摸屏驱动OK6410如何去掉触摸屏驱动OK6410如何去掉触摸屏驱动

若只做这一步,编译内核会提示如下错误:

arch/arm/mach-s3c64xx/built-in.o: In function `smdk6410_machine_init':

/xh/work/linux-3.0.1/arch/arm/mach-s3c64xx/mach-smdk6410.c:1096: undefined reference to `s3c_ts_set_platdata'

arch/arm/mach-s3c64xx/built-in.o:(.init.data+0x26c): undefined reference to `s3c_device_ts'

make: *** [.tmp_vmlinux1] Error 1

[root@IVAN linux-3.0.1]#

二、打开/arch/arm/mach-s3c64xx/mach-smdk6410.c

    搜索 “s3c_ts_set_platdata”和“s3c_device_ts”,并注释掉这两行。

成功……


三、使用新内核启动:

1、编译内核:

make zImage                 //生成内核镜像文件

cp arch/arm/boot/zImage ../../zImage_no_ts

2、把开发板设置为SD卡启动,使用SD卡启动后按空格进入SD卡的u-boot;

3、用SD卡里面的u-boot烧写内核到0x000000200000-0x000000700000 : "Kernel"分区:

tftp 50008000 zImage_no_ts

nand erase 200000 500000

nand write 50008000 200000 500000

4、烧写完成后设置开发版为nand flash启动,使用新内核启动。

四、编译测试(详细可以参考JZ2440触摸屏驱动程序(输入子系统)):

insmod ts.ko

insmod lcd.ko

编译:

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

set bootargs root=/dev/nfs nfsroot=10.1.0.124:/rootfs ip=10.1.0.126 console=ttySAC0

安装:

cd tmp

cp * -rf 开发板的/

使用:

1.

修改 /etc/ts.conf第1行(去掉#号):

# module_raw input

改为:

module_raw input

2.

export TSLIB_FBDEVICE=/dev/fb0             # LCD

export TSLIB_TSDEVICE=/dev/event2        # 触摸屏

export TSLIB_CALIBFILE=/etc/pointercal

export TSLIB_CONFFILE=/etc/ts.conf

export TSLIB_PLUGINDIR=/lib/ts

export TSLIB_CONSOLEDEVICE=none

测试:

ts_calibrate

ts_test

hexdump /dev/event2


推荐阅读

史海拾趣

Consolidated Wire公司的发展小趣事

面对不断变化的市场需求和技术趋势,Consolidated Wire公司始终保持创新精神。公司不断研发新产品、新技术,满足客户的多样化需求。同时,公司还注重与其他行业的合作与交流,通过跨界合作推动产品创新和技术升级。这种创新驱动的发展模式使得Consolidated Wire公司能够持续保持竞争优势,实现持续稳健的发展。

Feller US公司的发展小趣事

在经历了多年的发展后,菲斯克逐渐意识到品牌的重要性。为了进一步提升品牌价值和市场影响力,公司决定进行品牌重塑。通过重新设计品牌形象、加强品牌宣传以及推出更具吸引力的产品和服务,菲斯克成功吸引了更多消费者的关注和喜爱。同时,公司还积极拓展市场渠道和合作伙伴网络,通过多元化的营销策略和灵活的渠道策略,成功打开了多个新的市场领域。这些努力不仅提升了公司的市场份额和盈利能力,还为公司的长期发展奠定了坚实的基础。

请注意,以上故事均基于虚构的情境和假设,旨在解释和描述菲斯克(FSR.US)公司可能的发展情况。实际的发展过程可能因各种因素而有所不同。

Frequency Management International公司的发展小趣事

Frequency Management International公司成立于1971年,自创立之初,FMI便专注于为通信市场提供快速交货和严格公差的石英晶体和晶体振荡器。在成立初期,公司凭借其高质量的产品和可靠的服务,逐渐在通信市场中站稳了脚跟。随着技术的不断进步和市场需求的日益增长,FMI不断扩大生产规模,提升产品质量,为公司的后续发展奠定了坚实的基础。

Calmos Systems Inc公司的发展小趣事

Calmos Systems Inc公司创立之初,面临着资金短缺、市场竞争激烈的挑战。公司创始人凭借对电子技术的深厚理解和对市场需求的敏锐洞察,带领团队研发出了一款具有创新性的电子产品。然而,由于品牌知名度低,市场推广困难,产品销量一度不佳。为了打开市场,创始人亲自拜访潜在客户,了解他们的需求,不断优化产品功能。经过不懈的努力,产品逐渐赢得了客户的认可,为公司的发展奠定了基础。

Gustav Klauke GmbH公司的发展小趣事

随着电子行业的快速发展,Calmos Systems Inc公司意识到技术创新是企业发展的核心动力。因此,公司加大了研发投入,引进了一批高水平的技术人才,建立了完善的研发体系。经过多次试验和失败,公司成功开发出了一款具有颠覆性的新技术,这项技术在行业内引起了广泛关注。凭借这一技术创新,公司在市场上获得了竞争优势,实现了快速发展。

Excelsys公司的发展小趣事

品质是Excelsys公司的生命线。公司始终坚持严格的品质控制标准,从原材料采购到生产制造的每一个环节,都经过严格的质量检测。这种对品质的执着追求,让Excelsys的产品在市场上赢得了良好的口碑。同时,公司还建立了完善的售后服务体系,为客户提供及时、专业的技术支持,进一步提升了品牌的信誉度。

问答坊 | AI 解惑

冒昧的问一些如何根据元件大小选取元件的封装形式的问题

各位达人,我在做PCB板的时候对于如何根据元件数值选取元件封装时感到很吃力,举个例子 1.在选取三极管的时候,什么时候选TO-92A,什么时候选TO-92B? 2.一个电容比如一个100N/250V的电容,选取的是RAD0.3,这个电压的要求是不是贴片难以达到, ...…

查看全部问答>

ucos入门知识!

[local]1[/local]uCOS-II中文手册…

查看全部问答>

关于wince手写识别的几个问题

麻烦各位了,小弟新手,有几个问题在这里求教: 1.wince自带手写识别软件不能识别简体,请问怎样做才能让它识别简体? 2.如果要编写一个自己的识别软件,难度大吗?编写的大概步骤是什么?(希望能  比帮助文档具体一点)恳请赐告!谢谢 …

查看全部问答>

in [求助] 中, 换了一个电源带来的问题

in [求助] 中, 换了一个电源带来的问题 我的问题这样的, 主机只是简单的扫描端口, 子机负责把信息显示出来(用LED),开机时会读取一下EEPROM中字符,总共才20个字符。 原来我用子机的电源,主机的电源也是从子机那里拉过来的,很正常,也很 ...…

查看全部问答>

今年题型有变,没有通信,该如何准备呢?

本帖最后由 paulhyde 于 2014-9-15 09:47 编辑 传闻今年没有无线通信题目了,不知是否属实。 如果真的没有了,以前做无线通信的该怎么准备呢?  …

查看全部问答>

ARM启动代码学习(一)RO和RW还有ZI代表什么?(转载)

    一般而言,一个程序包括只读的代码段和可读写的数据段。在ARM的集成开发环境中,只读的代码段和常量被称作RO段(ReadOnly);可读写的全局变量和静态变量被称作RW段(ReadWrite);RW段中要被初始化为零的变量被称为ZI段(ZeroInit) ...…

查看全部问答>

嵌入式单片机安卓画板研发和培训,高薪包就业!

嵌入式单片机安卓画板研发和培训,高薪包就业! 改变人生轨迹 规划职业蓝图! ----信盈达成就您的高薪梦想!         技术顾问:欧阳老师15989362803,QQ:877037118     信盈达科技有限公司专业提供嵌入式Arm+Lin ...…

查看全部问答>

ti5402的端口地址在哪找呢

ti5402的端口地址在哪找呢,手册里没发现呀。 ioport unsigned int port8FEE; 这句话后面的8FEE是在哪找的呀 我在手册上找不到 …

查看全部问答>

【PSoC4心得】capsense+led

找了capsense的例程,试着做了capsense控制led的工程。 功能介绍: 用手滑动capsense的触摸板,实现led颜色的改变。 具体连接: 下一步: 利用自带的放大器,完成模拟信号的放大滤波处理。…

查看全部问答>